@astralyn/pi 0.99.0 → 1.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (569) hide show
  1. package/CHANGELOG.md +58 -3
  2. package/dist/bundle/chunks/anthropic-messages-YET4T7BO.js +6 -0
  3. package/dist/bundle/chunks/anthropic.js +2 -2
  4. package/dist/bundle/chunks/azure-openai-responses-SBLL5YN3.js +2 -0
  5. package/dist/bundle/chunks/bedrock-converse-stream.js +3 -3
  6. package/dist/bundle/chunks/chunk-4TT2QGFL.js +2 -0
  7. package/dist/bundle/chunks/chunk-GIG5IHES.js +2 -0
  8. package/dist/bundle/chunks/{chunk-VW2P3X6P.js → chunk-H2N2THAO.js} +436 -668
  9. package/dist/bundle/chunks/{chunk-A576H74Y.js → chunk-IZ3S3GDX.js} +1 -1
  10. package/dist/bundle/chunks/{chunk-ABVRAYXT.js → chunk-NY3CWK44.js} +2 -2
  11. package/dist/bundle/chunks/chunk-SVJ7OGEB.js +2 -0
  12. package/dist/bundle/chunks/chunk-TRHTWM3C.js +2 -0
  13. package/dist/bundle/chunks/{chunk-DEWXBB6W.js → chunk-V66VGGOM.js} +1 -1
  14. package/dist/bundle/chunks/chunk-XDYM2567.js +20 -0
  15. package/dist/bundle/chunks/{cloudflare-workers-ai-system-one-ZYSAFXXL.js → cloudflare-workers-ai-system-one-QI46LUZ6.js} +1 -1
  16. package/dist/bundle/chunks/codemode-worker.js +90 -10
  17. package/dist/bundle/chunks/github-copilot.js +1 -1
  18. package/dist/bundle/chunks/{google-generative-ai-SDNQVVXA.js → google-generative-ai-YTZCSHQN.js} +1 -1
  19. package/dist/bundle/chunks/{google-vertex-LZXOLBIO.js → google-vertex-OTFZJJXQ.js} +1 -1
  20. package/dist/bundle/chunks/{llama-cpp-classify-7IYGGPND.js → llama-cpp-classify-R7DQLTQN.js} +1 -1
  21. package/dist/bundle/chunks/{mistral-conversations-VYKPSSAM.js → mistral-conversations-ELH4V4TY.js} +1 -1
  22. package/dist/bundle/chunks/node-USQQ7C6M.js +16 -0
  23. package/dist/bundle/chunks/openai-chatgpt.js +2 -2
  24. package/dist/bundle/chunks/{openai-codex-responses-HZ4VUDXD.js → openai-codex-responses-OLVTU4UA.js} +1 -1
  25. package/dist/bundle/chunks/openai-codex.js +1 -1
  26. package/dist/bundle/chunks/openai-completions-53M2KJ67.js +7 -0
  27. package/dist/bundle/chunks/openai-responses-4ABDEL4Z.js +3 -0
  28. package/dist/bundle/chunks/{openrouter-images-5524IQHX.js → openrouter-images-YP3YVB54.js} +1 -1
  29. package/dist/bundle/chunks/openrouter.js +1 -1
  30. package/dist/bundle/chunks/radius.js +1 -1
  31. package/dist/bundle/chunks/{typesafe-system-one-Z2CDLKEY.js → typesafe-system-one-RREJAKWB.js} +1 -1
  32. package/dist/bundle/chunks/virtual-modules-YFKU7JZF.js +2 -0
  33. package/dist/bundle/cli.js +1 -1
  34. package/dist/bundle/index.js +1 -1
  35. package/dist/bundle/rpc-entry.js +1 -1
  36. package/dist/cli/args.d.ts.map +1 -1
  37. package/dist/cli/args.js +5 -2
  38. package/dist/cli/args.js.map +1 -1
  39. package/dist/config.d.ts +5 -8
  40. package/dist/config.d.ts.map +1 -1
  41. package/dist/config.js +19 -13
  42. package/dist/config.js.map +1 -1
  43. package/dist/core/agent-session.d.ts +21 -1
  44. package/dist/core/agent-session.d.ts.map +1 -1
  45. package/dist/core/agent-session.js +65 -12
  46. package/dist/core/agent-session.js.map +1 -1
  47. package/dist/core/export-html/tool-renderer.d.ts +3 -3
  48. package/dist/core/export-html/tool-renderer.d.ts.map +1 -1
  49. package/dist/core/export-html/tool-renderer.js +3 -3
  50. package/dist/core/export-html/tool-renderer.js.map +1 -1
  51. package/dist/core/extensions/index.d.ts +2 -2
  52. package/dist/core/extensions/index.d.ts.map +1 -1
  53. package/dist/core/extensions/index.js.map +1 -1
  54. package/dist/core/extensions/loader.d.ts.map +1 -1
  55. package/dist/core/extensions/loader.js +18 -1
  56. package/dist/core/extensions/loader.js.map +1 -1
  57. package/dist/core/extensions/runner.d.ts +3 -1
  58. package/dist/core/extensions/runner.d.ts.map +1 -1
  59. package/dist/core/extensions/runner.js +6 -0
  60. package/dist/core/extensions/runner.js.map +1 -1
  61. package/dist/core/extensions/types.d.ts +15 -1
  62. package/dist/core/extensions/types.d.ts.map +1 -1
  63. package/dist/core/extensions/types.js.map +1 -1
  64. package/dist/core/keybindings.d.ts +51 -11
  65. package/dist/core/keybindings.d.ts.map +1 -1
  66. package/dist/core/keybindings.js +11 -3
  67. package/dist/core/keybindings.js.map +1 -1
  68. package/dist/core/mcp-servers.d.ts +40 -7
  69. package/dist/core/mcp-servers.d.ts.map +1 -1
  70. package/dist/core/mcp-servers.js +63 -11
  71. package/dist/core/mcp-servers.js.map +1 -1
  72. package/dist/core/model-config.d.ts +36 -0
  73. package/dist/core/model-config.d.ts.map +1 -1
  74. package/dist/core/model-config.js +14 -2
  75. package/dist/core/model-config.js.map +1 -1
  76. package/dist/core/model-registry.d.ts +3 -1
  77. package/dist/core/model-registry.d.ts.map +1 -1
  78. package/dist/core/model-registry.js +4 -0
  79. package/dist/core/model-registry.js.map +1 -1
  80. package/dist/core/model-resolver.js +1 -1
  81. package/dist/core/model-resolver.js.map +1 -1
  82. package/dist/core/model-runtime.d.ts +6 -0
  83. package/dist/core/model-runtime.d.ts.map +1 -1
  84. package/dist/core/model-runtime.js +22 -18
  85. package/dist/core/model-runtime.js.map +1 -1
  86. package/dist/core/provider-composer.d.ts +2 -1
  87. package/dist/core/provider-composer.d.ts.map +1 -1
  88. package/dist/core/provider-composer.js +13 -0
  89. package/dist/core/provider-composer.js.map +1 -1
  90. package/dist/core/radius.d.ts +2 -0
  91. package/dist/core/radius.d.ts.map +1 -1
  92. package/dist/core/radius.js +2 -0
  93. package/dist/core/radius.js.map +1 -1
  94. package/dist/core/remote-catalog-provider.d.ts.map +1 -1
  95. package/dist/core/remote-catalog-provider.js +4 -9
  96. package/dist/core/remote-catalog-provider.js.map +1 -1
  97. package/dist/core/sdk.d.ts.map +1 -1
  98. package/dist/core/sdk.js +1 -0
  99. package/dist/core/sdk.js.map +1 -1
  100. package/dist/core/settings-manager.d.ts +7 -5
  101. package/dist/core/settings-manager.d.ts.map +1 -1
  102. package/dist/core/settings-manager.js +2 -1
  103. package/dist/core/settings-manager.js.map +1 -1
  104. package/dist/core/system-prompt.js +1 -1
  105. package/dist/core/system-prompt.js.map +1 -1
  106. package/dist/core/tasks/format.d.ts +7 -0
  107. package/dist/core/tasks/format.d.ts.map +1 -0
  108. package/dist/core/tasks/format.js +14 -0
  109. package/dist/core/tasks/format.js.map +1 -0
  110. package/dist/core/tasks/history.d.ts.map +1 -1
  111. package/dist/core/tasks/history.js +0 -19
  112. package/dist/core/tasks/history.js.map +1 -1
  113. package/dist/core/tasks/output.d.ts +8 -0
  114. package/dist/core/tasks/output.d.ts.map +1 -1
  115. package/dist/core/tasks/output.js +19 -0
  116. package/dist/core/tasks/output.js.map +1 -1
  117. package/dist/core/tasks/presentation.d.ts +1 -3
  118. package/dist/core/tasks/presentation.d.ts.map +1 -1
  119. package/dist/core/tasks/presentation.js +79 -166
  120. package/dist/core/tasks/presentation.js.map +1 -1
  121. package/dist/core/tasks/runtime.d.ts +16 -9
  122. package/dist/core/tasks/runtime.d.ts.map +1 -1
  123. package/dist/core/tasks/runtime.js +89 -106
  124. package/dist/core/tasks/runtime.js.map +1 -1
  125. package/dist/core/tasks/session.d.ts.map +1 -1
  126. package/dist/core/tasks/session.js +13 -4
  127. package/dist/core/tasks/session.js.map +1 -1
  128. package/dist/core/tasks/store.d.ts +20 -6
  129. package/dist/core/tasks/store.d.ts.map +1 -1
  130. package/dist/core/tasks/store.js +45 -18
  131. package/dist/core/tasks/store.js.map +1 -1
  132. package/dist/core/tasks/types.d.ts +14 -54
  133. package/dist/core/tasks/types.d.ts.map +1 -1
  134. package/dist/core/tasks/types.js +1 -5
  135. package/dist/core/tasks/types.js.map +1 -1
  136. package/dist/core/tools/renderers/bash.d.ts.map +1 -1
  137. package/dist/core/tools/renderers/bash.js +11 -34
  138. package/dist/core/tools/renderers/bash.js.map +1 -1
  139. package/dist/core/tools/renderers/index.d.ts +2 -2
  140. package/dist/core/tools/renderers/index.d.ts.map +1 -1
  141. package/dist/core/tools/renderers/index.js.map +1 -1
  142. package/dist/core/tools/shell-execution.d.ts +0 -1
  143. package/dist/core/tools/shell-execution.d.ts.map +1 -1
  144. package/dist/core/tools/shell-execution.js +3 -10
  145. package/dist/core/tools/shell-execution.js.map +1 -1
  146. package/dist/core/tools/shell-tool.d.ts.map +1 -1
  147. package/dist/core/tools/shell-tool.js +2 -4
  148. package/dist/core/tools/shell-tool.js.map +1 -1
  149. package/dist/core/tools/tasks/actions.d.ts +1 -1
  150. package/dist/core/tools/tasks/actions.d.ts.map +1 -1
  151. package/dist/core/tools/tasks/actions.js +26 -12
  152. package/dist/core/tools/tasks/actions.js.map +1 -1
  153. package/dist/core/tools/tasks/constants.d.ts +2 -6
  154. package/dist/core/tools/tasks/constants.d.ts.map +1 -1
  155. package/dist/core/tools/tasks/constants.js +2 -6
  156. package/dist/core/tools/tasks/constants.js.map +1 -1
  157. package/dist/core/tools/tasks/schema.d.ts +1 -1
  158. package/dist/core/tools/tasks/schema.d.ts.map +1 -1
  159. package/dist/core/tools/tasks/schema.js +8 -7
  160. package/dist/core/tools/tasks/schema.js.map +1 -1
  161. package/dist/core/tools/tasks/types.d.ts +8 -38
  162. package/dist/core/tools/tasks/types.d.ts.map +1 -1
  163. package/dist/core/tools/tasks/types.js +6 -11
  164. package/dist/core/tools/tasks/types.js.map +1 -1
  165. package/dist/core/virtual-models.d.ts +2 -0
  166. package/dist/core/virtual-models.d.ts.map +1 -1
  167. package/dist/core/virtual-models.js +19 -12
  168. package/dist/core/virtual-models.js.map +1 -1
  169. package/dist/extensions/btw/agent.d.ts +17 -8
  170. package/dist/extensions/btw/agent.d.ts.map +1 -1
  171. package/dist/extensions/btw/agent.js +74 -76
  172. package/dist/extensions/btw/agent.js.map +1 -1
  173. package/dist/extensions/btw/controller.d.ts +0 -1
  174. package/dist/extensions/btw/controller.d.ts.map +1 -1
  175. package/dist/extensions/btw/controller.js +26 -33
  176. package/dist/extensions/btw/controller.js.map +1 -1
  177. package/dist/extensions/btw/panel.d.ts +13 -14
  178. package/dist/extensions/btw/panel.d.ts.map +1 -1
  179. package/dist/extensions/btw/panel.js +38 -29
  180. package/dist/extensions/btw/panel.js.map +1 -1
  181. package/dist/extensions/codemode/execute.d.ts.map +1 -1
  182. package/dist/extensions/codemode/execute.js +197 -51
  183. package/dist/extensions/codemode/execute.js.map +1 -1
  184. package/dist/extensions/codemode/renderer.d.ts.map +1 -1
  185. package/dist/extensions/codemode/renderer.js +43 -25
  186. package/dist/extensions/codemode/renderer.js.map +1 -1
  187. package/dist/extensions/codemode/tool.d.ts +12 -11
  188. package/dist/extensions/codemode/tool.d.ts.map +1 -1
  189. package/dist/extensions/codemode/tool.js +73 -129
  190. package/dist/extensions/codemode/tool.js.map +1 -1
  191. package/dist/extensions/codemode/worker.d.ts +1 -1
  192. package/dist/extensions/codemode/worker.js +1 -1
  193. package/dist/extensions/codemode/worker.js.map +1 -1
  194. package/dist/extensions/deepwiki/schema.d.ts +1 -1
  195. package/dist/extensions/index.d.ts.map +1 -1
  196. package/dist/extensions/index.js +0 -2
  197. package/dist/extensions/index.js.map +1 -1
  198. package/dist/extensions/mcp/cli.d.ts.map +1 -1
  199. package/dist/extensions/mcp/cli.js +23 -5
  200. package/dist/extensions/mcp/cli.js.map +1 -1
  201. package/dist/extensions/mcp/config.d.ts +19 -5
  202. package/dist/extensions/mcp/config.d.ts.map +1 -1
  203. package/dist/extensions/mcp/config.js +60 -12
  204. package/dist/extensions/mcp/config.js.map +1 -1
  205. package/dist/extensions/mcp/index.d.ts +36 -9
  206. package/dist/extensions/mcp/index.d.ts.map +1 -1
  207. package/dist/extensions/mcp/index.js +309 -100
  208. package/dist/extensions/mcp/index.js.map +1 -1
  209. package/dist/extensions/mcp/oauth.d.ts +14 -8
  210. package/dist/extensions/mcp/oauth.d.ts.map +1 -1
  211. package/dist/extensions/mcp/oauth.js +105 -36
  212. package/dist/extensions/mcp/oauth.js.map +1 -1
  213. package/dist/extensions/mcp/runtime.d.ts +2 -0
  214. package/dist/extensions/mcp/runtime.d.ts.map +1 -1
  215. package/dist/extensions/mcp/runtime.js +17 -9
  216. package/dist/extensions/mcp/runtime.js.map +1 -1
  217. package/dist/extensions/mcp/tools.d.ts +8 -5
  218. package/dist/extensions/mcp/tools.d.ts.map +1 -1
  219. package/dist/extensions/mcp/tools.js +50 -26
  220. package/dist/extensions/mcp/tools.js.map +1 -1
  221. package/dist/extensions/mcp/ui.d.ts.map +1 -1
  222. package/dist/extensions/mcp/ui.js +7 -1
  223. package/dist/extensions/mcp/ui.js.map +1 -1
  224. package/dist/extensions/provider/catalog.d.ts +8 -1
  225. package/dist/extensions/provider/catalog.d.ts.map +1 -1
  226. package/dist/extensions/provider/catalog.js +31 -0
  227. package/dist/extensions/provider/catalog.js.map +1 -1
  228. package/dist/extensions/provider/connection.d.ts +4 -1
  229. package/dist/extensions/provider/connection.d.ts.map +1 -1
  230. package/dist/extensions/provider/connection.js +1 -5
  231. package/dist/extensions/provider/connection.js.map +1 -1
  232. package/dist/extensions/provider/editing.d.ts +36 -0
  233. package/dist/extensions/provider/editing.d.ts.map +1 -0
  234. package/dist/extensions/provider/editing.js +99 -0
  235. package/dist/extensions/provider/editing.js.map +1 -0
  236. package/dist/extensions/provider/json-fields.d.ts +5 -0
  237. package/dist/extensions/provider/json-fields.d.ts.map +1 -0
  238. package/dist/extensions/provider/json-fields.js +31 -0
  239. package/dist/extensions/provider/json-fields.js.map +1 -0
  240. package/dist/extensions/provider/store.d.ts +1 -4
  241. package/dist/extensions/provider/store.d.ts.map +1 -1
  242. package/dist/extensions/provider/store.js +2 -30
  243. package/dist/extensions/provider/store.js.map +1 -1
  244. package/dist/extensions/provider/ui/builtin-data.d.ts +0 -2
  245. package/dist/extensions/provider/ui/builtin-data.d.ts.map +1 -1
  246. package/dist/extensions/provider/ui/builtin-data.js +14 -79
  247. package/dist/extensions/provider/ui/builtin-data.js.map +1 -1
  248. package/dist/extensions/provider/ui/compat.d.ts.map +1 -1
  249. package/dist/extensions/provider/ui/compat.js +6 -9
  250. package/dist/extensions/provider/ui/compat.js.map +1 -1
  251. package/dist/extensions/provider/ui/controls.d.ts +48 -0
  252. package/dist/extensions/provider/ui/controls.d.ts.map +1 -0
  253. package/dist/extensions/provider/ui/controls.js +108 -0
  254. package/dist/extensions/provider/ui/controls.js.map +1 -0
  255. package/dist/extensions/provider/ui/dictionary.d.ts.map +1 -1
  256. package/dist/extensions/provider/ui/dictionary.js +6 -9
  257. package/dist/extensions/provider/ui/dictionary.js.map +1 -1
  258. package/dist/extensions/provider/ui/editor.d.ts +3 -3
  259. package/dist/extensions/provider/ui/editor.d.ts.map +1 -1
  260. package/dist/extensions/provider/ui/editor.js +35 -140
  261. package/dist/extensions/provider/ui/editor.js.map +1 -1
  262. package/dist/extensions/provider/ui/fetch-models.d.ts +0 -3
  263. package/dist/extensions/provider/ui/fetch-models.d.ts.map +1 -1
  264. package/dist/extensions/provider/ui/fetch-models.js +49 -44
  265. package/dist/extensions/provider/ui/fetch-models.js.map +1 -1
  266. package/dist/extensions/provider/ui/model-fields.d.ts.map +1 -1
  267. package/dist/extensions/provider/ui/model-fields.js +11 -14
  268. package/dist/extensions/provider/ui/model-fields.js.map +1 -1
  269. package/dist/extensions/provider/ui/model-options.d.ts +4 -34
  270. package/dist/extensions/provider/ui/model-options.d.ts.map +1 -1
  271. package/dist/extensions/provider/ui/model-options.js +90 -271
  272. package/dist/extensions/provider/ui/model-options.js.map +1 -1
  273. package/dist/extensions/provider/ui/pane.d.ts +4 -18
  274. package/dist/extensions/provider/ui/pane.d.ts.map +1 -1
  275. package/dist/extensions/provider/ui/pane.js.map +1 -1
  276. package/dist/extensions/provider/ui/provider-fields.d.ts +2 -19
  277. package/dist/extensions/provider/ui/provider-fields.d.ts.map +1 -1
  278. package/dist/extensions/provider/ui/provider-fields.js +58 -171
  279. package/dist/extensions/provider/ui/provider-fields.js.map +1 -1
  280. package/dist/extensions/provider/ui/thinking-map.d.ts.map +1 -1
  281. package/dist/extensions/provider/ui/thinking-map.js +6 -9
  282. package/dist/extensions/provider/ui/thinking-map.js.map +1 -1
  283. package/dist/extensions/question/detail-pane.d.ts +7 -2
  284. package/dist/extensions/question/detail-pane.d.ts.map +1 -1
  285. package/dist/extensions/question/detail-pane.js +16 -5
  286. package/dist/extensions/question/detail-pane.js.map +1 -1
  287. package/dist/extensions/question/dialog-view.d.ts +41 -0
  288. package/dist/extensions/question/dialog-view.d.ts.map +1 -0
  289. package/dist/extensions/question/dialog-view.js +329 -0
  290. package/dist/extensions/question/dialog-view.js.map +1 -0
  291. package/dist/extensions/question/dialog.d.ts +3 -3
  292. package/dist/extensions/question/dialog.d.ts.map +1 -1
  293. package/dist/extensions/question/dialog.js +220 -634
  294. package/dist/extensions/question/dialog.js.map +1 -1
  295. package/dist/extensions/question/index.d.ts.map +1 -1
  296. package/dist/extensions/question/index.js +2 -3
  297. package/dist/extensions/question/index.js.map +1 -1
  298. package/dist/extensions/question/render.d.ts.map +1 -1
  299. package/dist/extensions/question/render.js +22 -32
  300. package/dist/extensions/question/render.js.map +1 -1
  301. package/dist/extensions/question/results.d.ts.map +1 -1
  302. package/dist/extensions/question/results.js +56 -12
  303. package/dist/extensions/question/results.js.map +1 -1
  304. package/dist/extensions/question/schema.d.ts +21 -6
  305. package/dist/extensions/question/schema.d.ts.map +1 -1
  306. package/dist/extensions/question/schema.js.map +1 -1
  307. package/dist/extensions/question/state.d.ts +9 -7
  308. package/dist/extensions/question/state.d.ts.map +1 -1
  309. package/dist/extensions/question/state.js +63 -54
  310. package/dist/extensions/question/state.js.map +1 -1
  311. package/dist/extensions/question/types.d.ts +41 -18
  312. package/dist/extensions/question/types.d.ts.map +1 -1
  313. package/dist/extensions/question/types.js.map +1 -1
  314. package/dist/extensions/statusline/index.d.ts +4 -0
  315. package/dist/extensions/statusline/index.d.ts.map +1 -1
  316. package/dist/extensions/statusline/index.js +18 -355
  317. package/dist/extensions/statusline/index.js.map +1 -1
  318. package/dist/extensions/statusline/render.d.ts +19 -0
  319. package/dist/extensions/statusline/render.d.ts.map +1 -0
  320. package/dist/extensions/statusline/render.js +163 -0
  321. package/dist/extensions/statusline/render.js.map +1 -0
  322. package/dist/extensions/statusline/usage.d.ts +12 -0
  323. package/dist/extensions/statusline/usage.d.ts.map +1 -0
  324. package/dist/extensions/statusline/usage.js +36 -0
  325. package/dist/extensions/statusline/usage.js.map +1 -0
  326. package/dist/extensions/tool-search/tool.d.ts +5 -4
  327. package/dist/extensions/tool-search/tool.d.ts.map +1 -1
  328. package/dist/extensions/tool-search/tool.js +7 -28
  329. package/dist/extensions/tool-search/tool.js.map +1 -1
  330. package/dist/extensions/web-search/execute.d.ts +1 -5
  331. package/dist/extensions/web-search/execute.d.ts.map +1 -1
  332. package/dist/extensions/web-search/execute.js +4 -9
  333. package/dist/extensions/web-search/execute.js.map +1 -1
  334. package/dist/extensions/web-search/format.d.ts +12 -3
  335. package/dist/extensions/web-search/format.d.ts.map +1 -1
  336. package/dist/extensions/web-search/format.js +33 -25
  337. package/dist/extensions/web-search/format.js.map +1 -1
  338. package/dist/extensions/web-search/index.d.ts.map +1 -1
  339. package/dist/extensions/web-search/index.js +6 -29
  340. package/dist/extensions/web-search/index.js.map +1 -1
  341. package/dist/extensions/web-search/providers/deepseek.d.ts.map +1 -1
  342. package/dist/extensions/web-search/providers/deepseek.js +0 -1
  343. package/dist/extensions/web-search/providers/deepseek.js.map +1 -1
  344. package/dist/extensions/web-search/providers/http.d.ts +1 -1
  345. package/dist/extensions/web-search/providers/http.d.ts.map +1 -1
  346. package/dist/extensions/web-search/providers/http.js.map +1 -1
  347. package/dist/extensions/web-search/providers/minimax.d.ts.map +1 -1
  348. package/dist/extensions/web-search/providers/minimax.js +0 -1
  349. package/dist/extensions/web-search/providers/minimax.js.map +1 -1
  350. package/dist/extensions/web-search/render.d.ts +7 -2
  351. package/dist/extensions/web-search/render.d.ts.map +1 -1
  352. package/dist/extensions/web-search/render.js +32 -4
  353. package/dist/extensions/web-search/render.js.map +1 -1
  354. package/dist/extensions/web-search/results.d.ts.map +1 -1
  355. package/dist/extensions/web-search/results.js +3 -8
  356. package/dist/extensions/web-search/results.js.map +1 -1
  357. package/dist/extensions/web-search/types.d.ts +4 -2
  358. package/dist/extensions/web-search/types.d.ts.map +1 -1
  359. package/dist/extensions/web-search/types.js.map +1 -1
  360. package/dist/index.d.ts +3 -5
  361. package/dist/index.d.ts.map +1 -1
  362. package/dist/index.js +0 -1
  363. package/dist/index.js.map +1 -1
  364. package/dist/main.d.ts.map +1 -1
  365. package/dist/main.js +6 -0
  366. package/dist/main.js.map +1 -1
  367. package/dist/modes/interactive/components/armin.d.ts +3 -0
  368. package/dist/modes/interactive/components/armin.d.ts.map +1 -1
  369. package/dist/modes/interactive/components/armin.js +7 -5
  370. package/dist/modes/interactive/components/armin.js.map +1 -1
  371. package/dist/modes/interactive/components/auth-url.d.ts +14 -0
  372. package/dist/modes/interactive/components/auth-url.d.ts.map +1 -0
  373. package/dist/modes/interactive/components/auth-url.js +34 -0
  374. package/dist/modes/interactive/components/auth-url.js.map +1 -0
  375. package/dist/modes/interactive/components/easter-egg-3d.d.ts +104 -0
  376. package/dist/modes/interactive/components/easter-egg-3d.d.ts.map +1 -0
  377. package/dist/modes/interactive/components/easter-egg-3d.js +1123 -0
  378. package/dist/modes/interactive/components/easter-egg-3d.js.map +1 -0
  379. package/dist/modes/interactive/components/easter-egg-3d.lazy.d.ts +6 -0
  380. package/dist/modes/interactive/components/easter-egg-3d.lazy.d.ts.map +1 -0
  381. package/dist/modes/interactive/components/easter-egg-3d.lazy.js +24 -0
  382. package/dist/modes/interactive/components/easter-egg-3d.lazy.js.map +1 -0
  383. package/dist/modes/interactive/components/index.d.ts +0 -1
  384. package/dist/modes/interactive/components/index.d.ts.map +1 -1
  385. package/dist/modes/interactive/components/index.js +0 -1
  386. package/dist/modes/interactive/components/index.js.map +1 -1
  387. package/dist/modes/interactive/components/login-dialog.d.ts +2 -0
  388. package/dist/modes/interactive/components/login-dialog.d.ts.map +1 -1
  389. package/dist/modes/interactive/components/login-dialog.js +9 -5
  390. package/dist/modes/interactive/components/login-dialog.js.map +1 -1
  391. package/dist/modes/interactive/components/oauth-selector.d.ts +8 -2
  392. package/dist/modes/interactive/components/oauth-selector.d.ts.map +1 -1
  393. package/dist/modes/interactive/components/oauth-selector.js +24 -21
  394. package/dist/modes/interactive/components/oauth-selector.js.map +1 -1
  395. package/dist/modes/interactive/components/pi-logo.d.ts +7 -0
  396. package/dist/modes/interactive/components/pi-logo.d.ts.map +1 -1
  397. package/dist/modes/interactive/components/pi-logo.js +13 -1
  398. package/dist/modes/interactive/components/pi-logo.js.map +1 -1
  399. package/dist/modes/interactive/components/radius-login-selector.d.ts +15 -0
  400. package/dist/modes/interactive/components/radius-login-selector.d.ts.map +1 -0
  401. package/dist/modes/interactive/components/radius-login-selector.js +83 -0
  402. package/dist/modes/interactive/components/radius-login-selector.js.map +1 -0
  403. package/dist/modes/interactive/components/settings-selector.d.ts +3 -3
  404. package/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
  405. package/dist/modes/interactive/components/settings-selector.js +5 -5
  406. package/dist/modes/interactive/components/settings-selector.js.map +1 -1
  407. package/dist/modes/interactive/components/status-marker.d.ts +0 -2
  408. package/dist/modes/interactive/components/status-marker.d.ts.map +1 -1
  409. package/dist/modes/interactive/components/status-marker.js +0 -4
  410. package/dist/modes/interactive/components/status-marker.js.map +1 -1
  411. package/dist/modes/interactive/components/user-message.d.ts.map +1 -1
  412. package/dist/modes/interactive/components/user-message.js +5 -4
  413. package/dist/modes/interactive/components/user-message.js.map +1 -1
  414. package/dist/modes/interactive/components/visual-truncate.d.ts +27 -3
  415. package/dist/modes/interactive/components/visual-truncate.d.ts.map +1 -1
  416. package/dist/modes/interactive/components/visual-truncate.js +36 -6
  417. package/dist/modes/interactive/components/visual-truncate.js.map +1 -1
  418. package/dist/modes/interactive/interactive-mode.d.ts +12 -2
  419. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  420. package/dist/modes/interactive/interactive-mode.js +180 -55
  421. package/dist/modes/interactive/interactive-mode.js.map +1 -1
  422. package/dist/modes/interactive/tasks/completion-render.d.ts +1 -1
  423. package/dist/modes/interactive/tasks/completion-render.d.ts.map +1 -1
  424. package/dist/modes/interactive/tasks/completion-render.js +28 -82
  425. package/dist/modes/interactive/tasks/completion-render.js.map +1 -1
  426. package/dist/modes/interactive/tasks/index.d.ts.map +1 -1
  427. package/dist/modes/interactive/tasks/index.js +18 -13
  428. package/dist/modes/interactive/tasks/index.js.map +1 -1
  429. package/dist/modes/interactive/tasks/inspector.d.ts +35 -0
  430. package/dist/modes/interactive/tasks/inspector.d.ts.map +1 -0
  431. package/dist/modes/interactive/tasks/inspector.js +93 -0
  432. package/dist/modes/interactive/tasks/inspector.js.map +1 -0
  433. package/dist/modes/interactive/tasks/layout.d.ts +40 -0
  434. package/dist/modes/interactive/tasks/layout.d.ts.map +1 -0
  435. package/dist/modes/interactive/tasks/layout.js +212 -0
  436. package/dist/modes/interactive/tasks/layout.js.map +1 -0
  437. package/dist/modes/interactive/tasks/list.d.ts +21 -0
  438. package/dist/modes/interactive/tasks/list.d.ts.map +1 -0
  439. package/dist/modes/interactive/tasks/list.js +96 -0
  440. package/dist/modes/interactive/tasks/list.js.map +1 -0
  441. package/dist/modes/interactive/tasks/manager.d.ts +29 -36
  442. package/dist/modes/interactive/tasks/manager.d.ts.map +1 -1
  443. package/dist/modes/interactive/tasks/manager.js +315 -315
  444. package/dist/modes/interactive/tasks/manager.js.map +1 -1
  445. package/dist/modes/interactive/tasks/model.d.ts +21 -0
  446. package/dist/modes/interactive/tasks/model.d.ts.map +1 -0
  447. package/dist/modes/interactive/tasks/model.js +41 -0
  448. package/dist/modes/interactive/tasks/model.js.map +1 -0
  449. package/dist/modes/interactive/tasks/render.d.ts +5 -19
  450. package/dist/modes/interactive/tasks/render.d.ts.map +1 -1
  451. package/dist/modes/interactive/tasks/render.js +18 -102
  452. package/dist/modes/interactive/tasks/render.js.map +1 -1
  453. package/dist/modes/interactive/tasks/task-view.d.ts +8 -48
  454. package/dist/modes/interactive/tasks/task-view.d.ts.map +1 -1
  455. package/dist/modes/interactive/tasks/task-view.js +11 -51
  456. package/dist/modes/interactive/tasks/task-view.js.map +1 -1
  457. package/dist/modes/interactive/tasks/text.d.ts +1 -7
  458. package/dist/modes/interactive/tasks/text.d.ts.map +1 -1
  459. package/dist/modes/interactive/tasks/text.js +6 -29
  460. package/dist/modes/interactive/tasks/text.js.map +1 -1
  461. package/dist/modes/interactive/tasks/viewport.d.ts +2 -0
  462. package/dist/modes/interactive/tasks/viewport.d.ts.map +1 -1
  463. package/dist/modes/interactive/tasks/viewport.js +17 -7
  464. package/dist/modes/interactive/tasks/viewport.js.map +1 -1
  465. package/dist/modes/interactive/tasks/views.d.ts +9 -0
  466. package/dist/modes/interactive/tasks/views.d.ts.map +1 -0
  467. package/dist/modes/interactive/tasks/views.js +42 -0
  468. package/dist/modes/interactive/tasks/views.js.map +1 -0
  469. package/dist/modes/interactive/theme/system-theme.d.ts +2 -1
  470. package/dist/modes/interactive/theme/system-theme.d.ts.map +1 -1
  471. package/dist/modes/interactive/theme/system-theme.js +16 -5
  472. package/dist/modes/interactive/theme/system-theme.js.map +1 -1
  473. package/dist/modes/interactive/tool-view/tool-execution.d.ts +4 -19
  474. package/dist/modes/interactive/tool-view/tool-execution.d.ts.map +1 -1
  475. package/dist/modes/interactive/tool-view/tool-execution.js +23 -67
  476. package/dist/modes/interactive/tool-view/tool-execution.js.map +1 -1
  477. package/dist/utils/image-convert.d.ts +12 -0
  478. package/dist/utils/image-convert.d.ts.map +1 -1
  479. package/dist/utils/image-convert.js +45 -6
  480. package/dist/utils/image-convert.js.map +1 -1
  481. package/docs/bundled/README.md +0 -1
  482. package/docs/bundled/extensions/question.md +2 -2
  483. package/docs/bundled/extensions/statusline.md +24 -15
  484. package/docs/bundled/tasks.md +34 -48
  485. package/docs/codemode.md +207 -0
  486. package/docs/docs.json +4 -4
  487. package/docs/environment-variables.md +1 -1
  488. package/docs/extensions.md +11 -9
  489. package/docs/keybindings.md +14 -7
  490. package/docs/mcp.md +164 -82
  491. package/docs/models.md +51 -3
  492. package/docs/providers.md +8 -0
  493. package/docs/sdk.md +2 -2
  494. package/docs/session-format.md +12 -22
  495. package/docs/settings.md +4 -2
  496. package/docs/tui.md +1 -1
  497. package/docs/usage.md +6 -16
  498. package/examples/README.md +1 -1
  499. package/examples/extensions/README.md +1 -2
  500. package/examples/extensions/built-in-tool-renderer.ts +16 -40
  501. package/examples/extensions/custom-provider-anthropic/package-lock.json +2 -2
  502. package/examples/extensions/custom-provider-anthropic/package.json +1 -1
  503. package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
  504. package/examples/extensions/gondolin/package-lock.json +2 -2
  505. package/examples/extensions/gondolin/package.json +1 -1
  506. package/examples/extensions/minimal-mode.ts +24 -96
  507. package/examples/extensions/sandbox/package-lock.json +2 -2
  508. package/examples/extensions/sandbox/package.json +1 -1
  509. package/examples/extensions/with-deps/package-lock.json +2 -2
  510. package/examples/extensions/with-deps/package.json +1 -1
  511. package/examples/sdk/14-codemode-mcp.ts +2 -2
  512. package/npm-shrinkwrap.json +73 -62
  513. package/package.json +11 -10
  514. package/dist/bundle/chunks/anthropic-messages-KIXY7EDT.js +0 -6
  515. package/dist/bundle/chunks/azure-openai-responses-RPBERDXD.js +0 -2
  516. package/dist/bundle/chunks/chunk-CLLDCO64.js +0 -2
  517. package/dist/bundle/chunks/chunk-PJVFYVHE.js +0 -42
  518. package/dist/bundle/chunks/chunk-UUSTLCVC.js +0 -2
  519. package/dist/bundle/chunks/chunk-VWCWZD6E.js +0 -2
  520. package/dist/bundle/chunks/node-CXWYTK2I.js +0 -16
  521. package/dist/bundle/chunks/openai-completions-SKDGF6OE.js +0 -7
  522. package/dist/bundle/chunks/openai-responses-FPML4SSG.js +0 -3
  523. package/dist/bundle/chunks/virtual-modules-TQRORWJQ.js +0 -2
  524. package/dist/core/tasks/view-data.d.ts +0 -8
  525. package/dist/core/tasks/view-data.d.ts.map +0 -1
  526. package/dist/core/tasks/view-data.js +0 -61
  527. package/dist/core/tasks/view-data.js.map +0 -1
  528. package/dist/core/tasks/view.d.ts +0 -30
  529. package/dist/core/tasks/view.d.ts.map +0 -1
  530. package/dist/core/tasks/view.js +0 -50
  531. package/dist/core/tasks/view.js.map +0 -1
  532. package/dist/core/tools/renderers/shell-task.d.ts +0 -4
  533. package/dist/core/tools/renderers/shell-task.d.ts.map +0 -1
  534. package/dist/core/tools/renderers/shell-task.js +0 -35
  535. package/dist/core/tools/renderers/shell-task.js.map +0 -1
  536. package/dist/extensions/todo/constants.d.ts +0 -16
  537. package/dist/extensions/todo/constants.d.ts.map +0 -1
  538. package/dist/extensions/todo/constants.js +0 -30
  539. package/dist/extensions/todo/constants.js.map +0 -1
  540. package/dist/extensions/todo/index.d.ts +0 -3
  541. package/dist/extensions/todo/index.d.ts.map +0 -1
  542. package/dist/extensions/todo/index.js +0 -98
  543. package/dist/extensions/todo/index.js.map +0 -1
  544. package/dist/extensions/todo/schema.d.ts +0 -60
  545. package/dist/extensions/todo/schema.d.ts.map +0 -1
  546. package/dist/extensions/todo/schema.js +0 -56
  547. package/dist/extensions/todo/schema.js.map +0 -1
  548. package/dist/extensions/todo/state.d.ts +0 -34
  549. package/dist/extensions/todo/state.d.ts.map +0 -1
  550. package/dist/extensions/todo/state.js +0 -425
  551. package/dist/extensions/todo/state.js.map +0 -1
  552. package/dist/extensions/todo/view.d.ts +0 -36
  553. package/dist/extensions/todo/view.d.ts.map +0 -1
  554. package/dist/extensions/todo/view.js +0 -580
  555. package/dist/extensions/todo/view.js.map +0 -1
  556. package/dist/extensions/todo/widget.d.ts +0 -15
  557. package/dist/extensions/todo/widget.d.ts.map +0 -1
  558. package/dist/extensions/todo/widget.js +0 -50
  559. package/dist/extensions/todo/widget.js.map +0 -1
  560. package/dist/modes/interactive/components/daxnuts.d.ts +0 -23
  561. package/dist/modes/interactive/components/daxnuts.d.ts.map +0 -1
  562. package/dist/modes/interactive/components/daxnuts.js +0 -138
  563. package/dist/modes/interactive/components/daxnuts.js.map +0 -1
  564. package/dist/modes/interactive/tasks/fallback-view.d.ts +0 -4
  565. package/dist/modes/interactive/tasks/fallback-view.d.ts.map +0 -1
  566. package/dist/modes/interactive/tasks/fallback-view.js +0 -27
  567. package/dist/modes/interactive/tasks/fallback-view.js.map +0 -1
  568. package/docs/bundled/extensions/todo.md +0 -104
  569. package/examples/extensions/todo.ts +0 -297
