@prestyj/cli 5.9.0 → 5.11.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (675) hide show
  1. package/README.md +4 -5
  2. package/assets/skills/evidence-led-ui/SKILL.md +1 -1
  3. package/dist/app-sidecar-auth-broadcast.test.d.ts +2 -0
  4. package/dist/app-sidecar-auth-broadcast.test.d.ts.map +1 -0
  5. package/dist/app-sidecar-auth-broadcast.test.js +282 -0
  6. package/dist/app-sidecar-auth-broadcast.test.js.map +1 -0
  7. package/dist/app-sidecar-sessions.d.ts +5 -2
  8. package/dist/app-sidecar-sessions.d.ts.map +1 -1
  9. package/dist/app-sidecar-sessions.js +34 -8
  10. package/dist/app-sidecar-sessions.js.map +1 -1
  11. package/dist/app-sidecar-sessions.test.js +95 -0
  12. package/dist/app-sidecar-sessions.test.js.map +1 -1
  13. package/dist/app-sidecar.js +871 -142
  14. package/dist/app-sidecar.js.map +1 -1
  15. package/dist/chat-agents/general.test.js +5 -3
  16. package/dist/chat-agents/general.test.js.map +1 -1
  17. package/dist/chat-agents/memory.d.ts.map +1 -1
  18. package/dist/chat-agents/memory.js +14 -5
  19. package/dist/chat-agents/memory.js.map +1 -1
  20. package/dist/chat-agents/memory.test.js +11 -1
  21. package/dist/chat-agents/memory.test.js.map +1 -1
  22. package/dist/chat-agents/shared.js +1 -1
  23. package/dist/chat-agents/shared.js.map +1 -1
  24. package/dist/chat-agents/specialists.test.js +3 -2
  25. package/dist/chat-agents/specialists.test.js.map +1 -1
  26. package/dist/cli/command-routing.d.ts +1 -1
  27. package/dist/cli/command-routing.d.ts.map +1 -1
  28. package/dist/cli/command-routing.js +1 -0
  29. package/dist/cli/command-routing.js.map +1 -1
  30. package/dist/cli/command-routing.test.js +1 -0
  31. package/dist/cli/command-routing.test.js.map +1 -1
  32. package/dist/cli.d.ts.map +1 -1
  33. package/dist/cli.js +183 -51
  34. package/dist/cli.js.map +1 -1
  35. package/dist/config.d.ts +16 -0
  36. package/dist/config.d.ts.map +1 -1
  37. package/dist/config.js +51 -2
  38. package/dist/config.js.map +1 -1
  39. package/dist/config.test.js +71 -2
  40. package/dist/config.test.js.map +1 -1
  41. package/dist/core/agent-mcp-passthrough.test.d.ts +2 -0
  42. package/dist/core/agent-mcp-passthrough.test.d.ts.map +1 -0
  43. package/dist/core/agent-mcp-passthrough.test.js +61 -0
  44. package/dist/core/agent-mcp-passthrough.test.js.map +1 -0
  45. package/dist/core/agent-notifications.d.ts +62 -0
  46. package/dist/core/agent-notifications.d.ts.map +1 -0
  47. package/dist/core/agent-notifications.js +92 -0
  48. package/dist/core/agent-notifications.js.map +1 -0
  49. package/dist/core/agent-notifications.test.d.ts +2 -0
  50. package/dist/core/agent-notifications.test.d.ts.map +1 -0
  51. package/dist/core/agent-notifications.test.js +97 -0
  52. package/dist/core/agent-notifications.test.js.map +1 -0
  53. package/dist/core/agent-session-add-dir.test.d.ts +2 -0
  54. package/dist/core/agent-session-add-dir.test.d.ts.map +1 -0
  55. package/dist/core/agent-session-add-dir.test.js +110 -0
  56. package/dist/core/agent-session-add-dir.test.js.map +1 -0
  57. package/dist/core/agent-session-checkpoint-flush.test.d.ts +2 -0
  58. package/dist/core/agent-session-checkpoint-flush.test.d.ts.map +1 -0
  59. package/dist/core/agent-session-checkpoint-flush.test.js +201 -0
  60. package/dist/core/agent-session-checkpoint-flush.test.js.map +1 -0
  61. package/dist/core/agent-session-compaction.test.js +327 -13
  62. package/dist/core/agent-session-compaction.test.js.map +1 -1
  63. package/dist/core/agent-session-crash-durability.test.d.ts +2 -0
  64. package/dist/core/agent-session-crash-durability.test.d.ts.map +1 -0
  65. package/dist/core/agent-session-crash-durability.test.js +102 -0
  66. package/dist/core/agent-session-crash-durability.test.js.map +1 -0
  67. package/dist/core/agent-session-marker-anchors.test.d.ts +2 -0
  68. package/dist/core/agent-session-marker-anchors.test.d.ts.map +1 -0
  69. package/dist/core/agent-session-marker-anchors.test.js +326 -0
  70. package/dist/core/agent-session-marker-anchors.test.js.map +1 -0
  71. package/dist/core/agent-session-memory-tail.test.js +4 -7
  72. package/dist/core/agent-session-memory-tail.test.js.map +1 -1
  73. package/dist/core/agent-session-model-switch.test.d.ts +2 -0
  74. package/dist/core/agent-session-model-switch.test.d.ts.map +1 -0
  75. package/dist/core/agent-session-model-switch.test.js +161 -0
  76. package/dist/core/agent-session-model-switch.test.js.map +1 -0
  77. package/dist/core/agent-session-notifications.test.d.ts +2 -0
  78. package/dist/core/agent-session-notifications.test.d.ts.map +1 -0
  79. package/dist/core/agent-session-notifications.test.js +114 -0
  80. package/dist/core/agent-session-notifications.test.js.map +1 -0
  81. package/dist/core/agent-session-process-gate.test.d.ts +2 -0
  82. package/dist/core/agent-session-process-gate.test.d.ts.map +1 -0
  83. package/dist/core/agent-session-process-gate.test.js +92 -0
  84. package/dist/core/agent-session-process-gate.test.js.map +1 -0
  85. package/dist/core/agent-session-queue.test.js +69 -7
  86. package/dist/core/agent-session-queue.test.js.map +1 -1
  87. package/dist/core/agent-session-review-coverage.test.js +80 -23
  88. package/dist/core/agent-session-review-coverage.test.js.map +1 -1
  89. package/dist/core/agent-session-slash-restore.test.d.ts +2 -0
  90. package/dist/core/agent-session-slash-restore.test.d.ts.map +1 -0
  91. package/dist/core/agent-session-slash-restore.test.js +121 -0
  92. package/dist/core/agent-session-slash-restore.test.js.map +1 -0
  93. package/dist/core/agent-session-subagent-policy.test.js +7 -3
  94. package/dist/core/agent-session-subagent-policy.test.js.map +1 -1
  95. package/dist/core/agent-session.d.ts +256 -10
  96. package/dist/core/agent-session.d.ts.map +1 -1
  97. package/dist/core/agent-session.js +1071 -219
  98. package/dist/core/agent-session.js.map +1 -1
  99. package/dist/core/agent-tools-allowlist.test.js +5 -3
  100. package/dist/core/agent-tools-allowlist.test.js.map +1 -1
  101. package/dist/core/agents.d.ts +11 -0
  102. package/dist/core/agents.d.ts.map +1 -1
  103. package/dist/core/agents.js +21 -0
  104. package/dist/core/agents.js.map +1 -1
  105. package/dist/core/agents.test.d.ts +2 -0
  106. package/dist/core/agents.test.d.ts.map +1 -0
  107. package/dist/core/agents.test.js +67 -0
  108. package/dist/core/agents.test.js.map +1 -0
  109. package/dist/core/auth-providers.js +1 -1
  110. package/dist/core/auth-providers.js.map +1 -1
  111. package/dist/core/compaction/active-context.test.js +21 -0
  112. package/dist/core/compaction/active-context.test.js.map +1 -1
  113. package/dist/core/compaction/compactor.d.ts +108 -8
  114. package/dist/core/compaction/compactor.d.ts.map +1 -1
  115. package/dist/core/compaction/compactor.js +423 -119
  116. package/dist/core/compaction/compactor.js.map +1 -1
  117. package/dist/core/compaction/compactor.test.js +361 -9
  118. package/dist/core/compaction/compactor.test.js.map +1 -1
  119. package/dist/core/compaction/policy.d.ts +17 -0
  120. package/dist/core/compaction/policy.d.ts.map +1 -0
  121. package/dist/core/compaction/policy.js +22 -0
  122. package/dist/core/compaction/policy.js.map +1 -0
  123. package/dist/core/compaction/policy.test.d.ts +2 -0
  124. package/dist/core/compaction/policy.test.d.ts.map +1 -0
  125. package/dist/core/compaction/policy.test.js +35 -0
  126. package/dist/core/compaction/policy.test.js.map +1 -0
  127. package/dist/core/compaction/query-aware-selector.d.ts +33 -0
  128. package/dist/core/compaction/query-aware-selector.d.ts.map +1 -0
  129. package/dist/core/compaction/query-aware-selector.js +202 -0
  130. package/dist/core/compaction/query-aware-selector.js.map +1 -0
  131. package/dist/core/compaction/query-aware-selector.test.d.ts +2 -0
  132. package/dist/core/compaction/query-aware-selector.test.d.ts.map +1 -0
  133. package/dist/core/compaction/query-aware-selector.test.js +96 -0
  134. package/dist/core/compaction/query-aware-selector.test.js.map +1 -0
  135. package/dist/core/compaction/token-estimator.test.js +1 -1
  136. package/dist/core/compaction/token-estimator.test.js.map +1 -1
  137. package/dist/core/compaction/tool-result-pruner.d.ts +24 -11
  138. package/dist/core/compaction/tool-result-pruner.d.ts.map +1 -1
  139. package/dist/core/compaction/tool-result-pruner.js +98 -26
  140. package/dist/core/compaction/tool-result-pruner.js.map +1 -1
  141. package/dist/core/compaction/tool-result-pruner.test.js +178 -6
  142. package/dist/core/compaction/tool-result-pruner.test.js.map +1 -1
  143. package/dist/core/encode-cwd.d.ts +17 -0
  144. package/dist/core/encode-cwd.d.ts.map +1 -1
  145. package/dist/core/encode-cwd.js +20 -7
  146. package/dist/core/encode-cwd.js.map +1 -1
  147. package/dist/core/encode-cwd.test.js +20 -1
  148. package/dist/core/encode-cwd.test.js.map +1 -1
  149. package/dist/core/event-bus.d.ts +23 -0
  150. package/dist/core/event-bus.d.ts.map +1 -1
  151. package/dist/core/event-bus.js +10 -0
  152. package/dist/core/event-bus.js.map +1 -1
  153. package/dist/core/extensions/loader.d.ts.map +1 -1
  154. package/dist/core/extensions/loader.js +28 -8
  155. package/dist/core/extensions/loader.js.map +1 -1
  156. package/dist/core/extensions/plugin-bundles.d.ts +23 -0
  157. package/dist/core/extensions/plugin-bundles.d.ts.map +1 -0
  158. package/dist/core/extensions/plugin-bundles.js +228 -0
  159. package/dist/core/extensions/plugin-bundles.js.map +1 -0
  160. package/dist/core/extensions/plugin-bundles.test.d.ts +2 -0
  161. package/dist/core/extensions/plugin-bundles.test.d.ts.map +1 -0
  162. package/dist/core/extensions/plugin-bundles.test.js +110 -0
  163. package/dist/core/extensions/plugin-bundles.test.js.map +1 -0
  164. package/dist/core/foreign-session-import.d.ts +120 -0
  165. package/dist/core/foreign-session-import.d.ts.map +1 -0
  166. package/dist/core/foreign-session-import.js +598 -0
  167. package/dist/core/foreign-session-import.js.map +1 -0
  168. package/dist/core/foreign-session-import.test.d.ts +2 -0
  169. package/dist/core/foreign-session-import.test.d.ts.map +1 -0
  170. package/dist/core/foreign-session-import.test.js +220 -0
  171. package/dist/core/foreign-session-import.test.js.map +1 -0
  172. package/dist/core/foreign-transcript-blocks.d.ts +51 -0
  173. package/dist/core/foreign-transcript-blocks.d.ts.map +1 -0
  174. package/dist/core/foreign-transcript-blocks.js +151 -0
  175. package/dist/core/foreign-transcript-blocks.js.map +1 -0
  176. package/dist/core/ideal-review.d.ts +20 -1
  177. package/dist/core/ideal-review.d.ts.map +1 -1
  178. package/dist/core/ideal-review.js +43 -3
  179. package/dist/core/ideal-review.js.map +1 -1
  180. package/dist/core/ideal-review.test.js +106 -5
  181. package/dist/core/ideal-review.test.js.map +1 -1
  182. package/dist/core/local-endpoint-store.d.ts +50 -0
  183. package/dist/core/local-endpoint-store.d.ts.map +1 -0
  184. package/dist/core/local-endpoint-store.js +201 -0
  185. package/dist/core/local-endpoint-store.js.map +1 -0
  186. package/dist/core/local-endpoint-store.test.d.ts +2 -0
  187. package/dist/core/local-endpoint-store.test.d.ts.map +1 -0
  188. package/dist/core/local-endpoint-store.test.js +131 -0
  189. package/dist/core/local-endpoint-store.test.js.map +1 -0
  190. package/dist/core/loop-breaker.d.ts.map +1 -1
  191. package/dist/core/loop-breaker.js +1 -0
  192. package/dist/core/loop-breaker.js.map +1 -1
  193. package/dist/core/lsp/client.d.ts +65 -0
  194. package/dist/core/lsp/client.d.ts.map +1 -1
  195. package/dist/core/lsp/client.js +197 -14
  196. package/dist/core/lsp/client.js.map +1 -1
  197. package/dist/core/lsp/jsonrpc.d.ts +38 -1
  198. package/dist/core/lsp/jsonrpc.d.ts.map +1 -1
  199. package/dist/core/lsp/jsonrpc.js +13 -1
  200. package/dist/core/lsp/jsonrpc.js.map +1 -1
  201. package/dist/core/lsp/manager.d.ts +47 -9
  202. package/dist/core/lsp/manager.d.ts.map +1 -1
  203. package/dist/core/lsp/manager.js +107 -59
  204. package/dist/core/lsp/manager.js.map +1 -1
  205. package/dist/core/lsp/manager.test.js +50 -1
  206. package/dist/core/lsp/manager.test.js.map +1 -1
  207. package/dist/core/lsp/pool.d.ts +113 -0
  208. package/dist/core/lsp/pool.d.ts.map +1 -0
  209. package/dist/core/lsp/pool.js +255 -0
  210. package/dist/core/lsp/pool.js.map +1 -0
  211. package/dist/core/lsp/pool.test.d.ts +2 -0
  212. package/dist/core/lsp/pool.test.d.ts.map +1 -0
  213. package/dist/core/lsp/pool.test.js +286 -0
  214. package/dist/core/lsp/pool.test.js.map +1 -0
  215. package/dist/core/lsp/servers.d.ts.map +1 -1
  216. package/dist/core/lsp/servers.js +43 -3
  217. package/dist/core/lsp/servers.js.map +1 -1
  218. package/dist/core/lsp/servers.test.d.ts +2 -0
  219. package/dist/core/lsp/servers.test.d.ts.map +1 -0
  220. package/dist/core/lsp/servers.test.js +67 -0
  221. package/dist/core/lsp/servers.test.js.map +1 -0
  222. package/dist/core/lsp/test-support.d.ts +18 -0
  223. package/dist/core/lsp/test-support.d.ts.map +1 -0
  224. package/dist/core/lsp/test-support.js +27 -0
  225. package/dist/core/lsp/test-support.js.map +1 -0
  226. package/dist/core/lsp/uri.test.d.ts +2 -0
  227. package/dist/core/lsp/uri.test.d.ts.map +1 -0
  228. package/dist/core/lsp/uri.test.js +56 -0
  229. package/dist/core/lsp/uri.test.js.map +1 -0
  230. package/dist/core/lsp/windows.test.d.ts +2 -0
  231. package/dist/core/lsp/windows.test.d.ts.map +1 -0
  232. package/dist/core/lsp/windows.test.js +239 -0
  233. package/dist/core/lsp/windows.test.js.map +1 -0
  234. package/dist/core/mcp/catalog-cache.d.ts +63 -0
  235. package/dist/core/mcp/catalog-cache.d.ts.map +1 -0
  236. package/dist/core/mcp/catalog-cache.js +163 -0
  237. package/dist/core/mcp/catalog-cache.js.map +1 -0
  238. package/dist/core/mcp/catalog-cache.test.d.ts +2 -0
  239. package/dist/core/mcp/catalog-cache.test.d.ts.map +1 -0
  240. package/dist/core/mcp/catalog-cache.test.js +99 -0
  241. package/dist/core/mcp/catalog-cache.test.js.map +1 -0
  242. package/dist/core/mcp/client-session-recovery.test.d.ts +2 -0
  243. package/dist/core/mcp/client-session-recovery.test.d.ts.map +1 -0
  244. package/dist/core/mcp/client-session-recovery.test.js +231 -0
  245. package/dist/core/mcp/client-session-recovery.test.js.map +1 -0
  246. package/dist/core/mcp/client.d.ts +158 -0
  247. package/dist/core/mcp/client.d.ts.map +1 -1
  248. package/dist/core/mcp/client.js +476 -35
  249. package/dist/core/mcp/client.js.map +1 -1
  250. package/dist/core/mcp/elicitation-bridge.d.ts +41 -0
  251. package/dist/core/mcp/elicitation-bridge.d.ts.map +1 -0
  252. package/dist/core/mcp/elicitation-bridge.js +52 -0
  253. package/dist/core/mcp/elicitation-bridge.js.map +1 -0
  254. package/dist/core/mcp/elicitation.test.d.ts +2 -0
  255. package/dist/core/mcp/elicitation.test.d.ts.map +1 -0
  256. package/dist/core/mcp/elicitation.test.js +158 -0
  257. package/dist/core/mcp/elicitation.test.js.map +1 -0
  258. package/dist/core/mcp/index.d.ts +5 -1
  259. package/dist/core/mcp/index.d.ts.map +1 -1
  260. package/dist/core/mcp/index.js +2 -0
  261. package/dist/core/mcp/index.js.map +1 -1
  262. package/dist/core/mcp/legacy-negotiation.test.d.ts +2 -0
  263. package/dist/core/mcp/legacy-negotiation.test.d.ts.map +1 -0
  264. package/dist/core/mcp/legacy-negotiation.test.js +80 -0
  265. package/dist/core/mcp/legacy-negotiation.test.js.map +1 -0
  266. package/dist/core/mcp/oauth-provider.d.ts +1 -2
  267. package/dist/core/mcp/oauth-provider.d.ts.map +1 -1
  268. package/dist/core/mcp/oauth-provider.js +6 -2
  269. package/dist/core/mcp/oauth-provider.js.map +1 -1
  270. package/dist/core/mcp/oauth-store.d.ts +1 -1
  271. package/dist/core/mcp/oauth-store.d.ts.map +1 -1
  272. package/dist/core/mcp/oauth-store.js.map +1 -1
  273. package/dist/core/mcp/resolve-stdio.d.ts +35 -0
  274. package/dist/core/mcp/resolve-stdio.d.ts.map +1 -1
  275. package/dist/core/mcp/resolve-stdio.js +80 -1
  276. package/dist/core/mcp/resolve-stdio.js.map +1 -1
  277. package/dist/core/mcp/resolve-stdio.test.js +99 -4
  278. package/dist/core/mcp/resolve-stdio.test.js.map +1 -1
  279. package/dist/core/mcp/session-elicitation-wiring.test.d.ts +2 -0
  280. package/dist/core/mcp/session-elicitation-wiring.test.d.ts.map +1 -0
  281. package/dist/core/mcp/session-elicitation-wiring.test.js +138 -0
  282. package/dist/core/mcp/session-elicitation-wiring.test.js.map +1 -0
  283. package/dist/core/mcp/shared-pool.d.ts +158 -0
  284. package/dist/core/mcp/shared-pool.d.ts.map +1 -0
  285. package/dist/core/mcp/shared-pool.js +235 -0
  286. package/dist/core/mcp/shared-pool.js.map +1 -0
  287. package/dist/core/mcp/shared-pool.test.d.ts +2 -0
  288. package/dist/core/mcp/shared-pool.test.d.ts.map +1 -0
  289. package/dist/core/mcp/shared-pool.test.js +425 -0
  290. package/dist/core/mcp/shared-pool.test.js.map +1 -0
  291. package/dist/core/mcp/types.d.ts +12 -0
  292. package/dist/core/mcp/types.d.ts.map +1 -1
  293. package/dist/core/mcp/when-connected.test.d.ts +2 -0
  294. package/dist/core/mcp/when-connected.test.d.ts.map +1 -0
  295. package/dist/core/mcp/when-connected.test.js +46 -0
  296. package/dist/core/mcp/when-connected.test.js.map +1 -0
  297. package/dist/core/network-guard.d.ts +47 -0
  298. package/dist/core/network-guard.d.ts.map +1 -0
  299. package/dist/core/network-guard.js +208 -0
  300. package/dist/core/network-guard.js.map +1 -0
  301. package/dist/core/network-guard.test.d.ts +2 -0
  302. package/dist/core/network-guard.test.d.ts.map +1 -0
  303. package/dist/core/network-guard.test.js +72 -0
  304. package/dist/core/network-guard.test.js.map +1 -0
  305. package/dist/core/nolan-context.d.ts.map +1 -1
  306. package/dist/core/nolan-context.js +8 -0
  307. package/dist/core/nolan-context.js.map +1 -1
  308. package/dist/core/nolan-context.test.js +40 -0
  309. package/dist/core/nolan-context.test.js.map +1 -1
  310. package/dist/core/nolan-prompt.js +3 -0
  311. package/dist/core/nolan-prompt.js.map +1 -1
  312. package/dist/core/nolan-prompt.test.js +5 -0
  313. package/dist/core/nolan-prompt.test.js.map +1 -1
  314. package/dist/core/persistent-shell.d.ts +4 -1
  315. package/dist/core/persistent-shell.d.ts.map +1 -1
  316. package/dist/core/persistent-shell.js +21 -4
  317. package/dist/core/persistent-shell.js.map +1 -1
  318. package/dist/core/process-gate.d.ts +45 -0
  319. package/dist/core/process-gate.d.ts.map +1 -0
  320. package/dist/core/process-gate.js +79 -0
  321. package/dist/core/process-gate.js.map +1 -0
  322. package/dist/core/process-gate.test.d.ts +2 -0
  323. package/dist/core/process-gate.test.d.ts.map +1 -0
  324. package/dist/core/process-gate.test.js +87 -0
  325. package/dist/core/process-gate.test.js.map +1 -0
  326. package/dist/core/process-manager-dev-server-repro.test.js +34 -12
  327. package/dist/core/process-manager-dev-server-repro.test.js.map +1 -1
  328. package/dist/core/process-manager-notifications.test.d.ts +2 -0
  329. package/dist/core/process-manager-notifications.test.d.ts.map +1 -0
  330. package/dist/core/process-manager-notifications.test.js +217 -0
  331. package/dist/core/process-manager-notifications.test.js.map +1 -0
  332. package/dist/core/process-manager.d.ts +51 -2
  333. package/dist/core/process-manager.d.ts.map +1 -1
  334. package/dist/core/process-manager.js +212 -15
  335. package/dist/core/process-manager.js.map +1 -1
  336. package/dist/core/project-discovery.d.ts +38 -6
  337. package/dist/core/project-discovery.d.ts.map +1 -1
  338. package/dist/core/project-discovery.js +327 -40
  339. package/dist/core/project-discovery.js.map +1 -1
  340. package/dist/core/project-discovery.test.js +226 -1
  341. package/dist/core/project-discovery.test.js.map +1 -1
  342. package/dist/core/prompt-commands.d.ts.map +1 -1
  343. package/dist/core/prompt-commands.js +89 -156
  344. package/dist/core/prompt-commands.js.map +1 -1
  345. package/dist/core/prompt-commands.test.js +4 -10
  346. package/dist/core/prompt-commands.test.js.map +1 -1
  347. package/dist/core/radio.test.js +4 -1
  348. package/dist/core/radio.test.js.map +1 -1
  349. package/dist/core/regrounding.d.ts.map +1 -1
  350. package/dist/core/regrounding.js +1 -0
  351. package/dist/core/regrounding.js.map +1 -1
  352. package/dist/core/run-claim.d.ts +37 -0
  353. package/dist/core/run-claim.d.ts.map +1 -0
  354. package/dist/core/run-claim.js +46 -0
  355. package/dist/core/run-claim.js.map +1 -0
  356. package/dist/core/run-claim.test.d.ts +2 -0
  357. package/dist/core/run-claim.test.d.ts.map +1 -0
  358. package/dist/core/run-claim.test.js +107 -0
  359. package/dist/core/run-claim.test.js.map +1 -0
  360. package/dist/core/run-journal.test.d.ts +2 -0
  361. package/dist/core/run-journal.test.d.ts.map +1 -0
  362. package/dist/core/run-journal.test.js +195 -0
  363. package/dist/core/run-journal.test.js.map +1 -0
  364. package/dist/core/run-lifecycle.d.ts +22 -3
  365. package/dist/core/run-lifecycle.d.ts.map +1 -1
  366. package/dist/core/run-lifecycle.js +12 -3
  367. package/dist/core/run-lifecycle.js.map +1 -1
  368. package/dist/core/runtime-mode.d.ts +2 -0
  369. package/dist/core/runtime-mode.d.ts.map +1 -1
  370. package/dist/core/runtime-mode.js +4 -0
  371. package/dist/core/runtime-mode.js.map +1 -1
  372. package/dist/core/sandbox-domains.d.ts +14 -0
  373. package/dist/core/sandbox-domains.d.ts.map +1 -0
  374. package/dist/core/sandbox-domains.js +76 -0
  375. package/dist/core/sandbox-domains.js.map +1 -0
  376. package/dist/core/sandbox-feedback.d.ts +22 -0
  377. package/dist/core/sandbox-feedback.d.ts.map +1 -0
  378. package/dist/core/sandbox-feedback.js +69 -0
  379. package/dist/core/sandbox-feedback.js.map +1 -0
  380. package/dist/core/sandbox-feedback.test.d.ts +2 -0
  381. package/dist/core/sandbox-feedback.test.d.ts.map +1 -0
  382. package/dist/core/sandbox-feedback.test.js +32 -0
  383. package/dist/core/sandbox-feedback.test.js.map +1 -0
  384. package/dist/core/sandbox.d.ts +91 -0
  385. package/dist/core/sandbox.d.ts.map +1 -0
  386. package/dist/core/sandbox.js +254 -0
  387. package/dist/core/sandbox.js.map +1 -0
  388. package/dist/core/sandbox.test.d.ts +2 -0
  389. package/dist/core/sandbox.test.d.ts.map +1 -0
  390. package/dist/core/sandbox.test.js +157 -0
  391. package/dist/core/sandbox.test.js.map +1 -0
  392. package/dist/core/session-compaction.d.ts +6 -0
  393. package/dist/core/session-compaction.d.ts.map +1 -1
  394. package/dist/core/session-compaction.js +11 -1
  395. package/dist/core/session-compaction.js.map +1 -1
  396. package/dist/core/session-compaction.test.js +18 -1
  397. package/dist/core/session-compaction.test.js.map +1 -1
  398. package/dist/core/session-export.d.ts +98 -0
  399. package/dist/core/session-export.d.ts.map +1 -0
  400. package/dist/core/session-export.js +364 -0
  401. package/dist/core/session-export.js.map +1 -0
  402. package/dist/core/session-export.test.d.ts +2 -0
  403. package/dist/core/session-export.test.d.ts.map +1 -0
  404. package/dist/core/session-export.test.js +353 -0
  405. package/dist/core/session-export.test.js.map +1 -0
  406. package/dist/core/session-history.d.ts +95 -6
  407. package/dist/core/session-history.d.ts.map +1 -1
  408. package/dist/core/session-history.js +261 -17
  409. package/dist/core/session-history.js.map +1 -1
  410. package/dist/core/session-history.test.js +173 -2
  411. package/dist/core/session-history.test.js.map +1 -1
  412. package/dist/core/session-manager.d.ts +223 -6
  413. package/dist/core/session-manager.d.ts.map +1 -1
  414. package/dist/core/session-manager.js +515 -26
  415. package/dist/core/session-manager.js.map +1 -1
  416. package/dist/core/session-manager.test.js +147 -3
  417. package/dist/core/session-manager.test.js.map +1 -1
  418. package/dist/core/session-notification-visibility.test.d.ts +2 -0
  419. package/dist/core/session-notification-visibility.test.d.ts.map +1 -0
  420. package/dist/core/session-notification-visibility.test.js +113 -0
  421. package/dist/core/session-notification-visibility.test.js.map +1 -0
  422. package/dist/core/session-preview.d.ts +5 -4
  423. package/dist/core/session-preview.d.ts.map +1 -1
  424. package/dist/core/session-preview.js +12 -5
  425. package/dist/core/session-preview.js.map +1 -1
  426. package/dist/core/session-restore-display.test.js +25 -0
  427. package/dist/core/session-restore-display.test.js.map +1 -1
  428. package/dist/core/session-storage.d.ts.map +1 -1
  429. package/dist/core/session-storage.js +64 -4
  430. package/dist/core/session-storage.js.map +1 -1
  431. package/dist/core/session-storage.test.js +10 -2
  432. package/dist/core/session-storage.test.js.map +1 -1
  433. package/dist/core/settings-manager.d.ts +13 -2
  434. package/dist/core/settings-manager.d.ts.map +1 -1
  435. package/dist/core/settings-manager.js +36 -0
  436. package/dist/core/settings-manager.js.map +1 -1
  437. package/dist/core/setup-history.d.ts +0 -6
  438. package/dist/core/setup-history.d.ts.map +1 -1
  439. package/dist/core/setup-history.js +2 -18
  440. package/dist/core/setup-history.js.map +1 -1
  441. package/dist/core/setup-history.test.js +11 -26
  442. package/dist/core/setup-history.test.js.map +1 -1
  443. package/dist/core/skills-routing.test.js +3 -1
  444. package/dist/core/skills-routing.test.js.map +1 -1
  445. package/dist/core/slash-commands.d.ts +18 -0
  446. package/dist/core/slash-commands.d.ts.map +1 -1
  447. package/dist/core/slash-commands.js +42 -10
  448. package/dist/core/slash-commands.js.map +1 -1
  449. package/dist/core/slash-commands.test.d.ts +2 -0
  450. package/dist/core/slash-commands.test.d.ts.map +1 -0
  451. package/dist/core/slash-commands.test.js +59 -0
  452. package/dist/core/slash-commands.test.js.map +1 -0
  453. package/dist/core/speed-benchmark.test.js +9 -3
  454. package/dist/core/speed-benchmark.test.js.map +1 -1
  455. package/dist/core/steering.d.ts +12 -0
  456. package/dist/core/steering.d.ts.map +1 -1
  457. package/dist/core/steering.js +16 -0
  458. package/dist/core/steering.js.map +1 -1
  459. package/dist/core/subagent-manager.d.ts +14 -1
  460. package/dist/core/subagent-manager.d.ts.map +1 -1
  461. package/dist/core/subagent-manager.js +48 -1
  462. package/dist/core/subagent-manager.js.map +1 -1
  463. package/dist/core/subagent-manager.test.js +43 -7
  464. package/dist/core/subagent-manager.test.js.map +1 -1
  465. package/dist/core/subagent-store.test.js +14 -2
  466. package/dist/core/subagent-store.test.js.map +1 -1
  467. package/dist/core/verification-evidence.d.ts +17 -0
  468. package/dist/core/verification-evidence.d.ts.map +1 -0
  469. package/dist/core/verification-evidence.js +283 -0
  470. package/dist/core/verification-evidence.js.map +1 -0
  471. package/dist/core/verification-evidence.test.d.ts +2 -0
  472. package/dist/core/verification-evidence.test.d.ts.map +1 -0
  473. package/dist/core/verification-evidence.test.js +103 -0
  474. package/dist/core/verification-evidence.test.js.map +1 -0
  475. package/dist/core/workspace-guard.d.ts +2 -0
  476. package/dist/core/workspace-guard.d.ts.map +1 -1
  477. package/dist/core/workspace-guard.js +4 -1
  478. package/dist/core/workspace-guard.js.map +1 -1
  479. package/dist/core/workspace-guard.test.js +21 -0
  480. package/dist/core/workspace-guard.test.js.map +1 -1
  481. package/dist/interactive.d.ts.map +1 -1
  482. package/dist/interactive.js +17 -3
  483. package/dist/interactive.js.map +1 -1
  484. package/dist/modes/acp-mode.d.ts +122 -0
  485. package/dist/modes/acp-mode.d.ts.map +1 -0
  486. package/dist/modes/acp-mode.js +1366 -0
  487. package/dist/modes/acp-mode.js.map +1 -0
  488. package/dist/modes/acp-mode.test.d.ts +2 -0
  489. package/dist/modes/acp-mode.test.d.ts.map +1 -0
  490. package/dist/modes/acp-mode.test.js +1065 -0
  491. package/dist/modes/acp-mode.test.js.map +1 -0
  492. package/dist/modes/index.d.ts +1 -0
  493. package/dist/modes/index.d.ts.map +1 -1
  494. package/dist/modes/index.js +1 -0
  495. package/dist/modes/index.js.map +1 -1
  496. package/dist/modes/json-mode.d.ts +35 -0
  497. package/dist/modes/json-mode.d.ts.map +1 -1
  498. package/dist/modes/json-mode.js +38 -0
  499. package/dist/modes/json-mode.js.map +1 -1
  500. package/dist/modes/json-mode.test.d.ts +2 -0
  501. package/dist/modes/json-mode.test.d.ts.map +1 -0
  502. package/dist/modes/json-mode.test.js +84 -0
  503. package/dist/modes/json-mode.test.js.map +1 -0
  504. package/dist/modes/subagent-worker-mode.d.ts +5 -0
  505. package/dist/modes/subagent-worker-mode.d.ts.map +1 -1
  506. package/dist/modes/subagent-worker-mode.js +91 -11
  507. package/dist/modes/subagent-worker-mode.js.map +1 -1
  508. package/dist/modes/subagent-worker-mode.test.d.ts +2 -0
  509. package/dist/modes/subagent-worker-mode.test.d.ts.map +1 -0
  510. package/dist/modes/subagent-worker-mode.test.js +52 -0
  511. package/dist/modes/subagent-worker-mode.test.js.map +1 -0
  512. package/dist/session.d.ts +29 -0
  513. package/dist/session.d.ts.map +1 -1
  514. package/dist/session.js +41 -0
  515. package/dist/session.js.map +1 -1
  516. package/dist/system-prompt.d.ts +11 -1
  517. package/dist/system-prompt.d.ts.map +1 -1
  518. package/dist/system-prompt.js +39 -18
  519. package/dist/system-prompt.js.map +1 -1
  520. package/dist/system-prompt.test.js +33 -17
  521. package/dist/system-prompt.test.js.map +1 -1
  522. package/dist/test-support/fake-home.d.ts +20 -0
  523. package/dist/test-support/fake-home.d.ts.map +1 -0
  524. package/dist/test-support/fake-home.js +37 -0
  525. package/dist/test-support/fake-home.js.map +1 -0
  526. package/dist/tools/bash.d.ts +3 -1
  527. package/dist/tools/bash.d.ts.map +1 -1
  528. package/dist/tools/bash.js +70 -14
  529. package/dist/tools/bash.js.map +1 -1
  530. package/dist/tools/bash.test.js +122 -7
  531. package/dist/tools/bash.test.js.map +1 -1
  532. package/dist/tools/edit-robustness.test.js +3 -1
  533. package/dist/tools/edit-robustness.test.js.map +1 -1
  534. package/dist/tools/find.d.ts.map +1 -1
  535. package/dist/tools/find.js +4 -1
  536. package/dist/tools/find.js.map +1 -1
  537. package/dist/tools/goals.d.ts +2 -2
  538. package/dist/tools/grep.d.ts +3 -1
  539. package/dist/tools/grep.d.ts.map +1 -1
  540. package/dist/tools/grep.js +137 -12
  541. package/dist/tools/grep.js.map +1 -1
  542. package/dist/tools/grep.test.js +53 -0
  543. package/dist/tools/grep.test.js.map +1 -1
  544. package/dist/tools/index.d.ts +19 -2
  545. package/dist/tools/index.d.ts.map +1 -1
  546. package/dist/tools/index.js +22 -19
  547. package/dist/tools/index.js.map +1 -1
  548. package/dist/tools/index.test.d.ts +2 -0
  549. package/dist/tools/index.test.d.ts.map +1 -0
  550. package/dist/tools/index.test.js +55 -0
  551. package/dist/tools/index.test.js.map +1 -0
  552. package/dist/tools/overflow.test.js +4 -7
  553. package/dist/tools/overflow.test.js.map +1 -1
  554. package/dist/tools/path-utils.d.ts +15 -0
  555. package/dist/tools/path-utils.d.ts.map +1 -1
  556. package/dist/tools/path-utils.js +17 -0
  557. package/dist/tools/path-utils.js.map +1 -1
  558. package/dist/tools/path-utils.test.js +7 -2
  559. package/dist/tools/path-utils.test.js.map +1 -1
  560. package/dist/tools/prompt-hints.js +1 -1
  561. package/dist/tools/prompt-hints.js.map +1 -1
  562. package/dist/tools/read-only-bash.d.ts +3 -0
  563. package/dist/tools/read-only-bash.d.ts.map +1 -1
  564. package/dist/tools/read-only-bash.js +7 -9
  565. package/dist/tools/read-only-bash.js.map +1 -1
  566. package/dist/tools/search-code.d.ts.map +1 -1
  567. package/dist/tools/search-code.js +6 -4
  568. package/dist/tools/search-code.js.map +1 -1
  569. package/dist/tools/subagent-control.d.ts.map +1 -1
  570. package/dist/tools/subagent-control.js +6 -2
  571. package/dist/tools/subagent-control.js.map +1 -1
  572. package/dist/tools/subagent-shared.d.ts +6 -0
  573. package/dist/tools/subagent-shared.d.ts.map +1 -1
  574. package/dist/tools/subagent-shared.js +6 -0
  575. package/dist/tools/subagent-shared.js.map +1 -1
  576. package/dist/tools/subagent.d.ts +1 -1
  577. package/dist/tools/subagent.d.ts.map +1 -1
  578. package/dist/tools/subagent.js +51 -8
  579. package/dist/tools/subagent.js.map +1 -1
  580. package/dist/tools/subagent.test.js +65 -3
  581. package/dist/tools/subagent.test.js.map +1 -1
  582. package/dist/tools/task-output.d.ts.map +1 -1
  583. package/dist/tools/task-output.js +3 -1
  584. package/dist/tools/task-output.js.map +1 -1
  585. package/dist/tools/tool-search.d.ts +12 -1
  586. package/dist/tools/tool-search.d.ts.map +1 -1
  587. package/dist/tools/tool-search.js +22 -3
  588. package/dist/tools/tool-search.js.map +1 -1
  589. package/dist/tools/tool-search.test.d.ts +2 -0
  590. package/dist/tools/tool-search.test.d.ts.map +1 -0
  591. package/dist/tools/tool-search.test.js +69 -0
  592. package/dist/tools/tool-search.test.js.map +1 -0
  593. package/dist/tools/web-fetch.d.ts +3 -2
  594. package/dist/tools/web-fetch.d.ts.map +1 -1
  595. package/dist/tools/web-fetch.js +22 -8
  596. package/dist/tools/web-fetch.js.map +1 -1
  597. package/dist/tools/web-fetch.test.js +34 -0
  598. package/dist/tools/web-fetch.test.js.map +1 -1
  599. package/dist/tools/web-search.d.ts +2 -1
  600. package/dist/tools/web-search.d.ts.map +1 -1
  601. package/dist/tools/web-search.js +21 -5
  602. package/dist/tools/web-search.js.map +1 -1
  603. package/dist/types.d.ts +7 -0
  604. package/dist/types.d.ts.map +1 -1
  605. package/dist/ui/App.d.ts.map +1 -1
  606. package/dist/ui/App.js +32 -81
  607. package/dist/ui/App.js.map +1 -1
  608. package/dist/ui/app-items.d.ts +1 -12
  609. package/dist/ui/app-items.d.ts.map +1 -1
  610. package/dist/ui/app-items.js.map +1 -1
  611. package/dist/ui/components/Footer.d.ts +1 -1
  612. package/dist/ui/components/Footer.js +2 -2
  613. package/dist/ui/components/Footer.js.map +1 -1
  614. package/dist/ui/hooks/useAgentLoop.d.ts.map +1 -1
  615. package/dist/ui/hooks/useAgentLoop.js +18 -4
  616. package/dist/ui/hooks/useAgentLoop.js.map +1 -1
  617. package/dist/ui/hooks/usePixelFixFlow.d.ts +1 -2
  618. package/dist/ui/hooks/usePixelFixFlow.d.ts.map +1 -1
  619. package/dist/ui/hooks/usePixelFixFlow.js +2 -5
  620. package/dist/ui/hooks/usePixelFixFlow.js.map +1 -1
  621. package/dist/ui/login.js +1 -1
  622. package/dist/ui/login.js.map +1 -1
  623. package/dist/ui/terminal-history-status-renderers.d.ts +1 -2
  624. package/dist/ui/terminal-history-status-renderers.d.ts.map +1 -1
  625. package/dist/ui/terminal-history-status-renderers.js +2 -15
  626. package/dist/ui/terminal-history-status-renderers.js.map +1 -1
  627. package/dist/ui/terminal-history.d.ts.map +1 -1
  628. package/dist/ui/terminal-history.js +2 -4
  629. package/dist/ui/terminal-history.js.map +1 -1
  630. package/dist/ui/thinking-level-cycle.test.js +8 -8
  631. package/dist/ui/thinking-level-cycle.test.js.map +1 -1
  632. package/dist/ui/transcript/MiscRows.d.ts +1 -4
  633. package/dist/ui/transcript/MiscRows.d.ts.map +1 -1
  634. package/dist/ui/transcript/MiscRows.js +2 -7
  635. package/dist/ui/transcript/MiscRows.js.map +1 -1
  636. package/dist/ui/transcript/TranscriptRenderer.d.ts.map +1 -1
  637. package/dist/ui/transcript/TranscriptRenderer.js +1 -3
  638. package/dist/ui/transcript/TranscriptRenderer.js.map +1 -1
  639. package/dist/ui/transcript/presentation.d.ts +1 -9
  640. package/dist/ui/transcript/presentation.d.ts.map +1 -1
  641. package/dist/ui/transcript/presentation.js +0 -9
  642. package/dist/ui/transcript/presentation.js.map +1 -1
  643. package/dist/ui/transcript/spacing.d.ts +2 -2
  644. package/dist/ui/transcript/spacing.d.ts.map +1 -1
  645. package/dist/ui/transcript/spacing.js +0 -1
  646. package/dist/ui/transcript/spacing.js.map +1 -1
  647. package/dist/ui/transcript/spacing.test.js +1 -3
  648. package/dist/ui/transcript/spacing.test.js.map +1 -1
  649. package/dist/ui/tui-history-parity.test.js +2 -9
  650. package/dist/ui/tui-history-parity.test.js.map +1 -1
  651. package/dist/utils/github.d.ts +20 -0
  652. package/dist/utils/github.d.ts.map +1 -0
  653. package/dist/utils/github.js +65 -0
  654. package/dist/utils/github.js.map +1 -0
  655. package/dist/utils/github.test.d.ts +2 -0
  656. package/dist/utils/github.test.d.ts.map +1 -0
  657. package/dist/utils/github.test.js +23 -0
  658. package/dist/utils/github.test.js.map +1 -0
  659. package/dist/utils/image.d.ts +26 -3
  660. package/dist/utils/image.d.ts.map +1 -1
  661. package/dist/utils/image.js +83 -14
  662. package/dist/utils/image.js.map +1 -1
  663. package/dist/utils/image.test.d.ts +2 -0
  664. package/dist/utils/image.test.d.ts.map +1 -0
  665. package/dist/utils/image.test.js +139 -0
  666. package/dist/utils/image.test.js.map +1 -0
  667. package/dist/utils/process.d.ts +26 -3
  668. package/dist/utils/process.d.ts.map +1 -1
  669. package/dist/utils/process.js +68 -10
  670. package/dist/utils/process.js.map +1 -1
  671. package/dist/utils/process.test.d.ts +2 -0
  672. package/dist/utils/process.test.d.ts.map +1 -0
  673. package/dist/utils/process.test.js +42 -0
  674. package/dist/utils/process.test.js.map +1 -0
  675. package/package.json +6 -5
