@astralyn/pi 1.0.4 → 1.1.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 (332) hide show
  1. package/CHANGELOG.md +53 -0
  2. package/dist/bundle/chunks/{anthropic-messages-YIOJIMVL.js → anthropic-messages-3K3DWVY6.js} +1 -1
  3. package/dist/bundle/chunks/anthropic.js +1 -1
  4. package/dist/bundle/chunks/{azure-openai-responses-LDW4FGAQ.js → azure-openai-responses-CH74HGP4.js} +1 -1
  5. package/dist/bundle/chunks/bedrock-converse-stream.js +2 -2
  6. package/dist/bundle/chunks/{chunk-UCXU7KLO.js → chunk-3MMB5I7J.js} +1 -1
  7. package/dist/bundle/chunks/{chunk-GIG5IHES.js → chunk-5KJH3GGH.js} +1 -1
  8. package/dist/bundle/chunks/chunk-6VYRLG5F.js +2 -0
  9. package/dist/bundle/chunks/{chunk-73WG7F7N.js → chunk-C2ARIVS3.js} +1 -1
  10. package/dist/bundle/chunks/{chunk-23OTKHCH.js → chunk-D3XW5X3Z.js} +490 -260
  11. package/dist/bundle/chunks/{chunk-IFELM7MW.js → chunk-EJEOEBSJ.js} +1 -1
  12. package/dist/bundle/chunks/chunk-H35KWBT5.js +11 -0
  13. package/dist/bundle/chunks/chunk-KAC2YPTW.js +2 -0
  14. package/dist/bundle/chunks/chunk-MAC4N3BW.js +2 -0
  15. package/dist/bundle/chunks/chunk-QLU3LESZ.js +2 -0
  16. package/dist/bundle/chunks/{chunk-A6ALEEY5.js → chunk-TEAAYBTS.js} +1 -1
  17. package/dist/bundle/chunks/cloudflare-workers-ai-system-one-XO45ZT3V.js +2 -0
  18. package/dist/bundle/chunks/codemode-worker.js +101 -5
  19. package/dist/bundle/chunks/github-copilot.js +1 -1
  20. package/dist/bundle/chunks/{google-generative-ai-S5A5IBU4.js → google-generative-ai-VVO64ZRQ.js} +1 -1
  21. package/dist/bundle/chunks/{google-vertex-UBRQFDB4.js → google-vertex-LKS5NUHA.js} +1 -1
  22. package/dist/bundle/chunks/image-resize-worker.js +1 -1
  23. package/dist/bundle/chunks/{llama-cpp-classify-R7DQLTQN.js → llama-cpp-classify-H3IZDR5O.js} +2 -2
  24. package/dist/bundle/chunks/{mistral-conversations-A2N5FSOV.js → mistral-conversations-NJUOG4ET.js} +2 -2
  25. package/dist/bundle/chunks/openai-chatgpt.js +1 -1
  26. package/dist/bundle/chunks/{openai-codex-responses-Q6JHCWLE.js → openai-codex-responses-TZWBTTYM.js} +2 -2
  27. package/dist/bundle/chunks/openai-codex.js +1 -1
  28. package/dist/bundle/chunks/{openai-completions-H4VMO7AU.js → openai-completions-7HTTU6FH.js} +1 -1
  29. package/dist/bundle/chunks/openai-decisions-776H4VDZ.js +5 -0
  30. package/dist/bundle/chunks/{openai-responses-G4PGNM2H.js → openai-responses-7A6BAQ5X.js} +1 -1
  31. package/dist/bundle/chunks/{openrouter-images-YP3YVB54.js → openrouter-images-TDLJV5N4.js} +1 -1
  32. package/dist/bundle/chunks/{pi-messages-HZZ7GEEW.js → pi-messages-ZXNERWJG.js} +1 -1
  33. package/dist/bundle/chunks/typesafe-system-one-2DQLG4R2.js +2 -0
  34. package/dist/bundle/chunks/{virtual-modules-IJTAY26N.js → virtual-modules-2NHGQRS6.js} +1 -1
  35. package/dist/bundle/cli.js +1 -1
  36. package/dist/bundle/index.js +1 -1
  37. package/dist/bundle/rpc-entry.js +1 -1
  38. package/dist/cli/args.d.ts +2 -1
  39. package/dist/cli/args.d.ts.map +1 -1
  40. package/dist/cli/args.js +24 -5
  41. package/dist/cli/args.js.map +1 -1
  42. package/dist/core/agent-session.d.ts +38 -10
  43. package/dist/core/agent-session.d.ts.map +1 -1
  44. package/dist/core/agent-session.js +190 -186
  45. package/dist/core/agent-session.js.map +1 -1
  46. package/dist/core/bash-executor.d.ts.map +1 -1
  47. package/dist/core/bash-executor.js +40 -45
  48. package/dist/core/bash-executor.js.map +1 -1
  49. package/dist/core/context-snapshot.d.ts +4 -1
  50. package/dist/core/context-snapshot.d.ts.map +1 -1
  51. package/dist/core/context-snapshot.js +45 -0
  52. package/dist/core/context-snapshot.js.map +1 -1
  53. package/dist/core/export-html/tool-renderer.d.ts.map +1 -1
  54. package/dist/core/export-html/tool-renderer.js +2 -0
  55. package/dist/core/export-html/tool-renderer.js.map +1 -1
  56. package/dist/core/extensions/types.d.ts +13 -0
  57. package/dist/core/extensions/types.d.ts.map +1 -1
  58. package/dist/core/extensions/types.js.map +1 -1
  59. package/dist/core/mcp-servers.d.ts +8 -0
  60. package/dist/core/mcp-servers.d.ts.map +1 -1
  61. package/dist/core/mcp-servers.js +30 -7
  62. package/dist/core/mcp-servers.js.map +1 -1
  63. package/dist/core/model-runtime.d.ts.map +1 -1
  64. package/dist/core/model-runtime.js +2 -1
  65. package/dist/core/model-runtime.js.map +1 -1
  66. package/dist/core/nested-tool-calls.d.ts +1 -0
  67. package/dist/core/nested-tool-calls.d.ts.map +1 -1
  68. package/dist/core/nested-tool-calls.js +1 -0
  69. package/dist/core/nested-tool-calls.js.map +1 -1
  70. package/dist/core/resource-loader.d.ts +3 -0
  71. package/dist/core/resource-loader.d.ts.map +1 -1
  72. package/dist/core/resource-loader.js +3 -3
  73. package/dist/core/resource-loader.js.map +1 -1
  74. package/dist/core/sdk.d.ts +13 -4
  75. package/dist/core/sdk.d.ts.map +1 -1
  76. package/dist/core/sdk.js +19 -6
  77. package/dist/core/sdk.js.map +1 -1
  78. package/dist/core/settings-manager.d.ts +13 -0
  79. package/dist/core/settings-manager.d.ts.map +1 -1
  80. package/dist/core/settings-manager.js +37 -13
  81. package/dist/core/settings-manager.js.map +1 -1
  82. package/dist/core/skills.d.ts +4 -1
  83. package/dist/core/skills.d.ts.map +1 -1
  84. package/dist/core/skills.js +6 -1
  85. package/dist/core/skills.js.map +1 -1
  86. package/dist/core/system-prompt.d.ts +6 -0
  87. package/dist/core/system-prompt.d.ts.map +1 -1
  88. package/dist/core/system-prompt.js +9 -4
  89. package/dist/core/system-prompt.js.map +1 -1
  90. package/dist/core/tasks/session.d.ts +9 -0
  91. package/dist/core/tasks/session.d.ts.map +1 -1
  92. package/dist/core/tasks/session.js +21 -0
  93. package/dist/core/tasks/session.js.map +1 -1
  94. package/dist/core/tools/read.d.ts +13 -0
  95. package/dist/core/tools/read.d.ts.map +1 -1
  96. package/dist/core/tools/read.js +18 -1
  97. package/dist/core/tools/read.js.map +1 -1
  98. package/dist/core/tools/renderers/bash.d.ts.map +1 -1
  99. package/dist/core/tools/renderers/bash.js +8 -3
  100. package/dist/core/tools/renderers/bash.js.map +1 -1
  101. package/dist/core/tools/renderers/edit.js +1 -1
  102. package/dist/core/tools/renderers/edit.js.map +1 -1
  103. package/dist/extensions/codemode/execute.d.ts.map +1 -1
  104. package/dist/extensions/codemode/execute.js +65 -8
  105. package/dist/extensions/codemode/execute.js.map +1 -1
  106. package/dist/extensions/codemode/index.d.ts.map +1 -1
  107. package/dist/extensions/codemode/index.js +1 -0
  108. package/dist/extensions/codemode/index.js.map +1 -1
  109. package/dist/extensions/codemode/tool.d.ts +9 -2
  110. package/dist/extensions/codemode/tool.d.ts.map +1 -1
  111. package/dist/extensions/codemode/tool.js +14 -6
  112. package/dist/extensions/codemode/tool.js.map +1 -1
  113. package/dist/extensions/index.js +2 -2
  114. package/dist/extensions/index.js.map +1 -1
  115. package/dist/extensions/llama/provider.d.ts.map +1 -1
  116. package/dist/extensions/llama/provider.js +34 -11
  117. package/dist/extensions/llama/provider.js.map +1 -1
  118. package/dist/extensions/mcp/cli.js +17 -23
  119. package/dist/extensions/mcp/cli.js.map +1 -1
  120. package/dist/extensions/mcp/index.d.ts.map +1 -1
  121. package/dist/extensions/mcp/index.js +165 -64
  122. package/dist/extensions/mcp/index.js.map +1 -1
  123. package/dist/extensions/mcp/oauth.d.ts +5 -3
  124. package/dist/extensions/mcp/oauth.d.ts.map +1 -1
  125. package/dist/extensions/mcp/oauth.js +36 -10
  126. package/dist/extensions/mcp/oauth.js.map +1 -1
  127. package/dist/extensions/mcp/resources.d.ts +3 -4
  128. package/dist/extensions/mcp/resources.d.ts.map +1 -1
  129. package/dist/extensions/mcp/resources.js +3 -4
  130. package/dist/extensions/mcp/resources.js.map +1 -1
  131. package/dist/extensions/mcp/runtime.d.ts +4 -1
  132. package/dist/extensions/mcp/runtime.d.ts.map +1 -1
  133. package/dist/extensions/mcp/runtime.js +22 -5
  134. package/dist/extensions/mcp/runtime.js.map +1 -1
  135. package/dist/extensions/mcp/tools.d.ts +2 -1
  136. package/dist/extensions/mcp/tools.d.ts.map +1 -1
  137. package/dist/extensions/mcp/tools.js +2 -1
  138. package/dist/extensions/mcp/tools.js.map +1 -1
  139. package/dist/extensions/mcp/ui.d.ts +3 -3
  140. package/dist/extensions/mcp/ui.d.ts.map +1 -1
  141. package/dist/extensions/mcp/ui.js +10 -2
  142. package/dist/extensions/mcp/ui.js.map +1 -1
  143. package/dist/extensions/search/code-search.d.ts +29 -0
  144. package/dist/extensions/search/code-search.d.ts.map +1 -0
  145. package/dist/extensions/search/code-search.js +120 -0
  146. package/dist/extensions/search/code-search.js.map +1 -0
  147. package/dist/extensions/search/command.d.ts +5 -0
  148. package/dist/extensions/search/command.d.ts.map +1 -0
  149. package/dist/extensions/search/command.js +69 -0
  150. package/dist/extensions/search/command.js.map +1 -0
  151. package/dist/extensions/search/credential.d.ts +25 -0
  152. package/dist/extensions/search/credential.d.ts.map +1 -0
  153. package/dist/extensions/search/credential.js +117 -0
  154. package/dist/extensions/search/credential.js.map +1 -0
  155. package/dist/extensions/search/devin.d.ts +34 -0
  156. package/dist/extensions/search/devin.d.ts.map +1 -0
  157. package/dist/extensions/search/devin.js +210 -0
  158. package/dist/extensions/search/devin.js.map +1 -0
  159. package/dist/extensions/search/index.d.ts +5 -0
  160. package/dist/extensions/search/index.d.ts.map +1 -0
  161. package/dist/extensions/search/index.js +110 -0
  162. package/dist/extensions/search/index.js.map +1 -0
  163. package/dist/extensions/search/panel.d.ts +53 -0
  164. package/dist/extensions/search/panel.d.ts.map +1 -0
  165. package/dist/extensions/search/panel.js +157 -0
  166. package/dist/extensions/search/panel.js.map +1 -0
  167. package/dist/extensions/search/prompt.d.ts +14 -0
  168. package/dist/extensions/search/prompt.d.ts.map +1 -0
  169. package/dist/extensions/search/prompt.js +221 -0
  170. package/dist/extensions/search/prompt.js.map +1 -0
  171. package/dist/extensions/search/render.d.ts +28 -0
  172. package/dist/extensions/search/render.d.ts.map +1 -0
  173. package/dist/extensions/search/render.js +86 -0
  174. package/dist/extensions/search/render.js.map +1 -0
  175. package/dist/extensions/search/workspace.d.ts +38 -0
  176. package/dist/extensions/search/workspace.d.ts.map +1 -0
  177. package/dist/extensions/search/workspace.js +245 -0
  178. package/dist/extensions/search/workspace.js.map +1 -0
  179. package/dist/main.d.ts.map +1 -1
  180. package/dist/main.js +1 -0
  181. package/dist/main.js.map +1 -1
  182. package/dist/modes/interactive/components/bash-execution.d.ts +5 -1
  183. package/dist/modes/interactive/components/bash-execution.d.ts.map +1 -1
  184. package/dist/modes/interactive/components/bash-execution.js +14 -14
  185. package/dist/modes/interactive/components/bash-execution.js.map +1 -1
  186. package/dist/modes/interactive/components/branch-summary-message.d.ts +2 -1
  187. package/dist/modes/interactive/components/branch-summary-message.d.ts.map +1 -1
  188. package/dist/modes/interactive/components/branch-summary-message.js +5 -2
  189. package/dist/modes/interactive/components/branch-summary-message.js.map +1 -1
  190. package/dist/modes/interactive/components/compaction-summary-message.d.ts +2 -1
  191. package/dist/modes/interactive/components/compaction-summary-message.d.ts.map +1 -1
  192. package/dist/modes/interactive/components/compaction-summary-message.js +5 -2
  193. package/dist/modes/interactive/components/compaction-summary-message.js.map +1 -1
  194. package/dist/modes/interactive/components/custom-entry.d.ts +3 -1
  195. package/dist/modes/interactive/components/custom-entry.d.ts.map +1 -1
  196. package/dist/modes/interactive/components/custom-entry.js +7 -2
  197. package/dist/modes/interactive/components/custom-entry.js.map +1 -1
  198. package/dist/modes/interactive/components/custom-message.d.ts.map +1 -1
  199. package/dist/modes/interactive/components/custom-message.js +1 -0
  200. package/dist/modes/interactive/components/custom-message.js.map +1 -1
  201. package/dist/modes/interactive/components/settings-selector.js +1 -1
  202. package/dist/modes/interactive/components/settings-selector.js.map +1 -1
  203. package/dist/modes/interactive/components/skill-invocation-message.d.ts +2 -1
  204. package/dist/modes/interactive/components/skill-invocation-message.d.ts.map +1 -1
  205. package/dist/modes/interactive/components/skill-invocation-message.js +5 -2
  206. package/dist/modes/interactive/components/skill-invocation-message.js.map +1 -1
  207. package/dist/modes/interactive/interactive-mode.d.ts +2 -0
  208. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  209. package/dist/modes/interactive/interactive-mode.js +52 -59
  210. package/dist/modes/interactive/interactive-mode.js.map +1 -1
  211. package/dist/modes/interactive/program-status-reporter.d.ts +34 -0
  212. package/dist/modes/interactive/program-status-reporter.d.ts.map +1 -0
  213. package/dist/modes/interactive/program-status-reporter.js +107 -0
  214. package/dist/modes/interactive/program-status-reporter.js.map +1 -0
  215. package/dist/modes/interactive/tasks/host-hooks.d.ts +14 -0
  216. package/dist/modes/interactive/tasks/host-hooks.d.ts.map +1 -0
  217. package/dist/modes/interactive/tasks/host-hooks.js +31 -0
  218. package/dist/modes/interactive/tasks/host-hooks.js.map +1 -0
  219. package/dist/modes/interactive/theme/theme.d.ts.map +1 -1
  220. package/dist/modes/interactive/theme/theme.js +1 -0
  221. package/dist/modes/interactive/theme/theme.js.map +1 -1
  222. package/dist/modes/interactive/tool-view/tool-execution.d.ts +5 -0
  223. package/dist/modes/interactive/tool-view/tool-execution.d.ts.map +1 -1
  224. package/dist/modes/interactive/tool-view/tool-execution.js +7 -0
  225. package/dist/modes/interactive/tool-view/tool-execution.js.map +1 -1
  226. package/dist/package-manager-cli.d.ts.map +1 -1
  227. package/dist/package-manager-cli.js +24 -0
  228. package/dist/package-manager-cli.js.map +1 -1
  229. package/dist/utils/ansi.d.ts +8 -0
  230. package/dist/utils/ansi.d.ts.map +1 -1
  231. package/dist/utils/ansi.js +30 -11
  232. package/dist/utils/ansi.js.map +1 -1
  233. package/dist/utils/clipboard.d.ts.map +1 -1
  234. package/dist/utils/clipboard.js +12 -11
  235. package/dist/utils/clipboard.js.map +1 -1
  236. package/dist/utils/image-resize-core.d.ts +12 -0
  237. package/dist/utils/image-resize-core.d.ts.map +1 -1
  238. package/dist/utils/image-resize-core.js +5 -0
  239. package/dist/utils/image-resize-core.js.map +1 -1
  240. package/dist/utils/image-resize-worker.js +3 -2
  241. package/dist/utils/image-resize-worker.js.map +1 -1
  242. package/dist/utils/image-resize.d.ts.map +1 -1
  243. package/dist/utils/image-resize.js +9 -10
  244. package/dist/utils/image-resize.js.map +1 -1
  245. package/dist/utils/syntax-highlight.d.ts.map +1 -1
  246. package/dist/utils/syntax-highlight.js +6 -1
  247. package/dist/utils/syntax-highlight.js.map +1 -1
  248. package/docs/bundled/README.md +1 -1
  249. package/docs/bundled/extensions/provider.md +1 -1
  250. package/docs/bundled/extensions/question.md +1 -1
  251. package/docs/bundled/extensions/search.md +50 -0
  252. package/docs/bundled/extensions/statusline.md +15 -41
  253. package/docs/codemode.md +26 -5
  254. package/docs/docs.json +0 -4
  255. package/docs/environment-variables.md +1 -0
  256. package/docs/extensions.md +6 -2
  257. package/docs/json.md +2 -2
  258. package/docs/llama-cpp.md +8 -1
  259. package/docs/mcp.md +3 -1
  260. package/docs/models.md +4 -1
  261. package/docs/providers.md +17 -0
  262. package/docs/rpc.md +6 -3
  263. package/docs/session-format.md +1 -0
  264. package/docs/settings.md +4 -4
  265. package/docs/terminal-setup.md +14 -0
  266. package/docs/usage.md +19 -5
  267. package/examples/extensions/custom-provider-anthropic/package-lock.json +2 -2
  268. package/examples/extensions/custom-provider-anthropic/package.json +1 -1
  269. package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
  270. package/examples/extensions/gondolin/package-lock.json +2 -2
  271. package/examples/extensions/gondolin/package.json +1 -1
  272. package/examples/extensions/sandbox/package-lock.json +2 -2
  273. package/examples/extensions/sandbox/package.json +1 -1
  274. package/examples/extensions/with-deps/package-lock.json +2 -2
  275. package/examples/extensions/with-deps/package.json +1 -1
  276. package/npm-shrinkwrap.json +54 -54
  277. package/package.json +13 -11
  278. package/dist/bundle/chunks/chunk-57XI7YJH.js +0 -2
  279. package/dist/bundle/chunks/chunk-JI4WGISU.js +0 -2
  280. package/dist/bundle/chunks/chunk-TCQ4HHQD.js +0 -2
  281. package/dist/bundle/chunks/chunk-TXJO4AJ7.js +0 -11
  282. package/dist/bundle/chunks/cloudflare-workers-ai-system-one-OWU5SM6J.js +0 -2
  283. package/dist/bundle/chunks/typesafe-system-one-KYKKNU3E.js +0 -2
  284. package/dist/extensions/web-search/auth.d.ts +0 -12
  285. package/dist/extensions/web-search/auth.d.ts.map +0 -1
  286. package/dist/extensions/web-search/auth.js +0 -90
  287. package/dist/extensions/web-search/auth.js.map +0 -1
  288. package/dist/extensions/web-search/constants.d.ts +0 -13
  289. package/dist/extensions/web-search/constants.d.ts.map +0 -1
  290. package/dist/extensions/web-search/constants.js +0 -26
  291. package/dist/extensions/web-search/constants.js.map +0 -1
  292. package/dist/extensions/web-search/execute.d.ts +0 -9
  293. package/dist/extensions/web-search/execute.d.ts.map +0 -1
  294. package/dist/extensions/web-search/execute.js +0 -96
  295. package/dist/extensions/web-search/execute.js.map +0 -1
  296. package/dist/extensions/web-search/format.d.ts +0 -21
  297. package/dist/extensions/web-search/format.d.ts.map +0 -1
  298. package/dist/extensions/web-search/format.js +0 -117
  299. package/dist/extensions/web-search/format.js.map +0 -1
  300. package/dist/extensions/web-search/index.d.ts +0 -6
  301. package/dist/extensions/web-search/index.d.ts.map +0 -1
  302. package/dist/extensions/web-search/index.js +0 -50
  303. package/dist/extensions/web-search/index.js.map +0 -1
  304. package/dist/extensions/web-search/providers/deepseek.d.ts +0 -13
  305. package/dist/extensions/web-search/providers/deepseek.d.ts.map +0 -1
  306. package/dist/extensions/web-search/providers/deepseek.js +0 -110
  307. package/dist/extensions/web-search/providers/deepseek.js.map +0 -1
  308. package/dist/extensions/web-search/providers/http.d.ts +0 -4
  309. package/dist/extensions/web-search/providers/http.d.ts.map +0 -1
  310. package/dist/extensions/web-search/providers/http.js +0 -42
  311. package/dist/extensions/web-search/providers/http.js.map +0 -1
  312. package/dist/extensions/web-search/providers/minimax.d.ts +0 -12
  313. package/dist/extensions/web-search/providers/minimax.d.ts.map +0 -1
  314. package/dist/extensions/web-search/providers/minimax.js +0 -61
  315. package/dist/extensions/web-search/providers/minimax.js.map +0 -1
  316. package/dist/extensions/web-search/render.d.ts +0 -15
  317. package/dist/extensions/web-search/render.d.ts.map +0 -1
  318. package/dist/extensions/web-search/render.js +0 -142
  319. package/dist/extensions/web-search/render.js.map +0 -1
  320. package/dist/extensions/web-search/results.d.ts +0 -35
  321. package/dist/extensions/web-search/results.d.ts.map +0 -1
  322. package/dist/extensions/web-search/results.js +0 -167
  323. package/dist/extensions/web-search/results.js.map +0 -1
  324. package/dist/extensions/web-search/schema.d.ts +0 -10
  325. package/dist/extensions/web-search/schema.d.ts.map +0 -1
  326. package/dist/extensions/web-search/schema.js +0 -36
  327. package/dist/extensions/web-search/schema.js.map +0 -1
  328. package/dist/extensions/web-search/types.d.ts +0 -51
  329. package/dist/extensions/web-search/types.d.ts.map +0 -1
  330. package/dist/extensions/web-search/types.js +0 -5
  331. package/dist/extensions/web-search/types.js.map +0 -1
  332. package/docs/bundled/extensions/web-search.md +0 -46