@@ -3,12 +3,15 @@
3
3
  *
4
4
  * Connects the servers from `mcp.json` and the servers extensions register with
5
5
  * `pi.registerMcpServer()` when a session starts, and servers registered later right away. A server
6
- * in `mcp.json` takes precedence over a registered server of the same name. Tools are registered as
7
- * `mcp__<server>__<tool>`. By default (`"exposure": "codemode"`) the tools are only callable from
8
- * codemode scripts, which keeps large MCP tool lists out of the model's tool declarations; the
9
- * codemode tool is activated for that unless `autoEnableCodemode` is false. `"codemode-deferred"`
10
- * leaves them out of the codemode description as well. `"deferred"` declares them to the model once
11
- * the `tool_search` tool loads them, and activates `tool_search` instead of codemode.
6
+ * in `mcp.json` takes precedence over a registered server of the same name. Connections run in the
7
+ * background: the first prompt waits only for servers with `direct` tools, and codemode scripts,
8
+ * `tool_search`, and the resource tools wait for the servers they need when they run. Tools are
9
+ * registered as `mcp__<server>__<tool>`. By default (`"exposure": "codemode"`) the tools are only
10
+ * callable from codemode scripts, which keeps MCP tools out of the model's tool declarations and
11
+ * the codemode description: scripts find the tools with `searchTools()` and the server instructions
12
+ * with `describeNamespace()`. The codemode tool is activated for that unless `autoEnableCodemode` is
13
+ * false. `"deferred"` declares the tools to the model once the `tool_search` tool loads them, and
14
+ * activates `tool_search` instead of codemode.
12
15
  * `"exposure": "direct"` declares them to the model right away, and `"hidden"` makes them