@@ -1,8 +1,5 @@
1
- import { Client } from "@modelcontextprotocol/sdk/client/index.js";
2
- import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js";
3
- import { SSEClientTransport } from "@modelcontextprotocol/sdk/client/sse.js";
4
- import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js";
5
- import { UnauthorizedError } from "@modelcontextprotocol/sdk/client/auth.js";
1
+ import { StdioClientTransport } from "@modelcontextprotocol/client/stdio";
2
+ import { Client, OAuthError, OAuthErrorCode, ProtocolError, SdkError, SdkErrorCode, SdkHttpError, StreamableHTTPClientTransport, SSEClientTransport, UnauthorizedError, } from "@modelcontextprotocol/client";
6
3
  import { z } from "zod";
7
4
  import http from "node:http";
8
5
  import os from "node:os";
@@ -11,8 +8,220 @@ import { McpOAuthProvider, MCP_OAUTH_CALLBACK_PORT, MCP_OAUTH_CALLBACK_PATH, } f
11
8
  import { McpOAuthStore } from "./oauth-store.js";
12
9
  import { isLocalhost, alternateLoopback, isNetworkError } from "./loopback.js";
13
10
  import { resolveStdioCommand } from "./resolve-stdio.js";
11
+ import { McpCatalogCache } from "./catalog-cache.js";
12
+ import { isShareableServer, sharedMcpPool, } from "./shared-pool.js";
14
13
  export class MCPClientManager {
15
14
  servers = [];
15
+ /**
16
+ * Per-server connection settlement, so a caller holding a cached-only tool
17
+ * can wait for the live client instead of failing or hanging forever.
18
+ */
19
+ connections = new Map();
20
+ /**
21
+ * In-flight session rebuilds, keyed by server name. N tool calls to the same
22
+ * server all 404 at once when its session expires; without coalescing each
23
+ * would spawn its own reconnect and they would race to replace each other in
24
+ * `this.servers`. Sharing one promise means exactly one reconnect per outage.
25
+ */
26
+ reconnecting = new Map();
27
+ /**
28
+ * Claims on process-wide shared connections, keyed by server name. Held so
29
+ * `dispose` can hand them back: the pooled child only exits once the LAST
30
+ * manager holding it releases, so leaking a claim here would pin the process
31
+ * for the daemon's lifetime — the exact bug sharing is meant to fix.
32
+ */
33
+ sharedHandles = new Map();
34
+ catalogCache;
35
+ /**
36
+ * Opt into the 2026-07-28 revision. Off by default: `mode: "auto"` probes with
37
+ * `server/discover` before falling back to `initialize`, and a legacy stdio
38
+ * server that ignores pre-`initialize` requests pays the full probe timeout.
39
+ */
40
+ modernProtocol;
41
+ /**
42
+ * Host callback for server-initiated `elicitation/create`. Absent means we
43
+ * declare no elicitation capability at all — which is protocol-legal and is
44
+ * how the CLI runs, since it has nowhere to render the form.
45
+ */
46
+ onElicit;
47
+ /**
48
+ * Pool backing `shared: true` servers. Defaults to the daemon-wide singleton;
49
+ * injectable so tests can exercise sharing without touching global state.
50
+ */
51
+ pool;
52
+ /**
53
+ * Fired when a connected server's transport closes on its own — a crashed or
54
+ * exited child, not our own `dispose`. The pool uses it to drop a dead
55
+ * connection so the next session rebuilds instead of inheriting a corpse.
56
+ */
57
+ onServerClosed;
58
+ /** Set while `dispose` runs, so our own teardown is not reported as a death. */
59
+ disposing = false;
60
+ constructor(opts = {}) {
61
+ this.catalogCache = opts.catalogCache ?? new McpCatalogCache();
62
+ this.modernProtocol = opts.modernProtocol ?? false;
63
+ this.onElicit = opts.onElicit;
64
+ this.pool = opts.sharedPool ?? sharedMcpPool;
65
+ this.onServerClosed = opts.onServerClosed;
66
+ }
67
+ /**
68
+ * Build a `Client` for one server, declaring elicitation support and wiring
69
+ * the handler when the host can actually prompt the user.
70
+ *
71
+ * Form mode only. URL mode would have us open a browser tab in the middle of
72
+ * a tool call with no user gesture behind it — the SDK rejects URL-mode
73
+ * requests for us when the `url` capability is undeclared.
74
+ */
75
+ createClient(serverName, negotiate) {
76
+ const handler = this.onElicit;
77
+ if (!handler)
78
+ return new Client({ name: "ezcoder", version: "1.0.0" }, negotiate);
79
+ const client = new Client({ name: "ezcoder", version: "1.0.0" }, { ...negotiate, capabilities: { elicitation: { form: {} } } });
80
+ client.setRequestHandler("elicitation/create", async (request) => {
81
+ const params = request.params;
82
+ if (params.mode === "url") {
83
+ // Unreachable while `url` stays undeclared, but a server that ignores
84
+ // capabilities must get a clean decline rather than a thrown handler.
85
+ return { action: "decline" };
86
+ }
87
+ return handler({
88
+ server: serverName,
89
+ message: params.message,
90
+ requestedSchema: params.requestedSchema,
91
+ });
92
+ });
93
+ return client;
94
+ }
95
+ /**
96
+ * Version-negotiation options for a real (non-probe) connect. `probe()` is
97
+ * spawn-per-invocation and deliberately never negotiates: a legacy stdio
98
+ * server that ignores the discovery request would stall it for the whole
99
+ * probe timeout, turning "validate this server" into a 30s hang.
100
+ *
101
+ * The probe timeout is transport-aware because the SDK's timeout VERDICT is:
102
+ *
103
+ * - **stdio** — silence on a local pipe means a legacy server, and the SDK
104
+ * falls back to `initialize`. The probe runs on a disposable sibling
105
+ * process, so the fallback is clean. Waiting the full connect timeout to
106
+ * reach a conclusion we can draw in seconds is pure dead time, so cap it
107
+ * short.
108
+ * - **HTTP** — silence means an outage, and the SDK REJECTS the connect
109
+ * rather than falling back. A short timeout would therefore turn a slow
110
+ * cold start into a hard connection failure, so inherit the full connect
111
+ * timeout and let the normal timeout handling deal with a real outage.
112
+ */
113
+ negotiationOptions(transport) {
114
+ if (!this.modernProtocol)
115
+ return {};
116
+ return {
117
+ versionNegotiation: {
118
+ mode: "auto",
119
+ ...(transport === "stdio" ? { probe: { timeoutMs: STDIO_PROBE_TIMEOUT_MS } } : {}),
120
+ },
121
+ };
122
+ }
123
+ /**
124
+ * Claim the pooled connection for a shared server and adopt its tools.
125
+ *
126
+ * Shaped like `connectServer` (resolve tools / throw on failure) so the
127
+ * caller's `allSettled` handling is identical for both kinds. The pool
128
+ * reports failure in-band, so it is rethrown here with the message the pool
129
+ * already formatted.
130
+ */
131
+ async connectShared(config) {
132
+ const handle = await this.pool.acquire(config,
133
+ // The pooled connection is just another manager with sharing switched
134
+ // off, so it takes the normal connect path instead of recursing into the
135
+ // pool. Its elicit handler is the pool's dispatcher, NOT this session's:
136
+ // the connection is shared, so each request has to be routed to whichever
137
+ // session actually provoked it.
138
+ (opts) => {
139
+ const manager = new MCPClientManager({
140
+ catalogCache: opts.catalogCache,
141
+ modernProtocol: opts.modernProtocol,
142
+ onElicit: opts.onElicit,
143
+ sharedPool: this.pool,
144
+ // Let the pool retire this connection if its server exits.
145
+ onServerClosed: opts.onClosed,
146
+ });
147
+ return {
148
+ connect: async (target) => {
149
+ const [result] = await manager.connectAllDetailed([{ ...target, shared: false }]);
150
+ return (result ?? {
151
+ name: target.name,
152
+ ok: false,
153
+ toolCount: 0,
154
+ tools: [],
155
+ error: "connection produced no result",
156
+ });
157
+ },
158
+ dispose: () => manager.dispose(),
159
+ };
160
+ }, {
161
+ catalogCache: this.catalogCache,
162
+ modernProtocol: this.modernProtocol,
163
+ onElicit: this.onElicit,
164
+ });
165
+ if (!handle.result.ok) {
166
+ // Nothing was claimed on a failed connect, but releasing is idempotent
167
+ // and keeps this path honest if that ever changes.
168
+ await handle.release();
169
+ throw new Error(handle.result.error ?? "connection failed");
170
+ }
171
+ this.sharedHandles.set(config.name, handle);
172
+ // Wrap each pooled tool so a call from THIS session is attributable while
173
+ // it runs. The pool needs that to answer "which window asked?" when the
174
+ // server elicits mid-call; without it a shared server could only ever
175
+ // cancel its prompts.
176
+ return handle.result.tools.map((tool) => ({
177
+ ...tool,
178
+ execute: async (args, context) => {
179
+ const endCall = handle.beginCall();
180
+ try {
181
+ return await tool.execute(args, context);
182
+ }
183
+ finally {
184
+ endCall();
185
+ }
186
+ },
187
+ }));
188
+ }
189
+ /** Get-or-create the settlement record for one server name. */
190
+ connectionSlot(name) {
191
+ const existing = this.connections.get(name);
192
+ if (existing)
193
+ return existing;
194
+ let settle;
195
+ const promise = new Promise((resolve) => {
196
+ settle = resolve;
197
+ });
198
+ const slot = { promise, settle };
199
+ this.connections.set(name, slot);
200
+ return slot;
201
+ }
202
+ /**
203
+ * Resolve once a server's connection attempt has settled. Returns `ok:false`
204
+ * with the failure reason when that server could not connect, and times out
205
+ * rather than hanging when no attempt is ever made (e.g. a server that was
206
+ * removed from the config since the catalog cache was written).
207
+ */
208
+ async whenConnected(name, timeoutMs = 30_000) {
209
+ if (this.servers.some((server) => server.name === name))
210
+ return { ok: true };
211
+ const slot = this.connectionSlot(name);
212
+ let timer;
213
+ const timeout = new Promise((resolve) => {
214
+ timer = setTimeout(() => resolve({ ok: false, error: `timed out after ${timeoutMs}ms` }), timeoutMs);
215
+ timer.unref?.();
216
+ });
217
+ try {
218
+ return await Promise.race([slot.promise, timeout]);
219
+ }
220
+ finally {
221
+ if (timer)
222
+ clearTimeout(timer);
223
+ }
224
+ }
16
225
  async connectAll(configs) {
17
226
  const results = await this.connectAllDetailed(configs);
18
227
  return results.flatMap((r) => r.tools);
@@ -21,12 +230,25 @@ export class MCPClientManager {
21
230
  * Connect every enabled server and return one result per server (success →
22
231
  * ok + toolCount; failure → ok:false with a human-readable error string).
23
232
  * Keeps successfully connected servers in `this.servers`.
233
+ *
234
+ * Shareable servers — stdio, unless opted out with `shared: false` — are not
235
+ * connected here at all: they are claimed from the process-wide pool, so every
236
+ * session in the daemon multiplexes over one child process instead of spawning
237
+ * its own. The split is invisible to callers — results and tools come back in
238
+ * the same shape, `whenConnected` settles for both kinds, and `dispose`
239
+ * releases the pooled claims — so sharing applies wherever a manager is used
240
+ * (sessions, CLI, subagents) without each call site opting in.
24
241
  */
25
242
  async connectAllDetailed(configs) {
26
243
  const enabled = configs.filter((c) => c.enabled !== false);
27
244
  if (enabled.length === 0)
28
245
  return [];
29
- const settled = await Promise.allSettled(enabled.map((c) => this.connectServer(c)));
246
+ // Claim a settlement slot for every server up front, so a `whenConnected`
247
+ // caller that arrives before a slow server's turn still waits on the right
248
+ // promise instead of creating a second one.
249
+ for (const config of enabled)
250
+ this.connectionSlot(config.name);
251
+ const settled = await Promise.allSettled(enabled.map((c) => (isShareableServer(c) ? this.connectShared(c) : this.connectServer(c))));
30
252
  const results = settled.map((result, i) => {
31
253
  const name = enabled[i].name;
32
254
  if (result.status === "fulfilled") {
@@ -37,6 +259,10 @@ export class MCPClientManager {
37
259
  log("WARN", "mcp", `Failed to connect to MCP server "${name}"`, { error });
38
260
  return { name, ok: false, toolCount: 0, tools: [], error, requiresAuth };
39
261
  });
262
+ // Release anyone waiting on a cached-only tool from these servers.
263
+ for (const result of results) {
264
+ this.connectionSlot(result.name).settle(result.ok ? { ok: true } : { ok: false, error: result.error ?? "connection failed" });
265
+ }
40
266
  const connected = results.filter((r) => r.ok).length;
41
267
  const toolCount = results.reduce((sum, r) => sum + r.toolCount, 0);
42
268
  log("INFO", "mcp", `Connected ${connected} MCP server(s), ${toolCount} tool(s)`);
@@ -49,7 +275,7 @@ export class MCPClientManager {
49
275
  */
50
276
  async probe(config) {
51
277
  try {
52
- const tools = await this.connectServer(config);
278
+ const tools = await this.connectServer(config, { probe: true });
53
279
  const server = this.servers.find((s) => s.name === config.name);
54
280
  if (server) {
55
281
  this.servers = this.servers.filter((s) => s !== server);
@@ -88,6 +314,9 @@ export class MCPClientManager {
88
314
  // Fresh PKCE/state for this attempt so a previous half-finished login can't
89
315
  // poison the exchange.
90
316
  await store.patch(config.name, { codeVerifier: undefined, state: undefined });
317
+ // The whole callback query string, not just `code`: v2's finishAuth reads
318
+ // `iss` from it and validates the issuer (RFC 9207) before redeeming the
319
+ // code, which is the defense against an authorization-server mix-up.
91
320
  let codeResolve;
92
321
  let codeReject;
93
322
  const codePromise = new Promise((resolve, reject) => {
@@ -129,7 +358,7 @@ export class MCPClientManager {
129
358
  return;
130
359
  }
131
360
  res.end("<html><body><h1>Login successful!</h1><p>You can close this tab and return to EZ Coder.</p></body></html>");
132
- codeResolve?.(code);
361
+ codeResolve?.(reqUrl.searchParams);
133
362
  });
134
363
  try {
135
364
  await new Promise((resolve, reject) => {
@@ -167,9 +396,9 @@ export class MCPClientManager {
167
396
  if (!isUnauthorized(err))
168
397
  throw err;
169
398
  }
170
- const code = await codePromise;
399
+ const callbackParams = await codePromise;
171
400
  // Exchange the code for tokens (persisted via provider.saveTokens).
172
- await loginTransport.finishAuth(code);
401
+ await loginTransport.finishAuth(callbackParams);
173
402
  await loginClient.close().catch(() => { });
174
403
  // Verify the authorized connection on a fresh transport + list tools.
175
404
  const verifyTransport = new StreamableHTTPClientTransport(url, {
@@ -192,8 +421,20 @@ export class MCPClientManager {
192
421
  await store.patch(config.name, { codeVerifier: undefined, state: undefined });
193
422
  }
194
423
  }
195
- async connectServer(config) {
424
+ async connectServer(config, opts = {}) {
196
425
  const timeout = config.timeout ?? 30_000;
426
+ // `command` is what actually selects the stdio path further down.
427
+ const negotiate = opts.probe
428
+ ? {}
429
+ : this.negotiationOptions(config.command ? "stdio" : "http");
430
+ // A server we already know speaks the 2025 handshake skips the discovery
431
+ // probe entirely. Only the legacy verdict is reusable from an era string:
432
+ // adopting a 'modern' verdict needs the full DiscoverResult, so those still
433
+ // probe (a modern server answers immediately, so that costs nothing).
434
+ const prior = "versionNegotiation" in negotiate && (await this.cachedEra(config)) === "legacy"
435
+ ? { kind: "legacy" }
436
+ : undefined;
437
+ const connectOptions = { timeout, ...(prior ? { prior } : {}) };
197
438
  let client;
198
439
  let transport;
199
440
  if (config.command) {
@@ -226,9 +467,9 @@ export class MCPClientManager {
226
467
  transport.stderr?.on("data", (chunk) => {
227
468
  stderrChunks.push(typeof chunk === "string" ? chunk : chunk.toString("utf8"));
228
469
  });
229
- client = new Client({ name: "ezcoder", version: "1.0.0" });
470
+ client = this.createClient(config.name, negotiate);
230
471
  try {
231
- await client.connect(transport, { timeout });
472
+ await client.connect(transport, connectOptions);
232
473
  }
233
474
  catch (err) {
234
475
  const stderr = stderrChunks.join("").slice(-4000);
@@ -244,7 +485,7 @@ export class MCPClientManager {
244
485
  const url = new URL(config.url);
245
486
  const isLocal = isLocalhost(url);
246
487
  try {
247
- const r = await this.connectHttp(url, config, isLocal, timeout);
488
+ const r = await this.connectHttp(url, config, isLocal, negotiate, connectOptions);
248
489
  client = r.client;
249
490
  transport = r.transport;
250
491
  }
@@ -261,13 +502,40 @@ export class MCPClientManager {
261
502
  });
262
503
  const altUrl = new URL(url);
263
504
  altUrl.hostname = alt;
264
- const r = await this.connectHttp(altUrl, config, isLocal, timeout);
505
+ const r = await this.connectHttp(altUrl, config, isLocal, negotiate, connectOptions);
265
506
  client = r.client;
266
507
  transport = r.transport;
267
508
  }
268
509
  }
269
- this.servers.push({ name: config.name, client, transport, lastCallTime: 0 });
510
+ this.servers.push({ name: config.name, client, transport, lastCallTime: 0, config });
511
+ // Report an unexpected close. A stdio child that crashes has no recovery
512
+ // path (`canRecoverSession` excludes stdio deliberately: respawning one
513
+ // mid-call would be a surprise), so the only safe response is to let the
514
+ // owner drop this connection and rebuild on the next use. That matters most
515
+ // for a POOLED connection, where a corpse would otherwise be handed to every
516
+ // session in the daemon, including ones that connect later.
517
+ client.onclose = () => {
518
+ if (this.disposing)
519
+ return;
520
+ log("WARN", "mcp", `MCP server "${config.name}" closed unexpectedly`);
521
+ this.onServerClosed?.(config.name);
522
+ };
270
523
  const { tools } = await client.listTools(undefined, { timeout });
524
+ // Persist the live tool list so the NEXT cold start can answer tool_search
525
+ // before this server has finished connecting. Awaited (a small serialized
526
+ // JSON write) so the entry is on disk before the connect is reported done —
527
+ // otherwise a session that starts right after would still see a cold cache.
528
+ // A failed write must never fail the connect.
529
+ try {
530
+ await this.catalogCache.save(config, tools.map((tool) => ({
531
+ name: `mcp__${config.name}__${tool.name}`,
532
+ description: tool.description ?? "",
533
+ rawInputSchema: tool.inputSchema,
534
+ })), this.negotiatedEra(client));
535
+ }
536
+ catch {
537
+ // Cache is an optimization; a connected server is still fully usable.
538
+ }
271
539
  return tools.map((tool) => {
272
540
  const toolName = `mcp__${config.name}__${tool.name}`;
273
541
  return {
@@ -275,7 +543,7 @@ export class MCPClientManager {
275
543
  description: tool.description ?? "",
276
544
  parameters: z.record(z.string(), z.unknown()),
277
545
  rawInputSchema: tool.inputSchema,
278
- execute: async (args) => {
546
+ execute: async (args, context) => {
279
547
  const server = this.servers.find((s) => s.name === config.name);
280
548
  if (server) {
281
549
  const elapsed = Date.now() - server.lastCallTime;
@@ -285,8 +553,16 @@ export class MCPClientManager {
285
553
  }
286
554
  server.lastCallTime = Date.now();
287
555
  }
288
- try {
289
- const result = await client.callTool({ name: tool.name, arguments: args }, undefined, { timeout: config.timeout ?? 60_000 });
556
+ // Resolve the client from `this.servers` on every attempt rather than
557
+ // closing over the one from connect time: a session rebuild swaps the
558
+ // entry, and a stale capture would keep calling the dead client.
559
+ const liveClient = () => this.servers.find((s) => s.name === config.name)?.client ?? client;
560
+ // The client the attempt actually ran against, so a failure can be
561
+ // attributed to "my client was replaced" vs "the server hung up".
562
+ let attemptClient = liveClient();
563
+ const callOnce = async () => {
564
+ attemptClient = liveClient();
565
+ const result = await attemptClient.callTool({ name: tool.name, arguments: args }, { timeout: config.timeout ?? 60_000 });
290
566
  if (!("content" in result) || !Array.isArray(result.content)) {
291
567
  return "(empty response)";
292
568
  }
@@ -300,8 +576,23 @@ export class MCPClientManager {
300
576
  }
301
577
  }
302
578
  return texts.join("\n") || "(empty response)";
579
+ };
580
+ try {
581
+ return await callOnce();
303
582
  }
304
583
  catch (err) {
584
+ // An expired HTTP session is recoverable exactly once: rebuild the
585
+ // connection and replay the call. A second failure is a real error.
586
+ if (this.canRecoverSession(config, err, attemptClient, context?.signal)) {
587
+ try {
588
+ await this.reconnectServer(config);
589
+ if (!context?.signal?.aborted)
590
+ return await callOnce();
591
+ }
592
+ catch (retryErr) {
593
+ return `MCP tool error: ${formatConnectError(retryErr)}`;
594
+ }
595
+ }
305
596
  const msg = err instanceof Error ? err.message : String(err);
306
597
  if (msg.includes("Too Many R") || msg.includes("429")) {
307
598
  return "Rate limited — too many requests. Wait a moment before searching again.";
@@ -312,6 +603,66 @@ export class MCPClientManager {
312
603
  };
313
604
  });
314
605
  }
606
+ /**
607
+ * Is this failure a recoverable expired HTTP session?
608
+ *
609
+ * Stdio servers are excluded: they have no HTTP session to expire, so a 404
610
+ * from one means something else entirely and respawning the child process
611
+ * mid-call would be a surprise. An already-aborted call is excluded too —
612
+ * reconnecting to replay work the user cancelled resurrects it.
613
+ */
614
+ canRecoverSession(config, err, attemptClient, signal) {
615
+ if (config.command)
616
+ return false;
617
+ if (signal?.aborted)
618
+ return false;
619
+ if (isSessionExpired(err))
620
+ return true;
621
+ // A sibling call that hit the same expired session may already have torn
622
+ // the transport down underneath us, which surfaces as a generic "connection
623
+ // closed" rather than the 404. Recover only when the client we called has
624
+ // genuinely been retired — otherwise this is a real disconnect and a retry
625
+ // would just fail again.
626
+ const current = this.servers.find((s) => s.name === config.name)?.client;
627
+ return current !== attemptClient && this.isConnectionClosed(err);
628
+ }
629
+ /** A local "the transport went away mid-request" failure, as the SDK reports it. */
630
+ isConnectionClosed(reason) {
631
+ return SdkError.isInstance(reason) && reason.code === SdkErrorCode.ConnectionClosed;
632
+ }
633
+ /**
634
+ * Rebuild one server's connection from its stored config, replacing the dead
635
+ * entry in `this.servers`. Concurrent callers share a single rebuild.
636
+ *
637
+ * Rejects if the reconnect itself fails, so the caller reports a real error
638
+ * rather than retrying against a client that was never replaced.
639
+ */
640
+ async reconnectServer(config) {
641
+ const inFlight = this.reconnecting.get(config.name);
642
+ if (inFlight)
643
+ return inFlight;
644
+ const attempt = (async () => {
645
+ log("INFO", "mcp", `MCP session expired for "${config.name}", reconnecting`);
646
+ const dead = this.servers.find((s) => s.name === config.name);
647
+ if (dead) {
648
+ this.servers = this.servers.filter((s) => s !== dead);
649
+ try {
650
+ await dead.client.close();
651
+ }
652
+ catch {
653
+ // The session is already gone server-side; a failed close is expected.
654
+ }
655
+ }
656
+ await this.connectServer(config);
657
+ })();
658
+ this.reconnecting.set(config.name, attempt);
659
+ try {
660
+ await attempt;
661
+ }
662
+ finally {
663
+ this.reconnecting.delete(config.name);
664
+ }
665
+ }
315
666
  /**
316
667
  * Connect a single HTTP (Streamable HTTP or SSE) server and return the live
317
668
  * client + transport. Transport selection:
@@ -322,7 +673,7 @@ export class MCPClientManager {
322
673
  * needs OAuth and attaching it there is dead weight that can misdiagnose a
323
674
  * protocol mismatch as a login requirement.
324
675
  */
325
- async connectHttp(url, config, isLocal, timeout) {
676
+ async connectHttp(url, config, isLocal, negotiate, connectOptions) {
326
677
  const reqInit = config.headers ? { headers: config.headers } : undefined;
327
678
  const authProvider = isLocal ? undefined : new McpOAuthProvider({ serverName: config.name });
328
679
  const sseTransport = () => new SSEClientTransport(url, {
@@ -332,8 +683,8 @@ export class MCPClientManager {
332
683
  });
333
684
  if (config.transport === "sse") {
334
685
  const transport = sseTransport();
335
- const client = new Client({ name: "ezcoder", version: "1.0.0" });
336
- await client.connect(transport, { timeout });
686
+ const client = this.createClient(config.name, negotiate);
687
+ await client.connect(transport, connectOptions);
337
688
  return { client, transport };
338
689
  }
339
690
  try {
@@ -341,8 +692,8 @@ export class MCPClientManager {
341
692
  requestInit: reqInit,
342
693
  authProvider,
343
694
  });
344
- const client = new Client({ name: "ezcoder", version: "1.0.0" });
345
- await client.connect(transport, { timeout });
695
+ const client = this.createClient(config.name, negotiate);
696
+ await client.connect(transport, connectOptions);
346
697
  return { client, transport };
347
698
  }
348
699
  catch (streamableErr) {
@@ -356,12 +707,40 @@ export class MCPClientManager {
356
707
  error: String(streamableErr),
357
708
  });
358
709
  const transport = sseTransport();
359
- const client = new Client({ name: "ezcoder", version: "1.0.0" });
360
- await client.connect(transport, { timeout });
710
+ const client = this.createClient(config.name, negotiate);
711
+ await client.connect(transport, connectOptions);
361
712
  return { client, transport };
362
713
  }
363
714
  }
715
+ /**
716
+ * Protocol era actually negotiated with a server, as the SDK reports it.
717
+ * Undefined before a connect completes; with negotiation off the SDK always
718
+ * settles on `legacy` (the 2025 `initialize` handshake).
719
+ */
720
+ negotiatedEra(client) {
721
+ return client.getProtocolEra() ?? "legacy";
722
+ }
723
+ /** Previously negotiated era for this exact server config, if still cached. */
724
+ async cachedEra(config) {
725
+ try {
726
+ return await this.catalogCache.protocolEraFor(config);
727
+ }
728
+ catch {
729
+ return undefined;
730
+ }
731
+ }
364
732
  async dispose() {
733
+ // Our own teardown closes transports too; flag it so those closes are not
734
+ // reported as unexpected deaths.
735
+ this.disposing = true;
736
+ this.connections.clear();
737
+ this.reconnecting.clear();
738
+ // Hand back pooled claims first. These are references, not connections —
739
+ // the shared child survives if another session still holds it, and exits
740
+ // when this was the last claim.
741
+ const handles = [...this.sharedHandles.values()];
742
+ this.sharedHandles.clear();
743
+ await Promise.all(handles.map((handle) => handle.release()));
365
744
  for (const server of this.servers) {
366
745
  try {
367
746
  await server.client.close();
@@ -374,25 +753,81 @@ export class MCPClientManager {
374
753
  }
375
754
  }
376
755
  /**
377
- * Turn a thrown connection error into a short human-readable string. Surfaces
378
- * the common rate-limit case explicitly; otherwise the underlying message.
756
+ * Turn a thrown connection error into a short human-readable string.
757
+ *
758
+ * v2 splits the old `McpError` into `ProtocolError` (a JSON-RPC error that
759
+ * crossed the wire) and `SdkError` (a purely local failure: timeout, closed
760
+ * connection, HTTP status). Matching the typed classes gives far better wording
761
+ * than sniffing message text, which survives only as the fallback for errors
762
+ * thrown before the SDK's machinery engages (raw fetch failures).
379
763
  */
380
764
  function formatConnectError(reason) {
765
+ if (SdkHttpError.isInstance(reason)) {
766
+ if (reason.status === 429)
767
+ return "Rate limited (429) — try again in a moment.";
768
+ const statusText = reason.statusText ? ` ${reason.statusText}` : "";
769
+ return `Server responded with HTTP ${reason.status}${statusText}.`;
770
+ }
771
+ if (SdkError.isInstance(reason)) {
772
+ if (reason.code === SdkErrorCode.RequestTimeout) {
773
+ return "Timed out waiting for the server to respond.";
774
+ }
775
+ if (reason.code === SdkErrorCode.ConnectionClosed) {
776
+ return "Connection closed before the server finished starting up.";
777
+ }
778
+ return reason.message;
779
+ }
780
+ if (OAuthError.isInstance(reason))
781
+ return `OAuth error (${reason.code}): ${reason.message}`;
782
+ if (ProtocolError.isInstance(reason))
783
+ return reason.message;
381
784
  const msg = reason instanceof Error ? reason.message : String(reason);
382
785
  if (msg.includes("Too Many R") || msg.includes("429")) {
383
786
  return "Rate limited (429) — try again in a moment.";
384
787
  }
385
788
  return msg;
386
789
  }
790
+ /**
791
+ * How long to wait for a stdio server to answer `server/discover` before
792
+ * concluding it is a 2025-era server. A local child that has not replied in
793
+ * this window is not going to; the SDK then falls back to `initialize`.
794
+ */
795
+ const STDIO_PROBE_TIMEOUT_MS = 2_500;
796
+ /** OAuth failures that mean the saved credentials can no longer be used. */
797
+ const REAUTH_OAUTH_CODES = [
798
+ OAuthErrorCode.InvalidToken,
799
+ OAuthErrorCode.InvalidGrant,
800
+ OAuthErrorCode.InvalidClient,
801
+ OAuthErrorCode.AccessDenied,
802
+ ];
803
+ /**
804
+ * Whether an error means the remote server has dropped our HTTP session.
805
+ *
806
+ * `StreamableHTTPClientTransport.send` handles 401/403 (it re-runs auth) but
807
+ * returns a bare `SdkHttpError{status:404}` when the `Mcp-Session-Id` we are
808
+ * carrying is no longer known to the server — which is exactly what happens
809
+ * after a server restart or an idle-session sweep on a long desktop session.
810
+ * The SDK has no recovery for it, so we rebuild the connection ourselves.
811
+ */
812
+ function isSessionExpired(reason) {
813
+ return SdkHttpError.isInstance(reason) && reason.status === 404;
814
+ }
387
815
  /**
388
816
  * Whether a connect error means the server needs OAuth login. The SDK throws
389
- * its typed `UnauthorizedError` when auth is required, but a raw 401 from the
390
- * initial request (before the auth machinery engages) can also surface as a
391
- * plain error message — so we check both.
817
+ * its typed `UnauthorizedError` when auth is required, a `SdkHttpError` for a
818
+ * bare 401, and an `OAuthError` when the token endpoint rejects the saved
819
+ * credentials. A raw 401 from before the auth machinery engages can still
820
+ * surface as a plain message — so the string check remains as a fallback.
392
821
  */
393
822
  function isUnauthorized(reason) {
394
- if (reason instanceof UnauthorizedError)
823
+ if (UnauthorizedError.isInstance(reason))
395
824
  return true;
825
+ if (SdkHttpError.isInstance(reason))
826
+ return reason.status === 401;
827
+ // Token/grant/client codes mean "log in again"; the rest (server_error,
828
+ // temporarily_unavailable, …) are transient, not an auth gap.
829
+ if (OAuthError.isInstance(reason))
830
+ return REAUTH_OAUTH_CODES.includes(reason.code);
396
831
  const msg = reason instanceof Error ? reason.message : String(reason);
397
832
  return (msg.includes("Unauthorized") ||
398
833
  msg.includes("401") ||
@@ -410,12 +845,18 @@ function escapeHtml(value) {
410
845
  * Create a custom fetch wrapper that injects extra headers into every request.
411
846
  * Used for SSEClientTransport's eventSourceInit to pass auth headers
412
847
  * on the initial SSE GET connection (which doesn't use requestInit).
848
+ *
849
+ * The incoming headers may be a Web Standard `Headers` instance (v2 uses it
850
+ * throughout) or a plain object. Spreading a `Headers` yields `{}`, silently
851
+ * dropping the SDK's own auth header — so normalize through `Headers`, which
852
+ * accepts both shapes, and merge with `set()` rather than bracket access.
413
853
  */
414
854
  function createHeaderFetch(extraHeaders) {
415
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
416
855
  return (url, init) => {
417
- const existing = (init?.headers ?? {});
418
- return fetch(url, { ...init, headers: { ...existing, ...extraHeaders } });
856
+ const headers = new Headers(init?.headers);
857
+ for (const [name, value] of Object.entries(extraHeaders))
858
+ headers.set(name, value);
859
+ return fetch(url, { ...init, headers });
419
860
  };
420
861
  }
421
862
  //# sourceMappingURL=client.js.map