@@ -197,8 +197,6 @@ export function createMcpExtension(options = {}) {
197
197
  let projectConfig;
198
198
  /** Registered servers that `mcp.json` overrides, shown in `/mcp`. */
199
199
  let overridden = [];
200
- /** Between session_start and session_shutdown. Registrations before that are read on session_start. */
201
- let sessionActive = false;
202
200
  let autoEnableCodemode = true;
203
201
  /** Whether the "codemode tools unreachable" warning was shown since the session started. */
204
202
  let warnedUnreachable = false;
@@ -206,8 +204,6 @@ export function createMcpExtension(options = {}) {
206
204
  /** Whether a prompt already waited for the startup connections since the session started. */
207
205
  let waitedForStartup = false;
208
206
  const startupWaitMs = options.startupWaitMs ?? DEFAULT_STARTUP_WAIT_MS;
209
- /** Bumped on every session start and shutdown so a runtime load that resolves late is dropped. */
210
- let generation = 0;
211
207
  /** Working directory of the session, for stdio servers. */
212
208
  let sessionCwd = process.cwd();
213
209
  let credentials = options.credentials;
@@ -219,6 +215,23 @@ export function createMcpExtension(options = {}) {
219
215
  ((entry, patch) => updateMcpServerConfig(entry.override ?? entry.source, entry.name, patch, {
220
216
  override: entry.override !== undefined,
221
217
  }));
218
+ /**
219
+ * Lifetime of the current session: aborted on session_shutdown, and before the first session_start
220
+ * (registrations before that are read on session_start). Work captures `session.signal` when it
221
+ * starts and drops late results once it aborted, for example a runtime load that resolves after
222
+ * shutdown. Work that outlives the command that started it also stops on the signal and is
223
+ * registered with `track`, so shutdown can wait for its cleanup.
224
+ */
225
+ let session = new AbortController();
226
+ session.abort();
227
+ /** Work registered with `track`: manager actions opening or closing connections, and sign-ins. */
228
+ const backgroundActions = new Set();
229
+ const track = (work) => {
230
+ const task = work.then(() => undefined, () => undefined);
231
+ backgroundActions.add(task);
232
+ void task.finally(() => backgroundActions.delete(task));
233
+ return work;
234
+ };
222
235
  const listeners = new Set();
223
236
  const emitChange = () => {
224
237
  for (const listener of listeners)
@@ -301,8 +314,22 @@ export function createMcpExtension(options = {}) {
301
314
  exposure: getMcpToolExposure(entry.config, tool.name),
302
315
  namespace,
303
316
  timeoutMs: connection.timeoutMs,
304
- getClient: async () => connection,
305
- readableResources: () => resourceServers().includes(connection),
317
+ getClient: async () => {
318
+ // A prepared call can outlive this definition's connection while the readiness
319
+ // hook waits for a disable/re-enable. Resolve the replacement at execution time.
320
+ const current = findServer(server);
321
+ if (!current || !isEnabled(current))
322
+ throw new Error(`MCP server "${server}" is disabled.`);
323
+ const client = current.connection;
324
+ if (!client)
325
+ throw new Error(`MCP server "${server}" is still starting.`);
326
+ if (getMcpToolExposure(current.entry.config, tool.name) === "hidden" ||
327
+ (client.state === "connected" && !client.tools.some((offered) => offered.name === tool.name))) {
328
+ throw new Error(`MCP tool "${server}/${tool.name}" is no longer available.`);
329
+ }
330
+ return client;
331
+ },
332
+ readableResources: () => resourceServers().some((current) => current.name === server),
306
333
  });
307
334
  definitions.set(definition.name, definition);
308
335
  pi.registerTool(definition);
@@ -434,8 +461,10 @@ export function createMcpExtension(options = {}) {
434
461
  ensureDiscoveryActive(ctx);
435
462
  };
436
463
  /** Create the server's connection, loading the MCP runtime on first use. */
437
- const createConnection = async (server) => {
464
+ const createConnection = async (server, isCurrent) => {
438
465
  const runtime = await loadMcpRuntime();
466
+ if (!isCurrent())
467
+ return undefined;
439
468
  const connection = new runtime.McpServerConnection({
440
469
  entry: server.entry,
441
470
  cwd: sessionCwd,
@@ -443,8 +472,16 @@ export function createMcpExtension(options = {}) {
443
472
  credentials: getCredentials(runtime),
444
473
  providerToken: async (provider) => modelRegistry?.getApiKeyForProvider(provider),
445
474
  log: getServerLog(runtime),
446
- onTools: registerTools,
447
- onChange: onConnectionChange,
475
+ onTools: (connection) => {
476
+ if (isCurrent())
477
+ registerTools(connection);
478
+ },
479
+ onChange: (connection) => {
480
+ if (isCurrent())
481
+ onConnectionChange(connection);
482
+ else
483
+ tokensAtSignIn.delete(connection);
484
+ },
448
485
  });
449
486
  server.connection = connection;
450
487
  emitChange();
@@ -452,37 +489,48 @@ export function createMcpExtension(options = {}) {
452
489
  };
453
490
  /**
454
491
  * 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
492
+ * failures show in its state. It starts after `after`, unless disabled, replaced, or shut down
456
493
  * meanwhile. The returned promise rejects when the MCP runtime cannot be loaded.
457
494
  */
458
- const startConnection = (server, isCurrent, after) => {
495
+ const startConnection = (server, after) => {
496
+ const { signal } = session;
497
+ const attempt = Symbol();
498
+ server.attempt = attempt;
499
+ const isCurrent = () => !signal.aborted && server.attempt === attempt && isEnabled(server) && servers.includes(server);
459
500
  const ready = (async () => {
460
501
  await after;
461
502
  if (!isCurrent())
462
503
  return;
463
- const connection = await createConnection(server);
464
- if (!isCurrent())
504
+ const connection = await createConnection(server, isCurrent);
505
+ if (!connection || !isCurrent())
465
506
  return;
466
507
  await connection.getClient().catch(() => undefined);
467
508
  })();
468
509
  server.ready = ready.catch(() => undefined);
469
510
  return ready;
470
511
  };
471
- /** Wait for servers still connecting, until they settle or `signal` aborts. */
512
+ /** Wait for the latest connection attempts, including ones queued while waiting, or an abort. */
472
513
  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);
514
+ for (;;) {
515
+ const ready = waiting.flatMap((server) => isEnabled(server) && servers.includes(server) && server.ready ? [{ server, ready: server.ready }] : []);
516
+ if (ready.length === 0 || signal?.aborted)
517
+ return;
518
+ let onAbort;
519
+ await Promise.race([
520
+ Promise.all(ready.map((attempt) => attempt.ready)),
521
+ new Promise((resolve) => {
522
+ onAbort = () => resolve();
523
+ signal?.addEventListener("abort", onAbort, { once: true });
524
+ }),
525
+ ]);
526
+ if (onAbort)
527
+ signal?.removeEventListener("abort", onAbort);
528
+ if (signal?.aborted ||
529
+ ready.every((attempt) => !isEnabled(attempt.server) ||
530
+ !servers.includes(attempt.server) ||
531
+ attempt.ready === attempt.server.ready))
532
+ return;
533
+ }
486
534
  };
487
535
  /**
488
536
  * One message for everything that needs the user after startup, or only for `only`, servers
@@ -517,20 +565,23 @@ export function createMcpExtension(options = {}) {
517
565
  server.entry = { ...entry, config: { ...entry.config, ...patch } };
518
566
  return undefined;
519
567
  };
520
- const signIn = async (server, prompt) => {
568
+ /** Sign in, then reconnect. Returns an error message on failure. `cancel` or the session's end stops the sign-in. */
569
+ const signIn = async (server, prompt, cancel) => {
521
570
  const connection = server.connection;
522
571
  const url = connection?.oauthUrl;
523
572
  if (!connection || !url)
524
573
  return `MCP server "${server.entry.name}" does not use OAuth.`;
525
574
  const runtime = await loadMcpRuntime();
575
+ const signal = cancel ? AbortSignal.any([session.signal, cancel]) : session.signal;
526
576
  try {
527
- await runtime.signInMcpServer({
577
+ await track(runtime.signInMcpServer({
528
578
  serverUrl: url,
529
579
  store: getCredentials(runtime).forServer(server.entry.name, url),
530
580
  settings: connection.oauthSettings(),
531
581
  challenge: connection.challenge,
532
582
  prompt,
533
- });
583
+ signal,
584
+ }));
534
585
  }
535
586
  catch (error) {
536
587
  if (error instanceof runtime.McpSignInCancelledError)
@@ -560,8 +611,14 @@ export function createMcpExtension(options = {}) {
560
611
  const connection = server.connection;
561
612
  if (!connection)
562
613
  return `MCP server "${server.entry.name}" is disabled.`;
563
- try {
614
+ const previous = server.ready;
615
+ const ready = (async () => {
616
+ await previous;
564
617
  await connection.reconnect();
618
+ })();
619
+ server.ready = ready.catch(() => undefined);
620
+ try {
621
+ await ready;
565
622
  return undefined;
566
623
  }
567
624
  catch (error) {
@@ -575,13 +632,26 @@ export function createMcpExtension(options = {}) {
575
632
  return failed;
576
633
  if (!enabled) {
577
634
  const connection = server.connection;
635
+ server.attempt = undefined;
578
636
  server.connection = undefined;
637
+ if (connection) {
638
+ // A reconnect may already have detached its old client while awaiting transport
639
+ // shutdown. Closing the connection alone does not wait for that reconnect.
640
+ server.closing = Promise.all([connection.close(), server.ready]).then(() => undefined);
641
+ }
642
+ const closing = server.closing;
579
643
  hideTools(server.entry.name);
580
644
  emitChange();
581
- await connection?.close();
645
+ try {
646
+ await closing;
647
+ }
648
+ finally {
649
+ if (server.closing === closing)
650
+ server.closing = undefined;
651
+ }
582
652
  return undefined;
583
653
  }
584
- await startConnection(server, () => true);
654
+ await startConnection(server, server.closing);
585
655
  return undefined;
586
656
  };
587
657
  const setExposure = (server, exposure) => {
@@ -729,11 +799,13 @@ export function createMcpExtension(options = {}) {
729
799
  return undefined;
730
800
  return setExposure(server, choice);
731
801
  };
732
- /** Sign in with the manager view's sign-in screen, which shows the URL with a copy key. */
802
+ /** Sign in with the manager view's sign-in screen, which shows the URL with a copy key and cancels with Esc. */
733
803
  const signInWithUi = (ui, server) => {
734
804
  const title = `Sign in to ${server.entry.name}`;
805
+ const cancel = new AbortController();
806
+ const status = (message) => ui.status(title, message, () => cancel.abort());
735
807
  let authorizationUrl = "";
736
- ui.status(title, "Contacting the authorization server…");
808
+ status("Contacting the authorization server…");
737
809
  return signIn(server, {
738
810
  showAuthorizationUrl: (url) => {
739
811
  authorizationUrl = url.href;
@@ -741,22 +813,38 @@ export function createMcpExtension(options = {}) {
741
813
  },
742
814
  promptForRedirectUrl: async (signal) => {
743
815
  const value = await ui.redirectUrl(title, authorizationUrl, signal);
744
- ui.status(title, "Connecting…");
816
+ status("Connecting…");
745
817
  return value;
746
818
  },
747
- });
819
+ }, cancel.signal);
820
+ };
821
+ /** Keep the subscribed menu usable while a connection opens or closes. */
822
+ const runInBackground = (ctx, server, operation) => {
823
+ const ready = operation();
824
+ const attempt = server.attempt;
825
+ const { signal } = session;
826
+ const finish = (message) => {
827
+ if (signal.aborted || server.attempt !== attempt || !servers.includes(server))
828
+ return;
829
+ server.message = message;
830
+ ensureDiscoveryActive(ctx);
831
+ emitChange();
832
+ };
833
+ void track(ready.then(finish, (error) => finish(errorMessage(error))));
748
834
  };
749
835
  const runAction = async (ui, ctx, server, action) => {
750
- const { name } = server.entry;
836
+ const { signal } = session;
751
837
  let message;
752
838
  switch (action) {
753
839
  case "signin":
754
840
  message = await signInWithUi(ui, server);
755
841
  break;
756
842
  case "reconnect":
757
- // A failure shows as the connection's state and error.
758
- ui.status(`MCP server ${name}`, "Reconnecting…");
759
- await reconnect(server);
843
+ // Connection state and error already report failures, including required sign-ins.
844
+ runInBackground(ctx, server, async () => {
845
+ await reconnect(server);
846
+ return undefined;
847
+ });
760
848
  break;
761
849
  case "signout":
762
850
  await signOut(server);
@@ -772,11 +860,13 @@ export function createMcpExtension(options = {}) {
772
860
  case "enable-project":
773
861
  case "disable-project": {
774
862
  const enable = action.startsWith("enable");
775
- ui.status(`MCP server ${name}`, enable ? "Connecting…" : "Disconnecting…");
776
- message = await setEnabled(server, enable, action.endsWith("-project"));
863
+ runInBackground(ctx, server, () => setEnabled(server, enable, action.endsWith("-project")));
777
864
  break;
778
865
  }
779
866
  }
867
+ // The session ended meanwhile (for example during a sign-in), which made ctx stale.
868
+ if (signal.aborted)
869
+ return;
780
870
  server.message = message;
781
871
  ensureDiscoveryActive(ctx);
782
872
  emitChange();
@@ -860,6 +950,7 @@ export function createMcpExtension(options = {}) {
860
950
  ctx.ui.notify(`Signing in to MCP server "${name}" requires interactive mode.`, "error");
861
951
  return;
862
952
  }
953
+ const { signal } = session;
863
954
  let failure;
864
955
  if (ctx.mode === "tui") {
865
956
  await showMcpManager(ctx, async (ui) => {
@@ -875,6 +966,9 @@ export function createMcpExtension(options = {}) {
875
966
  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
967
  });
877
968
  }
969
+ // The session ended meanwhile, which cancelled the sign-in and made ctx stale.
970
+ if (signal.aborted)
971
+ return;
878
972
  if (failure) {
879
973
  ctx.ui.notify(failure, failure === "Sign-in cancelled." ? "info" : "error");
880
974
  return;
@@ -891,8 +985,8 @@ export function createMcpExtension(options = {}) {
891
985
  waitedForStartup = false;
892
986
  sessionCwd = ctx.cwd;
893
987
  modelRegistry = ctx.modelRegistry;
894
- const current = ++generation;
895
- sessionActive = true;
988
+ session = new AbortController();
989
+ const { signal } = session;
896
990
  configuredEntries = loaded.servers;
897
991
  const registered = registeredServers();
898
992
  overridden = registered.overridden;
@@ -909,10 +1003,9 @@ export function createMcpExtension(options = {}) {
909
1003
  // The MCP client loads only now, so sessions without servers never pay for it. Waiting one
910
1004
  // event loop turn lets the first render happen before loading and connecting.
911
1005
  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)))
1006
+ pending = Promise.all(enabled.map((server) => startConnection(server, runtime)))
914
1007
  .then(() => {
915
- if (isCurrent())
1008
+ if (!signal.aborted)
916
1009
  reportProblems(ctx);
917
1010
  })
918
1011
  .catch((error) => {
@@ -958,23 +1051,30 @@ export function createMcpExtension(options = {}) {
958
1051
  });
959
1052
  // A codemode script waits for the servers it names, or for every server when it searches or
960
1053
  // 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.
1054
+ // resource tools reach every server, so they wait for all of them. Direct MCP calls wait only
1055
+ // for their own server, including a reconnect still closing its old transport.
962
1056
  pi.on("tool_call", async (event, ctx) => {
963
1057
  const tool = pi.getAllTools().find((candidate) => candidate.name === event.toolName);
964
1058
  if (!tool)
965
1059
  return;
966
- const pendingServers = servers.filter((server) => isEnabled(server) && server.connection?.state !== "connected" && server.ready);
967
- if (pendingServers.length === 0)
1060
+ // Readiness can be pending while the display state is still connected: reconnect first
1061
+ // closes the old transport, then opens a new one. Settled promises return immediately.
1062
+ const readyServers = servers.filter((server) => isEnabled(server) && server.ready);
1063
+ if (readyServers.length === 0)
968
1064
  return;
969
1065
  let waiting = [];
970
1066
  const orchestrator = discoverOrchestrators([tool]);
971
1067
  if (orchestrator.codemode) {
972
1068
  const { code } = event.input;
973
1069
  const source = typeof code === "string" ? code : "";
974
- waiting = pendingServers.filter((server) => scriptNeedsServer(source, server.entry.name));
1070
+ waiting = readyServers.filter((server) => scriptNeedsServer(source, server.entry.name));
975
1071
  }
976
1072
  else if (orchestrator.toolSearch || RESOURCE_TOOL_NAMES.has(tool.name)) {
977
- waiting = pendingServers;
1073
+ waiting = readyServers;
1074
+ }
1075
+ else {
1076
+ const owner = toolOwners.get(event.toolName)?.split("\0", 1)[0];
1077
+ waiting = readyServers.filter((server) => server.entry.name === owner);
978
1078
  }
979
1079
  await waitForServers(waiting, ctx.signal);
980
1080
  });
@@ -985,9 +1085,9 @@ export function createMcpExtension(options = {}) {
985
1085
  });
986
1086
  // Servers registered or unregistered during the session connect or disconnect right away.
987
1087
  pi.on("mcp_servers_change", async (_event, ctx) => {
988
- if (!sessionActive)
1088
+ const { signal } = session;
1089
+ if (signal.aborted)
989
1090
  return;
990
- const current = generation;
991
1091
  const registered = registeredServers();
992
1092
  overridden = registered.overridden;
993
1093
  const next = new Map(registered.servers.map((server) => [server.entry.name, server]));
@@ -1003,11 +1103,11 @@ export function createMcpExtension(options = {}) {
1003
1103
  ensureDiscoveryActive(ctx);
1004
1104
  await Promise.all(removed.map((server) => server.connection?.close()));
1005
1105
  const connecting = added.filter(isEnabled);
1006
- if (current !== generation || connecting.length === 0)
1106
+ if (signal.aborted || connecting.length === 0)
1007
1107
  return;
1008
1108
  try {
1009
- await Promise.all(connecting.map((server) => startConnection(server, () => current === generation)));
1010
- if (current !== generation) {
1109
+ await Promise.all(connecting.map((server) => startConnection(server)));
1110
+ if (signal.aborted) {
1011
1111
  await Promise.all(connecting.map((server) => server.connection?.close()));
1012
1112
  return;
1013
1113
  }
@@ -1016,17 +1116,16 @@ export function createMcpExtension(options = {}) {
1016
1116
  ctx.ui.notify(`MCP failed to load: ${errorMessage(error)}`, "error");
1017
1117
  return;
1018
1118
  }
1019
- if (current !== generation)
1119
+ if (signal.aborted)
1020
1120
  return;
1021
1121
  reportProblems(ctx, connecting);
1022
1122
  });
1023
1123
  pi.on("session_shutdown", async () => {
1024
- sessionActive = false;
1025
- generation++;
1124
+ session.abort();
1026
1125
  const closing = connections();
1027
1126
  servers = [];
1028
1127
  emitChange();
1029
- await Promise.all(closing.map((connection) => connection.close()));
1128
+ await Promise.all([...backgroundActions, ...closing.map((connection) => connection.close())]);
1030
1129
  });
1031
1130
  pi.registerCommand("mcp", {
1032
1131
  description: "Manage MCP servers: sign in, reconnect, enable or disable, and change exposure",
@@ -1052,19 +1151,21 @@ export function createMcpExtension(options = {}) {
1052
1151
  return items.length > 0 ? items : null;
1053
1152
  },
1054
1153
  handler: async (args, ctx) => {
1055
- await pending;
1056
1154
  const [action, name, ...extra] = args.trim().split(/\s+/).filter(Boolean);
1057
1155
  if (action === undefined) {
1058
1156
  if (ctx.mode === "tui")
1059
1157
  await showMcpManager(ctx, (ui) => manage(ui, ctx));
1060
- else
1158
+ else {
1159
+ await pending;
1061
1160
  ctx.ui.notify(formatStatus(), "info");
1161
+ }
1062
1162
  return;
1063
1163
  }
1064
1164
  if (extra.length > 0) {
1065
1165
  ctx.ui.notify(MCP_USAGE, "warning");
1066
1166
  return;
1067
1167
  }
1168
+ await pending;
1068
1169
  switch (action) {
1069
1170
  case "login": {
1070
1171
  const server = await pickServer(name, ctx, oauthPick);