13
16
  * unreachable. `toolExposure` overrides the exposure of single tools. Servers with resources are
14
17
  * reached through Codex's `list_mcp_resources`, `list_mcp_resource_templates`, and
@@ -24,18 +27,23 @@
24
27
  */
25
28
  import { join, resolve } from "node:path";
26
29
  import { getAgentDir } from "../../config.js";
30
+ import { mcpNamespace } from "../../core/mcp-servers.js";
27
31
  import { openBrowser } from "../../utils/open-browser.js";
28
32
  import { getMcpToolExposure, loadMcpConfig, updateMcpServerConfig, } from "./config.js";
29
- import { createMcpResourceToolDefinitions } from "./resources.js";
33
+ import { createMcpResourceToolDefinitions, LIST_MCP_RESOURCE_TEMPLATES_TOOL, LIST_MCP_RESOURCES_TOOL, READ_MCP_RESOURCE_TOOL, } from "./resources.js";
30
34
  import { loadMcpRuntime } from "./runtime.lazy.js";
31
- import { createMcpToolDefinition, createMcpToolName } from "./tools.js";
35
+ import { createMcpToolDefinition, createMcpToolName, createMcpToolRenderers } from "./tools.js";
32
36
  import { showMcpManager } from "./ui.js";
33
37
  const DEFAULT_STARTUP_WAIT_MS = 10_000;
