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