34
38
  const CODEMODE_TOOL_NAME = "codemode";
35
39
  const TOOL_SEARCH_TOOL_NAME = "tool_search";
40
+ const RESOURCE_TOOL_NAMES = new Set([
41
+ LIST_MCP_RESOURCES_TOOL,
42
+ LIST_MCP_RESOURCE_TEMPLATES_TOOL,
43
+ READ_MCP_RESOURCE_TOOL,
44
+ ]);
36
45
  const EXPOSURE_DESCRIPTIONS = {
37
- codemode: "called from codemode scripts, listed in the codemode description",
38
- "codemode-deferred": "called from codemode scripts, not listed; scripts find them with searchTools()",
46
+ codemode: "called from codemode scripts, which find them with searchTools()",
39
47
  deferred: "not declared until tool_search loads them, then called directly; no codemode needed",
40
48
  direct: "declared to the model like built-in tools",
41
49
  };
@@ -51,6 +59,86 @@ function isEnabled(server) {
51
59
  function exposureOf(entry) {
52
60
  return entry.config.exposure ?? "codemode";
53
61
  }
62
+ /** Exposures the server's tools can have, known from its config before it connects. */
63
+ function configuredExposures(entry) {
64
+ return new Set([exposureOf(entry), ...Object.values(entry.config.toolExposure ?? {})]);
65
+ }
66
+ /** Whether some of the server's tools are declared to the model, so the first prompt waits for them. */
67
+ function hasDirectTools(entry) {
68
+ return configuredExposures(entry).has("direct");
69
+ }
70
+ /** Whether some of the server's tools are reached through codemode or tool_search. */
71
+ function hasIndirectTools(entry) {
72
+ const exposures = configuredExposures(entry);
73
+ return exposures.has("codemode") || exposures.has("deferred");
74
+ }
75
+ /** Name of the system prompt section that lists the servers whose tools are not declared. */
76
+ export const MCP_SERVERS_SECTION = "mcp_servers";
77
+ /** Characters of a server description in the section, as Codex allows for deferred namespaces. */
78
+ const MAX_SERVER_DESCRIPTION_CHARS = 250;
79
+ /**
80
+ * Characters of the whole section. Descriptions shrink to fit; when the server lines alone do not
81
+ * fit, the last servers are left out and counted in a closing line.
82
+ */
83
+ export const MAX_SERVERS_SECTION_CHARS = 4096;
84
+ /** The section's first line. It explains only the ways of reaching tools that the listed servers use. */
85
+ function serversSectionIntro(reaches) {
86
+ let intro = "MCP servers whose tools are not declared to you.";
87
+ if (reaches.has("codemode"))
88
+ intro += " Call the tools of `codemode` servers from codemode scripts.";
89
+ if (reaches.has("tool_search"))
90
+ intro += " Load the tools of `tool_search` servers with `tool_search`.";
91
+ return intro;
92
+ }
93
+ function truncate(text, max) {
94
+ if (text.length <= max)
95
+ return text;
96
+ return max <= 1 ? "" : `${text.slice(0, max - 1).trimEnd()}…`;
97
+ }
98
+ /** First line of the configured description, or of the server instructions once connected. */
99
+ function serverSummary(server) {
100
+ const text = server.entry.config.description?.trim() || server.connection?.instructions || "";
101
+ return (text.split("\n", 1)[0] ?? "").trim();
102
+ }
103
+ /**
104
+ * The `mcp_servers` section: every enabled server with codemode or deferred tools, with how its
105
+ * tools are reached and a one-line summary. The model learns of the servers from it, since neither
106
+ * codemode nor tool_search lists them. Undefined when there are no such servers.
107
+ */
108
+ export function renderServersSection(servers) {
109
+ const listed = servers
110
+ .filter((server) => isEnabled(server) && hasIndirectTools(server.entry))
111
+ .sort((a, b) => a.entry.name.localeCompare(b.entry.name));
112
+ if (listed.length === 0)
113
+ return undefined;
114
+ const reaches = listed.map((server) => configuredExposures(server.entry).has("codemode") ? "codemode" : "tool_search");
115
+ const intro = serversSectionIntro(new Set(reaches));
116
+ const heads = listed.map((server, index) => `- ${mcpNamespace(server.entry.name)} (${reaches[index]})`);
117
+ const omitted = (count) => count > 0 ? [`- … ${count} more server${count === 1 ? "" : "s"}; find their tools with searchTools()`] : [];
118
+ // Characters of the intro, the first `kept` server lines without descriptions, and the omission line.
119
+ const size = (kept) => [intro, ...heads.slice(0, kept), ...omitted(listed.length - kept)].join("\n").length;
120
+ let kept = listed.length;
121
+ while (kept > 0 && size(kept) > MAX_SERVERS_SECTION_CHARS)
122
+ kept--;
123
+ // Each description also takes a ": " separator.
124
+ const perServer = kept === 0
125
+ ? 0
126
+ : Math.min(MAX_SERVER_DESCRIPTION_CHARS, Math.floor((MAX_SERVERS_SECTION_CHARS - size(kept)) / kept) - 2);
127
+ const lines = listed.slice(0, kept).map((server, index) => {
128
+ const summary = perServer > 0 ? truncate(serverSummary(server), perServer) : "";
129
+ return summary ? `${heads[index]}: ${summary}` : heads[index];
130
+ });
131
+ return [intro, ...lines, ...omitted(listed.length - kept)].join("\n");
132
+ }
133
+ /**
134
+ * Whether a codemode script needs the server: it names the server's namespace, or searches,
135
+ * enumerates, or describes tools or namespaces, which may name the server in other forms.
136
+ */
137
+ function scriptNeedsServer(code, server) {
138
+ if (/\b(searchTools|describeNamespace|describeTool|ALL_TOOLS)\b/.test(code))
139
+ return true;
140
+ return code.includes(mcpNamespace(server));
141
+ }
54
142
  /** Short state for lists and the startup report. `withError` appends the first line of a failure. */
55
143
  function describeState(server, withError = true) {
56
144
  if (!isEnabled(server))
@@ -105,6 +193,8 @@ export function createMcpExtension(options = {}) {
105
193
  /** Servers from `mcp.json`, which take precedence over registered servers of the same name. */
106
194
  let configuredEntries = [];
107
195
  let configErrors = [];
196
+ /** The trusted project's `mcp.json`, where `/mcp` saves project overrides of global servers. */
197
+ let projectConfig;
108
198
  /** Registered servers that `mcp.json` overrides, shown in `/mcp`. */
109
199
  let overridden = [];
110
200
  /** Between session_start and session_shutdown. Registrations before that are read on session_start. */
@@ -121,9 +211,14 @@ export function createMcpExtension(options = {}) {
121
211
  /** Working directory of the session, for stdio servers. */
122
212
  let sessionCwd = process.cwd();
123
213
  let credentials = options.credentials;
214
+ /** The session's model registry, which resolves `auth.provider` tokens. */
215
+ let modelRegistry;
124
216
  let serverLog;
125
217
  const openUrl = options.openUrl ?? openBrowser;
126
- const updateConfig = options.updateConfig ?? ((entry, patch) => updateMcpServerConfig(entry.source, entry.name, patch));
218
+ const updateConfig = options.updateConfig ??
219
+ ((entry, patch) => updateMcpServerConfig(entry.override ?? entry.source, entry.name, patch, {
220
+ override: entry.override !== undefined,
221
+ }));
127
222
  const listeners = new Set();
128
223
  const emitChange = () => {
129
224
  for (const listener of listeners)
@@ -142,9 +237,9 @@ export function createMcpExtension(options = {}) {
142
237
  const registered = [];
143
238
  const overriddenNames = [];
144
239
  for (const { name, config, extensionPath } of pi.getMcpServers()) {
145
- const configured = configuredEntries.find((entry) => entry.name === name);
240
+ const configured = configuredEntries.find((entry) => mcpNamespace(entry.name) === mcpNamespace(name));
146
241
  if (configured) {
147
- overriddenNames.push(`"${name}" registered by ${extensionPath} is overridden by ${configured.source}`);
242
+ overriddenNames.push(`"${name}" registered by ${extensionPath} is overridden by "${configured.name}" in ${configured.source}`);
148
243
  continue;
149
244
  }
150
245
  registered.push({
@@ -168,20 +263,31 @@ export function createMcpExtension(options = {}) {
168
263
  const serverTools = new Map();
169
264
  /** Last definition registered under each tool name, to re-register withdrawn tools as hidden. */
170
265
  const definitions = new Map();
266
+ // A resumed session renders calls to MCP tools before their server connected, if it ever does.
267
+ pi.registerToolRenderer((toolName, next) => {
268
+ const match = /^mcp__(.+?)__(.+)$/.exec(toolName);
269
+ return next() ?? (match ? createMcpToolRenderers(`${match[1]}/${match[2]}`) : undefined);
270
+ });
171
271
  const registerTools = (connection) => {
172
272
  const server = connection.entry.name;
173
273
  const entry = findServer(server)?.entry ?? connection.entry;
174
- const namespaceName = `mcp__${server}`;
274
+ const description = entry.config.description?.trim();
175
275
  const namespace = {
176
- name: namespaceName,
177
- description: connection.instructions ?? `Tools in the ${namespaceName} namespace.`,
276
+ name: mcpNamespace(server),
277
+ ...(description ? { description } : {}),
278
+ ...(connection.instructions ? { instructions: connection.instructions } : {}),
178
279
  };
179
280
  const previous = serverTools.get(server) ?? new Set();
180
281
  const current = new Set();
282
+ // Like Codex, all tools whose names sanitize to the same name get the hash suffix, so which
283
+ // one would keep the plain name does not depend on the order of the list.
284
+ const plain = [...new Set(connection.tools.map((tool) => tool.name))].map((tool) => createMcpToolName(server, tool));
181
285
  const assignName = (tool, owner) => {
182
286
  const name = createMcpToolName(server, tool, (candidate) => {
183
287
  const existing = toolOwners.get(candidate);
184
- return (existing !== undefined && existing !== owner) || current.has(candidate);
288
+ return ((existing !== undefined && existing !== owner) ||
289
+ current.has(candidate) ||
290
+ plain.indexOf(candidate) !== plain.lastIndexOf(candidate));
185
291
  });
186
292
  toolOwners.set(name, owner);
187
293
  current.add(name);
@@ -232,7 +338,7 @@ export function createMcpExtension(options = {}) {
232
338
  */
233
339
  const syncResourceTools = () => {
234
340
  const exposures = new Set(serversWithResources().map((server) => exposureOf(server.entry)));
235
- const exposure = ["direct", "codemode", "codemode-deferred", "deferred"].find((candidate) => exposures.has(candidate));
341
+ const exposure = ["direct", "codemode", "deferred"].find((candidate) => exposures.has(candidate));
236
342
  const next = exposure ?? "hidden";
237
343
  if (next === resourceToolsExposure || (resourceToolsExposure === undefined && next === "hidden"))
238
344
  return;
@@ -246,33 +352,40 @@ export function createMcpExtension(options = {}) {
246
352
  pi.setActiveTools(pi.getActiveTools().filter((name) => !names.has(name)));
247
353
  }
248
354
  };
355
+ /**
356
+ * Which of the tools are the bundled codemode and tool_search tools. Other extensions' tools of
357
+ * the same names cannot reach MCP tools. The owning extensions identify their tools through the
358
+ * event bus, so this extension does not import their internals.
359
+ */
360
+ const discoverOrchestrators = (tools) => {
361
+ const candidates = new Map(tools.map((tool) => [tool.name, tool.parameters]));
362
+ pi.events.emit("pi:discover-tool-orchestrators", candidates);
363
+ return {
364
+ codemode: candidates.get(CODEMODE_TOOL_NAME) === true,
365
+ toolSearch: candidates.get(TOOL_SEARCH_TOOL_NAME) === true,
366
+ };
367
+ };
249
368
  /**
250
369
  * Tools that are not declared to the model are reached through the codemode tool (scripts call
251
370
  * them) or the tool_search tool (it declares them). Either reaches every such tool. Activate the
252
- * one the tools' exposure asks for: codemode for `codemode` and `codemode-deferred` unless
253
- * `autoEnableCodemode` is false, tool_search for `deferred`.
371
+ * one the tools' exposure asks for: codemode for `codemode` unless `autoEnableCodemode` is false,
372
+ * tool_search for `deferred`.
254
373
  */
255
374
  const ensureDiscoveryActive = (ctx) => {
375
+ // From the config, so the tool is active before the servers connect. Resource tools share
376
+ // their server's exposure.
256
377
  const exposures = new Set();
257
- for (const { connection, entry } of servers) {
258
- if (connection?.state !== "connected")
259
- continue;
260
- // Resource tools share the server's exposure.
261
- if (connection.hasResources)
262
- exposures.add(exposureOf(entry));
263
- for (const tool of connection.tools)
264
- exposures.add(getMcpToolExposure(entry.config, tool.name));
378
+ for (const server of servers) {
379
+ if (isEnabled(server))
380
+ for (const exposure of configuredExposures(server.entry))
381
+ exposures.add(exposure);
265
382
  }
266
- const needsCodemode = exposures.has("codemode") || exposures.has("codemode-deferred");
383
+ const needsCodemode = exposures.has("codemode");
267
384
  const needsToolSearch = exposures.has("deferred");
268
385
  if (!needsCodemode && !needsToolSearch)
269
386
  return;
270
387
  // Other extensions' tools of the same names cannot reach MCP tools, so never activate them.
271
- const tools = pi.getAllTools();
272
- const candidates = new Map(tools.map((tool) => [tool.name, tool.parameters]));
273
- pi.events.emit("pi:discover-tool-orchestrators", candidates);
274
- const hasCodemode = candidates.get(CODEMODE_TOOL_NAME) === true;
275
- const hasToolSearch = candidates.get(TOOL_SEARCH_TOOL_NAME) === true;
388
+ const { codemode: hasCodemode, toolSearch: hasToolSearch } = discoverOrchestrators(pi.getAllTools());
276
389
  const active = pi.getActiveTools();
277
390
  const activate = [];
278
391
  if (needsCodemode && hasCodemode && autoEnableCodemode && !active.includes(CODEMODE_TOOL_NAME)) {
@@ -301,7 +414,7 @@ export function createMcpExtension(options = {}) {
301
414
  const tokensAtSignIn = new Map();
302
415
  const storedTokens = (connection) => {
303
416
  const url = connection.oauthUrl;
304
- return url && credentials ? JSON.stringify(credentials.tokens(url) ?? null) : "null";
417
+ return url && credentials ? JSON.stringify(credentials.tokens(connection.name, url) ?? null) : "null";
305
418
  };
306
419
  const onConnectionChange = (connection) => {
307
420
  if (connection.state !== "needs-auth")
@@ -328,6 +441,7 @@ export function createMcpExtension(options = {}) {
328
441
  cwd: sessionCwd,
329
442
  createTransport: options.createTransport ?? runtime.createDefaultTransport,
330
443
  credentials: getCredentials(runtime),
444
+ providerToken: async (provider) => modelRegistry?.getApiKeyForProvider(provider),
331
445
  log: getServerLog(runtime),
332
446
  onTools: registerTools,
333
447
  onChange: onConnectionChange,
@@ -336,6 +450,40 @@ export function createMcpExtension(options = {}) {
336
450
  emitChange();
337
451
  return connection;
338
452
  };
453
+ /**
454
+ * Connect the server in the background. `server.ready` settles when it connected or failed;
455
+ * failures show in its state. It starts after `after`; `isCurrent` stops it when the session ended
456
+ * meanwhile. The returned promise rejects when the MCP runtime cannot be loaded.
457
+ */
458
+ const startConnection = (server, isCurrent, after) => {
459
+ const ready = (async () => {
460
+ await after;
461
+ if (!isCurrent())
462
+ return;
463
+ const connection = await createConnection(server);
464
+ if (!isCurrent())
465
+ return;
466
+ await connection.getClient().catch(() => undefined);
467
+ })();
468
+ server.ready = ready.catch(() => undefined);
469
+ return ready;
470
+ };
471
+ /** Wait for servers still connecting, until they settle or `signal` aborts. */
472
+ const waitForServers = async (waiting, signal) => {
473
+ const ready = waiting.flatMap((server) => (server.ready ? [server.ready] : []));
474
+ if (ready.length === 0 || signal?.aborted)
475
+ return;
476
+ let onAbort;
477
+ await Promise.race([
478
+ Promise.all(ready),
479
+ new Promise((resolve) => {
480
+ onAbort = () => resolve();
481
+ signal?.addEventListener("abort", onAbort, { once: true });
482
+ }),
483
+ ]);
484
+ if (onAbort)
485
+ signal?.removeEventListener("abort", onAbort);
486
+ };
339
487
  /**
340
488
  * One message for everything that needs the user after startup, or only for `only`, servers
341
489
  * that connected later.
@@ -353,18 +501,20 @@ export function createMcpExtension(options = {}) {
353
501
  };
354
502
  /**
355
503
  * Save a config change; returns an error message when the file could not be updated. Changes to
356
- * registered servers only apply to the current session.
504
+ * registered servers only apply to the current session. `inProject` adds a project override.
357
505
  */
358
- const saveConfig = (server, patch) => {
359
- if (server.entry.scope !== "extension") {
506
+ const saveConfig = (server, patch, inProject = false) => {
507
+ const override = inProject ? projectConfig : server.entry.override;
508
+ const entry = override ? { ...server.entry, override } : server.entry;
509
+ if (entry.scope !== "extension") {
360
510
  try {
361
- updateConfig(server.entry, patch);
511
+ updateConfig(entry, patch);
362
512
  }
363
513
  catch (error) {
364
- return `Could not update ${server.entry.source}: ${errorMessage(error)}`;
514
+ return `Could not update ${entry.override ?? entry.source}: ${errorMessage(error)}`;
365
515
  }
366
516
  }
367
- server.entry = { ...server.entry, config: { ...server.entry.config, ...patch } };
517
+ server.entry = { ...entry, config: { ...entry.config, ...patch } };
368
518
  return undefined;
369
519
  };
370
520
  const signIn = async (server, prompt) => {
@@ -376,7 +526,7 @@ export function createMcpExtension(options = {}) {
376
526
  try {
377
527
  await runtime.signInMcpServer({
378
528
  serverUrl: url,
379
- store: getCredentials(runtime).forServer(url),
529
+ store: getCredentials(runtime).forServer(server.entry.name, url),
380
530
  settings: connection.oauthSettings(),
381
531
  challenge: connection.challenge,
382
532
  prompt,
@@ -402,7 +552,7 @@ export function createMcpExtension(options = {}) {
402
552
  const url = connection?.oauthUrl;
403
553
  if (!connection || !url)
404
554
  return false;
405
- const removed = getCredentials(await loadMcpRuntime()).remove(url);
555
+ const removed = getCredentials(await loadMcpRuntime()).remove(server.entry.name, url);
406
556
  await connection.signOut();
407
557
  return removed;
408
558
  };
@@ -419,8 +569,8 @@ export function createMcpExtension(options = {}) {
419
569
  }
420
570
  };
421
571
  /** Returns an error message when the config could not be saved; connection errors show in the state. */
422
- const setEnabled = async (server, enabled) => {
423
- const failed = saveConfig(server, { enabled });
572
+ const setEnabled = async (server, enabled, inProject = false) => {
573
+ const failed = saveConfig(server, { enabled }, inProject);
424
574
  if (failed)
425
575
  return failed;
426
576
  if (!enabled) {
@@ -431,8 +581,7 @@ export function createMcpExtension(options = {}) {
431
581
  await connection?.close();
432
582
  return undefined;
433
583
  }
434
- const connection = await createConnection(server);
435
- await connection.getClient().catch(() => undefined);
584
+ await startConnection(server, () => true);
436
585
  return undefined;
437
586
  };
438
587
  const setExposure = (server, exposure) => {
@@ -467,7 +616,7 @@ export function createMcpExtension(options = {}) {
467
616
  .map((server) => ({
468
617
  value: server.entry.name,
469
618
  label: server.entry.name,
470
- description: `${describeState(server)} · ${exposureOf(server.entry)} · ${server.entry.scope ?? server.entry.source}`,
619
+ description: `${describeState(server)} · ${exposureOf(server.entry)} · ${server.entry.override ? "global, project override" : (server.entry.scope ?? server.entry.source)}`,
471
620
  })),
472
621
  empty: `No MCP servers configured. Add them to ${resolve(getAgentDir(), "mcp.json")} or .pi/mcp.json.`,
473
622
  confirmLabel: "manage",
@@ -487,12 +636,20 @@ export function createMcpExtension(options = {}) {
487
636
  const { entry, connection } = server;
488
637
  const saved = entry.scope === "extension"
489
638
  ? "for this session"
490
- : entry.scope
491
- ? `saved to the ${entry.scope} mcp.json`
492
- : "saved to mcp.json";
639
+ : entry.override
640
+ ? "saved to the project mcp.json"
641
+ : entry.scope
642
+ ? `saved to the ${entry.scope} mcp.json`
643
+ : "saved to mcp.json";
644
+ // Global servers without an override can be turned on or off for the trusted project alone.
645
+ const inProject = entry.scope === "global" && !entry.override && projectConfig !== undefined;
646
+ const inProjectSaved = "saved to the project mcp.json";
493
647
  const items = [];
494
648
  if (!isEnabled(server)) {
495
649
  items.push({ value: "enable", label: "Enable", description: saved });
650
+ if (inProject) {
651
+ items.push({ value: "enable-project", label: "Enable in this project", description: inProjectSaved });
652
+ }
496
653
  }
497
654
  else {
498
655
  const state = connection?.state;
@@ -509,10 +666,14 @@ export function createMcpExtension(options = {}) {
509
666
  }
510
667
  items.push({ value: "exposure", label: "Exposure", description: exposureOf(entry) });
511
668
  items.push({ value: "disable", label: "Disable", description: saved });
669
+ if (inProject) {
670
+ items.push({ value: "disable-project", label: "Disable in this project", description: inProjectSaved });
671
+ }
512
672
  }
513
673
  const details = [
514
674
  describeTransport(entry),
515
675
  `${entry.scope ?? "config"}: ${entry.source}`,
676
+ ...(entry.override ? [`project override: ${entry.override}`] : []),
516
677
  `State: ${describeState(server, false)}`,
517
678
  ];
518
679
  const error = [server.message, connection?.state === "connected" ? undefined : connection?.error]
@@ -554,7 +715,7 @@ export function createMcpExtension(options = {}) {
554
715
  title: `Exposure of ${server.entry.name}`,
555
716
  details: server.entry.scope === "extension"
556
717
  ? `Applies to this session; the server is registered by ${server.entry.source}.`
557
- : `Saved to ${server.entry.source}.`,
718
+ : `Saved to ${server.entry.override ?? server.entry.source}.`,
558
719
  items: Object.keys(EXPOSURE_DESCRIPTIONS).map((exposure) => ({
559
720
  value: exposure,
560
721
  label: `${exposure === current ? "✓ " : " "}${exposure}`,
@@ -568,27 +729,30 @@ export function createMcpExtension(options = {}) {
568
729
  return undefined;
569
730
  return setExposure(server, choice);
570
731
  };
732
+ /** Sign in with the manager view's sign-in screen, which shows the URL with a copy key. */
733
+ const signInWithUi = (ui, server) => {
734
+ const title = `Sign in to ${server.entry.name}`;
735
+ let authorizationUrl = "";
736
+ ui.status(title, "Contacting the authorization server…");
737
+ return signIn(server, {
738
+ showAuthorizationUrl: (url) => {
739
+ authorizationUrl = url.href;
740
+ openUrl(url.href);
741
+ },
742
+ promptForRedirectUrl: async (signal) => {
743
+ const value = await ui.redirectUrl(title, authorizationUrl, signal);
744
+ ui.status(title, "Connecting…");
745
+ return value;
746
+ },
747
+ });
748
+ };
571
749
  const runAction = async (ui, ctx, server, action) => {
572
750
  const { name } = server.entry;
573
751
  let message;
574
752
  switch (action) {
575
- case "signin": {
576
- const title = `Sign in to ${name}`;
577
- let authorizationUrl = "";
578
- ui.status(title, "Contacting the authorization server…");
579
- message = await signIn(server, {
580
- showAuthorizationUrl: (url) => {
581
- authorizationUrl = url.href;
582
- openUrl(url.href);
583
- },
584
- promptForRedirectUrl: async (signal) => {
585
- const value = await ui.redirectUrl(title, authorizationUrl, signal);
586
- ui.status(title, "Connecting…");
587
- return value;
588
- },
589
- });
753
+ case "signin":
754
+ message = await signInWithUi(ui, server);
590
755
  break;
591
- }
592
756
  case "reconnect":
593
757
  // A failure shows as the connection's state and error.
594
758
  ui.status(`MCP server ${name}`, "Reconnecting…");
@@ -605,9 +769,13 @@ export function createMcpExtension(options = {}) {
605
769
  break;
606
770
  case "enable":
607
771
  case "disable":
608
- ui.status(`MCP server ${name}`, action === "enable" ? "Connecting…" : "Disconnecting…");
609
- message = await setEnabled(server, action === "enable");
772
+ case "enable-project":
773
+ case "disable-project": {
774
+ const enable = action.startsWith("enable");
775
+ ui.status(`MCP server ${name}`, enable ? "Connecting…" : "Disconnecting…");
776
+ message = await setEnabled(server, enable, action.endsWith("-project"));
610
777
  break;
778
+ }
611
779
  }
612
780
  server.message = message;
613
781
  ensureDiscoveryActive(ctx);
@@ -692,13 +860,21 @@ export function createMcpExtension(options = {}) {
692
860
  ctx.ui.notify(`Signing in to MCP server "${name}" requires interactive mode.`, "error");
693
861
  return;
694
862
  }
695
- const failure = await signIn(server, {
696
- showAuthorizationUrl: (url) => {
697
- ctx.ui.notify(`Sign in to MCP server "${name}" in your browser:\n${url.href}`, "info");
698
- openUrl(url.href);
699
- },
700
- promptForRedirectUrl: (signal) => ctx.ui.input(`Waiting for sign-in to "${name}". If the browser cannot reach this machine, paste the URL it was redirected to.`, "http://127.0.0.1:.../callback?code=...", { signal }),
701
- });
863
+ let failure;
864
+ if (ctx.mode === "tui") {
865
+ await showMcpManager(ctx, async (ui) => {
866
+ failure = await signInWithUi(ui, server);
867
+ });
868
+ }
869
+ else {
870
+ failure = await signIn(server, {
871
+ showAuthorizationUrl: (url) => {
872
+ ctx.ui.notify(`Sign in to MCP server "${name}" in your browser:\n${url.href}`, "info");
873
+ openUrl(url.href);
874
+ },
875
+ promptForRedirectUrl: (signal) => ctx.ui.input(`Waiting for sign-in to "${name}". If the browser cannot reach this machine, paste the URL it was redirected to.`, "http://127.0.0.1:.../callback?code=...", { signal }),
876
+ });
877
+ }
702
878
  if (failure) {
703
879
  ctx.ui.notify(failure, failure === "Sign-in cancelled." ? "info" : "error");
704
880
  return;
@@ -709,10 +885,12 @@ export function createMcpExtension(options = {}) {
709
885
  pi.on("session_start", (_event, ctx) => {
710
886
  const loaded = (options.loadConfig ?? defaultLoadConfig)(ctx);
711
887
  configErrors = loaded.errors;
888
+ projectConfig = loaded.projectConfig;
712
889
  autoEnableCodemode = loaded.autoEnableCodemode ?? true;
713
890
  warnedUnreachable = false;
714
891
  waitedForStartup = false;
715
892
  sessionCwd = ctx.cwd;
893
+ modelRegistry = ctx.modelRegistry;
716
894
  const current = ++generation;
717
895
  sessionActive = true;
718
896
  configuredEntries = loaded.servers;
@@ -720,6 +898,9 @@ export function createMcpExtension(options = {}) {
720
898
  overridden = registered.overridden;
721
899
  servers = [...loaded.servers.map((entry) => ({ entry })), ...registered.servers];
722
900
  emitChange();
901
+ // Codemode or tool_search is activated from the config: the first prompt does not wait for
902
+ // servers whose tools are not declared to the model, and scripts or searches wait for them.
903
+ ensureDiscoveryActive(ctx);
723
904
  const enabled = servers.filter(isEnabled);
724
905
  if (enabled.length === 0) {
725
906
  reportProblems(ctx);
@@ -727,19 +908,12 @@ export function createMcpExtension(options = {}) {
727
908
  }
728
909
  // The MCP client loads only now, so sessions without servers never pay for it. Waiting one
729
910
  // event loop turn lets the first render happen before loading and connecting.
730
- pending = new Promise((resolve) => setImmediate(resolve))
731
- .then(() => loadMcpRuntime())
732
- .then(async () => {
733
- if (current !== generation)
734
- return;
735
- const started = await Promise.all(enabled.map((server) => createConnection(server)));
736
- if (current !== generation)
737
- return;
738
- await Promise.allSettled(started.map((connection) => connection.getClient()));
739
- if (current !== generation)
740
- return;
741
- ensureDiscoveryActive(ctx);
742
- reportProblems(ctx);
911
+ const runtime = new Promise((resolve) => setImmediate(resolve)).then(() => loadMcpRuntime());
912
+ const isCurrent = () => current === generation;
913
+ pending = Promise.all(enabled.map((server) => startConnection(server, isCurrent, runtime)))
914
+ .then(() => {
915
+ if (isCurrent())
916
+ reportProblems(ctx);
743
917
  })
744
918
  .catch((error) => {
745
919
  // The session may have been disposed meanwhile, which makes ctx stale.
@@ -749,16 +923,19 @@ export function createMcpExtension(options = {}) {
749
923
  catch { }
750
924
  });
751
925
  });
752
- // The first prompt waits for startup connections so their tools are available to it, but not
753
- // indefinitely: a slow or hanging server must not hold up the prompt.
754
- pi.on("before_agent_start", async (_event, ctx) => {
755
- const startup = pending;
756
- if (!startup || waitedForStartup)
926
+ // The first prompt waits for servers whose tools are declared to the model, so they are declared
927
+ // in its first request, but not indefinitely: a slow or hanging server must not hold up the
928
+ // prompt. Other servers are waited for when a script or search needs them (below).
929
+ const waitForDirectServers = async (ctx) => {
930
+ if (waitedForStartup)
757
931
  return;
758
932
  waitedForStartup = true;
933
+ const ready = servers.flatMap((server) => isEnabled(server) && hasDirectTools(server.entry) && server.ready ? [server.ready] : []);
934
+ if (ready.length === 0)
935
+ return;
759
936
  let timer;
760
937
  const finished = await Promise.race([
761
- startup.then(() => true),
938
+ Promise.all(ready).then(() => true),
762
939
  new Promise((resolve) => {
763
940
  timer = setTimeout(() => resolve(false), startupWaitMs);
764
941
  }),
@@ -767,6 +944,39 @@ export function createMcpExtension(options = {}) {
767
944
  if (!finished) {
768
945
  ctx.ui.notify("MCP servers are still connecting; their tools become available once connected.", "info");
769
946
  }
947
+ };
948
+ // Every prompt lists the servers in the `mcp_servers` section as they are when it starts. Pi
949
+ // appends the section to the conversation when it changed, for example after a server connected.
950
+ pi.on("before_agent_start", async (event, ctx) => {
951
+ await waitForDirectServers(ctx);
952
+ const { sections } = event.systemPromptOptions;
953
+ const section = renderServersSection(servers);
954
+ if (section)
955
+ sections[MCP_SERVERS_SECTION] = section;
956
+ else
957
+ delete sections[MCP_SERVERS_SECTION];
958
+ });
959
+ // A codemode script waits for the servers it names, or for every server when it searches or
960
+ // enumerates tools, so their tools are registered before the script runs. tool_search and the
961
+ // resource tools reach every server, so they wait for all of them.
962
+ pi.on("tool_call", async (event, ctx) => {
963
+ const tool = pi.getAllTools().find((candidate) => candidate.name === event.toolName);
964
+ if (!tool)
965
+ return;
966
+ const pendingServers = servers.filter((server) => isEnabled(server) && server.connection?.state !== "connected" && server.ready);
967
+ if (pendingServers.length === 0)
968
+ return;
969
+ let waiting = [];
970
+ const orchestrator = discoverOrchestrators([tool]);
971
+ if (orchestrator.codemode) {
972
+ const { code } = event.input;
973
+ const source = typeof code === "string" ? code : "";
974
+ waiting = pendingServers.filter((server) => scriptNeedsServer(source, server.entry.name));
975
+ }
976
+ else if (orchestrator.toolSearch || RESOURCE_TOOL_NAMES.has(tool.name)) {
977
+ waiting = pendingServers;
978
+ }
979
+ await waitForServers(waiting, ctx.signal);
770
980
  });
771
981
  // Pick up sign-ins done outside the session, such as `pi mcp login` run by the agent.
772
982
  pi.on("turn_start", async (_event, ctx) => {
@@ -790,17 +1000,17 @@ export function createMcpExtension(options = {}) {
790
1000
  const added = registered.servers.filter((server) => !findServer(server.entry.name));
791
1001
  servers.push(...added);
792
1002
  emitChange();
1003
+ ensureDiscoveryActive(ctx);
793
1004
  await Promise.all(removed.map((server) => server.connection?.close()));
794
1005
  const connecting = added.filter(isEnabled);
795
1006
  if (current !== generation || connecting.length === 0)
796
1007
  return;
797
1008
  try {
798
- const started = await Promise.all(connecting.map((server) => createConnection(server)));
1009
+ await Promise.all(connecting.map((server) => startConnection(server, () => current === generation)));
799
1010
  if (current !== generation) {
800
- await Promise.all(started.map((connection) => connection.close()));
1011
+ await Promise.all(connecting.map((server) => server.connection?.close()));
801
1012
  return;
802
1013
  }
803
- await Promise.allSettled(started.map((connection) => connection.getClient()));
804
1014
  }
805
1015
  catch (error) {
806
1016
  ctx.ui.notify(`MCP failed to load: ${errorMessage(error)}`, "error");
@@ -808,7 +1018,6 @@ export function createMcpExtension(options = {}) {
808
1018
  }
809
1019
  if (current !== generation)
810
1020
  return;
811
- ensureDiscoveryActive(ctx);
812
1021
  reportProblems(ctx, connecting);
813
1022
  });
814
1023
  pi.on("session_shutdown", async () => {