@animalabs/agent-framework 0.22.1 → 0.22.3

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 (946) hide show
  1. package/README.md +4 -2
  2. package/dist/src/agent.d.ts +266 -28
  3. package/dist/src/agent.d.ts.map +1 -1
  4. package/dist/src/agent.js +539 -104
  5. package/dist/src/agent.js.map +1 -1
  6. package/dist/src/api/mcp-server-core.d.ts +41 -0
  7. package/dist/src/api/mcp-server-core.d.ts.map +1 -0
  8. package/dist/src/api/mcp-server-core.js +593 -0
  9. package/dist/src/api/mcp-server-core.js.map +1 -0
  10. package/dist/src/api/mcp-server.d.ts +2 -36
  11. package/dist/src/api/mcp-server.d.ts.map +1 -1
  12. package/dist/src/api/mcp-server.js +15 -595
  13. package/dist/src/api/mcp-server.js.map +1 -1
  14. package/dist/src/api/server.d.ts +9 -1
  15. package/dist/src/api/server.d.ts.map +1 -1
  16. package/dist/src/api/server.js +55 -27
  17. package/dist/src/api/server.js.map +1 -1
  18. package/dist/src/api/types.d.ts +10 -2
  19. package/dist/src/api/types.d.ts.map +1 -1
  20. package/dist/src/branch-names.d.ts +14 -0
  21. package/dist/src/branch-names.d.ts.map +1 -0
  22. package/dist/src/branch-names.js +22 -0
  23. package/dist/src/branch-names.js.map +1 -0
  24. package/dist/src/closest-names.d.ts +28 -0
  25. package/dist/src/closest-names.d.ts.map +1 -0
  26. package/dist/src/closest-names.js +98 -0
  27. package/dist/src/closest-names.js.map +1 -0
  28. package/dist/src/code-execution/py-runner.d.ts +16 -5
  29. package/dist/src/code-execution/py-runner.d.ts.map +1 -1
  30. package/dist/src/code-execution/py-runner.js +186 -74
  31. package/dist/src/code-execution/py-runner.js.map +1 -1
  32. package/dist/src/code-execution/runtime-py.d.ts.map +1 -1
  33. package/dist/src/code-execution/runtime-py.js +49 -3
  34. package/dist/src/code-execution/runtime-py.js.map +1 -1
  35. package/dist/src/code-execution/tool-definition.d.ts +12 -1
  36. package/dist/src/code-execution/tool-definition.d.ts.map +1 -1
  37. package/dist/src/code-execution/tool-definition.js +21 -3
  38. package/dist/src/code-execution/tool-definition.js.map +1 -1
  39. package/dist/src/config-checks.d.ts +28 -0
  40. package/dist/src/config-checks.d.ts.map +1 -0
  41. package/dist/src/config-checks.js +52 -0
  42. package/dist/src/config-checks.js.map +1 -0
  43. package/dist/src/deadline-timer.d.ts +21 -0
  44. package/dist/src/deadline-timer.d.ts.map +1 -0
  45. package/dist/src/deadline-timer.js +43 -0
  46. package/dist/src/deadline-timer.js.map +1 -0
  47. package/dist/src/error-message.d.ts +30 -0
  48. package/dist/src/error-message.d.ts.map +1 -0
  49. package/dist/src/error-message.js +50 -0
  50. package/dist/src/error-message.js.map +1 -0
  51. package/dist/src/framework.d.ts +1212 -192
  52. package/dist/src/framework.d.ts.map +1 -1
  53. package/dist/src/framework.js +6686 -1835
  54. package/dist/src/framework.js.map +1 -1
  55. package/dist/src/gate/event-gate.d.ts +8 -0
  56. package/dist/src/gate/event-gate.d.ts.map +1 -1
  57. package/dist/src/gate/event-gate.js +27 -3
  58. package/dist/src/gate/event-gate.js.map +1 -1
  59. package/dist/src/gate/gate-script.d.ts.map +1 -1
  60. package/dist/src/gate/gate-script.js.map +1 -1
  61. package/dist/src/index.d.ts +5 -3
  62. package/dist/src/index.d.ts.map +1 -1
  63. package/dist/src/index.js +5 -3
  64. package/dist/src/index.js.map +1 -1
  65. package/dist/src/mcpl/capability-grant.d.ts.map +1 -1
  66. package/dist/src/mcpl/channel-registry.d.ts +170 -13
  67. package/dist/src/mcpl/channel-registry.d.ts.map +1 -1
  68. package/dist/src/mcpl/channel-registry.js +499 -258
  69. package/dist/src/mcpl/channel-registry.js.map +1 -1
  70. package/dist/src/mcpl/checkpoint-manager.d.ts +21 -1
  71. package/dist/src/mcpl/checkpoint-manager.d.ts.map +1 -1
  72. package/dist/src/mcpl/checkpoint-manager.js +91 -30
  73. package/dist/src/mcpl/checkpoint-manager.js.map +1 -1
  74. package/dist/src/mcpl/conversation-router.d.ts +19 -3
  75. package/dist/src/mcpl/conversation-router.d.ts.map +1 -1
  76. package/dist/src/mcpl/conversation-router.js +23 -8
  77. package/dist/src/mcpl/conversation-router.js.map +1 -1
  78. package/dist/src/mcpl/convert-block.d.ts +20 -0
  79. package/dist/src/mcpl/convert-block.d.ts.map +1 -0
  80. package/dist/src/mcpl/convert-block.js +89 -0
  81. package/dist/src/mcpl/convert-block.js.map +1 -0
  82. package/dist/src/mcpl/errors.d.ts +13 -0
  83. package/dist/src/mcpl/errors.d.ts.map +1 -1
  84. package/dist/src/mcpl/errors.js +28 -0
  85. package/dist/src/mcpl/errors.js.map +1 -1
  86. package/dist/src/mcpl/feature-set-manager.d.ts.map +1 -1
  87. package/dist/src/mcpl/feature-set-manager.js +4 -3
  88. package/dist/src/mcpl/feature-set-manager.js.map +1 -1
  89. package/dist/src/mcpl/hook-orchestrator.d.ts +23 -0
  90. package/dist/src/mcpl/hook-orchestrator.d.ts.map +1 -1
  91. package/dist/src/mcpl/hook-orchestrator.js +83 -72
  92. package/dist/src/mcpl/hook-orchestrator.js.map +1 -1
  93. package/dist/src/mcpl/inbound-source.d.ts +114 -0
  94. package/dist/src/mcpl/inbound-source.d.ts.map +1 -0
  95. package/dist/src/mcpl/inbound-source.js +83 -0
  96. package/dist/src/mcpl/inbound-source.js.map +1 -0
  97. package/dist/src/mcpl/index.d.ts +3 -1
  98. package/dist/src/mcpl/index.d.ts.map +1 -1
  99. package/dist/src/mcpl/index.js +3 -1
  100. package/dist/src/mcpl/index.js.map +1 -1
  101. package/dist/src/mcpl/inference-router.d.ts +15 -11
  102. package/dist/src/mcpl/inference-router.d.ts.map +1 -1
  103. package/dist/src/mcpl/inference-router.js +153 -84
  104. package/dist/src/mcpl/inference-router.js.map +1 -1
  105. package/dist/src/mcpl/log-value.d.ts +54 -0
  106. package/dist/src/mcpl/log-value.d.ts.map +1 -0
  107. package/dist/src/mcpl/log-value.js +109 -0
  108. package/dist/src/mcpl/log-value.js.map +1 -0
  109. package/dist/src/mcpl/prose-stream-router.d.ts +6 -6
  110. package/dist/src/mcpl/prose-stream-router.d.ts.map +1 -1
  111. package/dist/src/mcpl/prose-stream-router.js +4 -4
  112. package/dist/src/mcpl/prose-stream-router.js.map +1 -1
  113. package/dist/src/mcpl/push-coalescer.d.ts +64 -7
  114. package/dist/src/mcpl/push-coalescer.d.ts.map +1 -1
  115. package/dist/src/mcpl/push-coalescer.js +121 -24
  116. package/dist/src/mcpl/push-coalescer.js.map +1 -1
  117. package/dist/src/mcpl/push-handler.d.ts +38 -8
  118. package/dist/src/mcpl/push-handler.d.ts.map +1 -1
  119. package/dist/src/mcpl/push-handler.js +77 -78
  120. package/dist/src/mcpl/push-handler.js.map +1 -1
  121. package/dist/src/mcpl/reference-fetcher.d.ts +14 -2
  122. package/dist/src/mcpl/reference-fetcher.d.ts.map +1 -1
  123. package/dist/src/mcpl/reference-fetcher.js +72 -30
  124. package/dist/src/mcpl/reference-fetcher.js.map +1 -1
  125. package/dist/src/mcpl/references.d.ts +49 -14
  126. package/dist/src/mcpl/references.d.ts.map +1 -1
  127. package/dist/src/mcpl/references.js +74 -21
  128. package/dist/src/mcpl/references.js.map +1 -1
  129. package/dist/src/mcpl/refusal-lines.d.ts +37 -0
  130. package/dist/src/mcpl/refusal-lines.d.ts.map +1 -0
  131. package/dist/src/mcpl/refusal-lines.js +61 -0
  132. package/dist/src/mcpl/refusal-lines.js.map +1 -0
  133. package/dist/src/mcpl/scope-manager.d.ts.map +1 -1
  134. package/dist/src/mcpl/server-connection.d.ts +107 -12
  135. package/dist/src/mcpl/server-connection.d.ts.map +1 -1
  136. package/dist/src/mcpl/server-connection.js +470 -139
  137. package/dist/src/mcpl/server-connection.js.map +1 -1
  138. package/dist/src/mcpl/server-registry.d.ts +10 -1
  139. package/dist/src/mcpl/server-registry.d.ts.map +1 -1
  140. package/dist/src/mcpl/server-registry.js +14 -3
  141. package/dist/src/mcpl/server-registry.js.map +1 -1
  142. package/dist/src/mcpl/skip-reply-wake.d.ts +36 -0
  143. package/dist/src/mcpl/skip-reply-wake.d.ts.map +1 -0
  144. package/dist/src/mcpl/skip-reply-wake.js +55 -0
  145. package/dist/src/mcpl/skip-reply-wake.js.map +1 -0
  146. package/dist/src/mcpl/tool-classes.d.ts +1 -1
  147. package/dist/src/mcpl/tool-classes.d.ts.map +1 -1
  148. package/dist/src/mcpl/tool-classes.js +3 -2
  149. package/dist/src/mcpl/tool-classes.js.map +1 -1
  150. package/dist/src/mcpl/tool-lifecycle.d.ts.map +1 -1
  151. package/dist/src/mcpl/tool-lifecycle.js.map +1 -1
  152. package/dist/src/mcpl/transport.d.ts +74 -7
  153. package/dist/src/mcpl/transport.d.ts.map +1 -1
  154. package/dist/src/mcpl/transport.js +209 -22
  155. package/dist/src/mcpl/transport.js.map +1 -1
  156. package/dist/src/mcpl/types.d.ts +43 -28
  157. package/dist/src/mcpl/types.d.ts.map +1 -1
  158. package/dist/src/mcpl/types.js.map +1 -1
  159. package/dist/src/mcpl/visible-content.d.ts +15 -0
  160. package/dist/src/mcpl/visible-content.d.ts.map +1 -1
  161. package/dist/src/mcpl/visible-content.js +25 -0
  162. package/dist/src/mcpl/visible-content.js.map +1 -1
  163. package/dist/src/module-registry.d.ts +19 -1
  164. package/dist/src/module-registry.d.ts.map +1 -1
  165. package/dist/src/module-registry.js +54 -25
  166. package/dist/src/module-registry.js.map +1 -1
  167. package/dist/src/modules/api/index.d.ts.map +1 -1
  168. package/dist/src/modules/api/index.js +1 -1
  169. package/dist/src/modules/api/index.js.map +1 -1
  170. package/dist/src/modules/discord/discord-js-client.d.ts +1 -0
  171. package/dist/src/modules/discord/discord-js-client.d.ts.map +1 -1
  172. package/dist/src/modules/discord/discord-js-client.js +25 -9
  173. package/dist/src/modules/discord/discord-js-client.js.map +1 -1
  174. package/dist/src/modules/discord/index.d.ts +29 -3
  175. package/dist/src/modules/discord/index.d.ts.map +1 -1
  176. package/dist/src/modules/discord/index.js +383 -145
  177. package/dist/src/modules/discord/index.js.map +1 -1
  178. package/dist/src/modules/discord/types.d.ts +14 -1
  179. package/dist/src/modules/discord/types.d.ts.map +1 -1
  180. package/dist/src/modules/health/index.d.ts.map +1 -1
  181. package/dist/src/modules/health/index.js +2 -1
  182. package/dist/src/modules/health/index.js.map +1 -1
  183. package/dist/src/modules/history/index.d.ts +3 -1
  184. package/dist/src/modules/history/index.d.ts.map +1 -1
  185. package/dist/src/modules/history/index.js +359 -127
  186. package/dist/src/modules/history/index.js.map +1 -1
  187. package/dist/src/modules/history/semantic.d.ts +28 -1
  188. package/dist/src/modules/history/semantic.d.ts.map +1 -1
  189. package/dist/src/modules/history/semantic.js +177 -32
  190. package/dist/src/modules/history/semantic.js.map +1 -1
  191. package/dist/src/modules/unknown-tool.d.ts +10 -0
  192. package/dist/src/modules/unknown-tool.d.ts.map +1 -0
  193. package/dist/src/modules/unknown-tool.js +17 -0
  194. package/dist/src/modules/unknown-tool.js.map +1 -0
  195. package/dist/src/modules/workspace/branch-intent.d.ts.map +1 -1
  196. package/dist/src/modules/workspace/branch-intent.js.map +1 -1
  197. package/dist/src/modules/workspace/disk-agreement.d.ts +54 -6
  198. package/dist/src/modules/workspace/disk-agreement.d.ts.map +1 -1
  199. package/dist/src/modules/workspace/disk-agreement.js +93 -27
  200. package/dist/src/modules/workspace/disk-agreement.js.map +1 -1
  201. package/dist/src/modules/workspace/effects.d.ts +64 -6
  202. package/dist/src/modules/workspace/effects.d.ts.map +1 -1
  203. package/dist/src/modules/workspace/effects.js +291 -44
  204. package/dist/src/modules/workspace/effects.js.map +1 -1
  205. package/dist/src/modules/workspace/index.d.ts +127 -27
  206. package/dist/src/modules/workspace/index.d.ts.map +1 -1
  207. package/dist/src/modules/workspace/index.js +821 -248
  208. package/dist/src/modules/workspace/index.js.map +1 -1
  209. package/dist/src/modules/workspace/observe.d.ts +117 -15
  210. package/dist/src/modules/workspace/observe.d.ts.map +1 -1
  211. package/dist/src/modules/workspace/observe.js +436 -51
  212. package/dist/src/modules/workspace/observe.js.map +1 -1
  213. package/dist/src/modules/workspace/reconcile.d.ts +75 -8
  214. package/dist/src/modules/workspace/reconcile.d.ts.map +1 -1
  215. package/dist/src/modules/workspace/reconcile.js +576 -68
  216. package/dist/src/modules/workspace/reconcile.js.map +1 -1
  217. package/dist/src/modules/workspace/types.d.ts +42 -3
  218. package/dist/src/modules/workspace/types.d.ts.map +1 -1
  219. package/dist/src/modules/workspace/types.js.map +1 -1
  220. package/dist/src/modules/workspace/watcher.d.ts +7 -2
  221. package/dist/src/modules/workspace/watcher.d.ts.map +1 -1
  222. package/dist/src/modules/workspace/watcher.js +28 -4
  223. package/dist/src/modules/workspace/watcher.js.map +1 -1
  224. package/dist/src/operator-log.d.ts.map +1 -1
  225. package/dist/src/operator-log.js.map +1 -1
  226. package/dist/src/prose-drafts.d.ts +240 -0
  227. package/dist/src/prose-drafts.d.ts.map +1 -0
  228. package/dist/src/prose-drafts.js +362 -0
  229. package/dist/src/prose-drafts.js.map +1 -0
  230. package/dist/src/prose-segments.d.ts +21 -2
  231. package/dist/src/prose-segments.d.ts.map +1 -1
  232. package/dist/src/prose-segments.js +46 -9
  233. package/dist/src/prose-segments.js.map +1 -1
  234. package/dist/src/provider-waits.d.ts.map +1 -1
  235. package/dist/src/provider-waits.js.map +1 -1
  236. package/dist/src/queue.d.ts.map +1 -1
  237. package/dist/src/record-journal.d.ts.map +1 -1
  238. package/dist/src/record-journal.js.map +1 -1
  239. package/dist/src/recovery/discord-awareness-outbox.d.ts.map +1 -1
  240. package/dist/src/recovery/discord-awareness-outbox.js.map +1 -1
  241. package/dist/src/recovery/offline-branch.d.ts +1 -0
  242. package/dist/src/recovery/offline-branch.d.ts.map +1 -1
  243. package/dist/src/recovery/offline-branch.js +32 -25
  244. package/dist/src/recovery/offline-branch.js.map +1 -1
  245. package/dist/src/recovery/recover-cli.js.map +1 -1
  246. package/dist/src/runtime/liveness-watchdog.d.ts.map +1 -1
  247. package/dist/src/runtime/liveness-watchdog.js.map +1 -1
  248. package/dist/src/safe-slice.d.ts +5 -1
  249. package/dist/src/safe-slice.d.ts.map +1 -1
  250. package/dist/src/safe-slice.js +9 -1
  251. package/dist/src/safe-slice.js.map +1 -1
  252. package/dist/src/shutdown.d.ts.map +1 -1
  253. package/dist/src/shutdown.js.map +1 -1
  254. package/dist/src/stored-removal.d.ts +73 -0
  255. package/dist/src/stored-removal.d.ts.map +1 -0
  256. package/dist/src/stored-removal.js +100 -0
  257. package/dist/src/stored-removal.js.map +1 -0
  258. package/dist/src/thinking-token-stamp.js.map +1 -1
  259. package/dist/src/tool-image-ledger.d.ts +87 -19
  260. package/dist/src/tool-image-ledger.d.ts.map +1 -1
  261. package/dist/src/tool-image-ledger.js +135 -32
  262. package/dist/src/tool-image-ledger.js.map +1 -1
  263. package/dist/src/tool-presentation.d.ts +9 -0
  264. package/dist/src/tool-presentation.d.ts.map +1 -1
  265. package/dist/src/tool-presentation.js +257 -60
  266. package/dist/src/tool-presentation.js.map +1 -1
  267. package/dist/src/tool-result-guard.d.ts.map +1 -1
  268. package/dist/src/tool-result-guard.js +7 -10
  269. package/dist/src/tool-result-guard.js.map +1 -1
  270. package/dist/src/tool-result-history.d.ts +32 -3
  271. package/dist/src/tool-result-history.d.ts.map +1 -1
  272. package/dist/src/tool-result-history.js +106 -19
  273. package/dist/src/tool-result-history.js.map +1 -1
  274. package/dist/src/tune-out/coordinator.d.ts +25 -1
  275. package/dist/src/tune-out/coordinator.d.ts.map +1 -1
  276. package/dist/src/tune-out/coordinator.js +260 -65
  277. package/dist/src/tune-out/coordinator.js.map +1 -1
  278. package/dist/src/tune-out/tools.d.ts +1 -1
  279. package/dist/src/tune-out/tools.d.ts.map +1 -1
  280. package/dist/src/types/agent.d.ts +59 -11
  281. package/dist/src/types/agent.d.ts.map +1 -1
  282. package/dist/src/types/events.d.ts +17 -0
  283. package/dist/src/types/events.d.ts.map +1 -1
  284. package/dist/src/types/framework.d.ts +31 -5
  285. package/dist/src/types/framework.d.ts.map +1 -1
  286. package/dist/src/types/inference-log.d.ts +1 -1
  287. package/dist/src/types/inference-log.d.ts.map +1 -1
  288. package/dist/src/types/module.d.ts +30 -7
  289. package/dist/src/types/module.d.ts.map +1 -1
  290. package/dist/src/types/trace.d.ts +151 -11
  291. package/dist/src/types/trace.d.ts.map +1 -1
  292. package/dist/src/usage/usage-tracker.d.ts +5 -0
  293. package/dist/src/usage/usage-tracker.d.ts.map +1 -1
  294. package/dist/src/usage/usage-tracker.js +35 -8
  295. package/dist/src/usage/usage-tracker.js.map +1 -1
  296. package/package.json +10 -9
  297. package/src/agent.ts +572 -105
  298. package/src/api/mcp-server-core.ts +681 -0
  299. package/src/api/mcp-server.ts +16 -685
  300. package/src/api/server.ts +55 -30
  301. package/src/api/types.ts +10 -2
  302. package/src/branch-names.ts +19 -0
  303. package/src/closest-names.ts +94 -0
  304. package/src/code-execution/py-runner.ts +200 -76
  305. package/src/code-execution/runtime-py.ts +49 -3
  306. package/src/code-execution/tool-definition.ts +28 -4
  307. package/src/config-checks.ts +48 -0
  308. package/src/deadline-timer.ts +44 -0
  309. package/src/error-message.ts +48 -0
  310. package/src/framework.ts +7158 -1936
  311. package/src/gate/event-gate.ts +28 -3
  312. package/src/index.ts +12 -3
  313. package/src/mcpl/channel-registry.ts +615 -289
  314. package/src/mcpl/checkpoint-manager.ts +104 -29
  315. package/src/mcpl/conversation-router.ts +28 -8
  316. package/src/mcpl/convert-block.ts +97 -0
  317. package/src/mcpl/errors.ts +28 -0
  318. package/src/mcpl/feature-set-manager.ts +4 -3
  319. package/src/mcpl/hook-orchestrator.ts +84 -77
  320. package/src/mcpl/inbound-source.ts +156 -0
  321. package/src/mcpl/index.ts +10 -1
  322. package/src/mcpl/inference-router.ts +174 -99
  323. package/src/mcpl/log-value.ts +116 -0
  324. package/src/mcpl/prose-stream-router.ts +6 -6
  325. package/src/mcpl/push-coalescer.ts +124 -24
  326. package/src/mcpl/push-handler.ts +86 -84
  327. package/src/mcpl/reference-fetcher.ts +71 -26
  328. package/src/mcpl/references.ts +81 -22
  329. package/src/mcpl/refusal-lines.ts +59 -0
  330. package/src/mcpl/server-connection.ts +496 -142
  331. package/src/mcpl/server-registry.ts +15 -4
  332. package/src/mcpl/skip-reply-wake.ts +73 -0
  333. package/src/mcpl/tool-classes.ts +3 -2
  334. package/src/mcpl/transport.ts +219 -26
  335. package/src/mcpl/types.ts +18 -3
  336. package/src/mcpl/visible-content.ts +27 -0
  337. package/src/module-registry.ts +58 -23
  338. package/src/modules/api/index.ts +1 -1
  339. package/src/modules/discord/discord-js-client.ts +26 -10
  340. package/src/modules/discord/index.ts +395 -160
  341. package/src/modules/discord/types.ts +15 -2
  342. package/src/modules/health/index.ts +2 -1
  343. package/src/modules/history/index.ts +410 -120
  344. package/src/modules/history/semantic.ts +189 -32
  345. package/src/modules/unknown-tool.ts +16 -0
  346. package/src/modules/workspace/disk-agreement.ts +125 -21
  347. package/src/modules/workspace/effects.ts +279 -35
  348. package/src/modules/workspace/index.ts +841 -261
  349. package/src/modules/workspace/observe.ts +456 -56
  350. package/src/modules/workspace/reconcile.ts +688 -76
  351. package/src/modules/workspace/types.ts +41 -2
  352. package/src/modules/workspace/watcher.ts +27 -4
  353. package/src/prose-drafts.ts +481 -0
  354. package/src/prose-segments.ts +51 -8
  355. package/src/recovery/offline-branch.ts +36 -29
  356. package/src/safe-slice.ts +9 -1
  357. package/src/stored-removal.ts +126 -0
  358. package/src/tool-image-ledger.ts +153 -34
  359. package/src/tool-presentation.ts +224 -40
  360. package/src/tool-result-guard.ts +7 -8
  361. package/src/tool-result-history.ts +124 -20
  362. package/src/tune-out/coordinator.ts +259 -65
  363. package/src/types/agent.ts +59 -13
  364. package/src/types/events.ts +17 -0
  365. package/src/types/framework.ts +31 -5
  366. package/src/types/inference-log.ts +1 -1
  367. package/src/types/module.ts +31 -7
  368. package/src/types/trace.ts +158 -12
  369. package/src/usage/usage-tracker.ts +32 -8
  370. package/dist/test/activation-request-sanitize.test.d.ts +0 -2
  371. package/dist/test/activation-request-sanitize.test.d.ts.map +0 -1
  372. package/dist/test/activation-request-sanitize.test.js +0 -89
  373. package/dist/test/activation-request-sanitize.test.js.map +0 -1
  374. package/dist/test/agent-cache-ttl.test.d.ts +0 -2
  375. package/dist/test/agent-cache-ttl.test.d.ts.map +0 -1
  376. package/dist/test/agent-cache-ttl.test.js +0 -41
  377. package/dist/test/agent-cache-ttl.test.js.map +0 -1
  378. package/dist/test/agent-runtime-settings.test.d.ts +0 -2
  379. package/dist/test/agent-runtime-settings.test.d.ts.map +0 -1
  380. package/dist/test/agent-runtime-settings.test.js +0 -462
  381. package/dist/test/agent-runtime-settings.test.js.map +0 -1
  382. package/dist/test/api-admin-gate.test.d.ts +0 -2
  383. package/dist/test/api-admin-gate.test.d.ts.map +0 -1
  384. package/dist/test/api-admin-gate.test.js +0 -116
  385. package/dist/test/api-admin-gate.test.js.map +0 -1
  386. package/dist/test/assistant-persist-refusal.test.d.ts +0 -2
  387. package/dist/test/assistant-persist-refusal.test.d.ts.map +0 -1
  388. package/dist/test/assistant-persist-refusal.test.js +0 -63
  389. package/dist/test/assistant-persist-refusal.test.js.map +0 -1
  390. package/dist/test/batched-wake-locus.test.d.ts +0 -2
  391. package/dist/test/batched-wake-locus.test.d.ts.map +0 -1
  392. package/dist/test/batched-wake-locus.test.js +0 -166
  393. package/dist/test/batched-wake-locus.test.js.map +0 -1
  394. package/dist/test/busy-agent-scheduler.test.d.ts +0 -2
  395. package/dist/test/busy-agent-scheduler.test.d.ts.map +0 -1
  396. package/dist/test/busy-agent-scheduler.test.js +0 -92
  397. package/dist/test/busy-agent-scheduler.test.js.map +0 -1
  398. package/dist/test/channel-incoming-targeting.test.d.ts +0 -2
  399. package/dist/test/channel-incoming-targeting.test.d.ts.map +0 -1
  400. package/dist/test/channel-incoming-targeting.test.js +0 -81
  401. package/dist/test/channel-incoming-targeting.test.js.map +0 -1
  402. package/dist/test/channel-label-history.test.d.ts +0 -2
  403. package/dist/test/channel-label-history.test.d.ts.map +0 -1
  404. package/dist/test/channel-label-history.test.js +0 -424
  405. package/dist/test/channel-label-history.test.js.map +0 -1
  406. package/dist/test/channel-lifecycle-provenance.test.d.ts +0 -2
  407. package/dist/test/channel-lifecycle-provenance.test.d.ts.map +0 -1
  408. package/dist/test/channel-lifecycle-provenance.test.js +0 -47
  409. package/dist/test/channel-lifecycle-provenance.test.js.map +0 -1
  410. package/dist/test/channel-registry-routing.test.d.ts +0 -2
  411. package/dist/test/channel-registry-routing.test.d.ts.map +0 -1
  412. package/dist/test/channel-registry-routing.test.js +0 -446
  413. package/dist/test/channel-registry-routing.test.js.map +0 -1
  414. package/dist/test/channel-registry-typing.test.d.ts +0 -2
  415. package/dist/test/channel-registry-typing.test.d.ts.map +0 -1
  416. package/dist/test/channel-registry-typing.test.js +0 -91
  417. package/dist/test/channel-registry-typing.test.js.map +0 -1
  418. package/dist/test/channels-changed-respond-first.test.d.ts +0 -2
  419. package/dist/test/channels-changed-respond-first.test.d.ts.map +0 -1
  420. package/dist/test/channels-changed-respond-first.test.js +0 -74
  421. package/dist/test/channels-changed-respond-first.test.js.map +0 -1
  422. package/dist/test/checkpoint-attribution.test.d.ts +0 -2
  423. package/dist/test/checkpoint-attribution.test.d.ts.map +0 -1
  424. package/dist/test/checkpoint-attribution.test.js +0 -200
  425. package/dist/test/checkpoint-attribution.test.js.map +0 -1
  426. package/dist/test/code-execution.test.d.ts +0 -11
  427. package/dist/test/code-execution.test.d.ts.map +0 -1
  428. package/dist/test/code-execution.test.js +0 -1272
  429. package/dist/test/code-execution.test.js.map +0 -1
  430. package/dist/test/component-defaults.test.d.ts +0 -2
  431. package/dist/test/component-defaults.test.d.ts.map +0 -1
  432. package/dist/test/component-defaults.test.js +0 -54
  433. package/dist/test/component-defaults.test.js.map +0 -1
  434. package/dist/test/conversation-fork-injection-scoping.test.d.ts +0 -2
  435. package/dist/test/conversation-fork-injection-scoping.test.d.ts.map +0 -1
  436. package/dist/test/conversation-fork-injection-scoping.test.js +0 -200
  437. package/dist/test/conversation-fork-injection-scoping.test.js.map +0 -1
  438. package/dist/test/conversation-router.test.d.ts +0 -2
  439. package/dist/test/conversation-router.test.d.ts.map +0 -1
  440. package/dist/test/conversation-router.test.js +0 -174
  441. package/dist/test/conversation-router.test.js.map +0 -1
  442. package/dist/test/conversation-routing.test.d.ts +0 -7
  443. package/dist/test/conversation-routing.test.d.ts.map +0 -1
  444. package/dist/test/conversation-routing.test.js +0 -387
  445. package/dist/test/conversation-routing.test.js.map +0 -1
  446. package/dist/test/deferred-wake-integrity.test.d.ts +0 -29
  447. package/dist/test/deferred-wake-integrity.test.d.ts.map +0 -1
  448. package/dist/test/deferred-wake-integrity.test.js +0 -320
  449. package/dist/test/deferred-wake-integrity.test.js.map +0 -1
  450. package/dist/test/discord-awareness-outbox.test.d.ts +0 -2
  451. package/dist/test/discord-awareness-outbox.test.d.ts.map +0 -1
  452. package/dist/test/discord-awareness-outbox.test.js +0 -267
  453. package/dist/test/discord-awareness-outbox.test.js.map +0 -1
  454. package/dist/test/discord-history-delete-window.test.d.ts +0 -2
  455. package/dist/test/discord-history-delete-window.test.d.ts.map +0 -1
  456. package/dist/test/discord-history-delete-window.test.js +0 -81
  457. package/dist/test/discord-history-delete-window.test.js.map +0 -1
  458. package/dist/test/discord-history-sync.test.d.ts +0 -2
  459. package/dist/test/discord-history-sync.test.d.ts.map +0 -1
  460. package/dist/test/discord-history-sync.test.js +0 -56
  461. package/dist/test/discord-history-sync.test.js.map +0 -1
  462. package/dist/test/ephemeral-settle.test.d.ts +0 -2
  463. package/dist/test/ephemeral-settle.test.d.ts.map +0 -1
  464. package/dist/test/ephemeral-settle.test.js +0 -354
  465. package/dist/test/ephemeral-settle.test.js.map +0 -1
  466. package/dist/test/event-gate-passthrough.test.d.ts +0 -15
  467. package/dist/test/event-gate-passthrough.test.d.ts.map +0 -1
  468. package/dist/test/event-gate-passthrough.test.js +0 -289
  469. package/dist/test/event-gate-passthrough.test.js.map +0 -1
  470. package/dist/test/event-gate-policy-mutation.test.d.ts +0 -2
  471. package/dist/test/event-gate-policy-mutation.test.d.ts.map +0 -1
  472. package/dist/test/event-gate-policy-mutation.test.js +0 -137
  473. package/dist/test/event-gate-policy-mutation.test.js.map +0 -1
  474. package/dist/test/event-gate-rate-limit.test.d.ts +0 -2
  475. package/dist/test/event-gate-rate-limit.test.d.ts.map +0 -1
  476. package/dist/test/event-gate-rate-limit.test.js +0 -627
  477. package/dist/test/event-gate-rate-limit.test.js.map +0 -1
  478. package/dist/test/event-gate-script.test.d.ts +0 -2
  479. package/dist/test/event-gate-script.test.d.ts.map +0 -1
  480. package/dist/test/event-gate-script.test.js +0 -95
  481. package/dist/test/event-gate-script.test.js.map +0 -1
  482. package/dist/test/event-gate-selfwake.test.d.ts +0 -15
  483. package/dist/test/event-gate-selfwake.test.d.ts.map +0 -1
  484. package/dist/test/event-gate-selfwake.test.js +0 -125
  485. package/dist/test/event-gate-selfwake.test.js.map +0 -1
  486. package/dist/test/event-gate-tags.test.d.ts +0 -2
  487. package/dist/test/event-gate-tags.test.d.ts.map +0 -1
  488. package/dist/test/event-gate-tags.test.js +0 -76
  489. package/dist/test/event-gate-tags.test.js.map +0 -1
  490. package/dist/test/event-gate.test.d.ts +0 -2
  491. package/dist/test/event-gate.test.d.ts.map +0 -1
  492. package/dist/test/event-gate.test.js +0 -919
  493. package/dist/test/event-gate.test.js.map +0 -1
  494. package/dist/test/explicit-prose-routing.test.d.ts +0 -11
  495. package/dist/test/explicit-prose-routing.test.d.ts.map +0 -1
  496. package/dist/test/explicit-prose-routing.test.js +0 -1394
  497. package/dist/test/explicit-prose-routing.test.js.map +0 -1
  498. package/dist/test/framework.test.d.ts +0 -5
  499. package/dist/test/framework.test.d.ts.map +0 -1
  500. package/dist/test/framework.test.js +0 -1048
  501. package/dist/test/framework.test.js.map +0 -1
  502. package/dist/test/gather-context-timeout.test.d.ts +0 -2
  503. package/dist/test/gather-context-timeout.test.d.ts.map +0 -1
  504. package/dist/test/gather-context-timeout.test.js +0 -120
  505. package/dist/test/gather-context-timeout.test.js.map +0 -1
  506. package/dist/test/health-snapshot.test.d.ts +0 -2
  507. package/dist/test/health-snapshot.test.d.ts.map +0 -1
  508. package/dist/test/health-snapshot.test.js +0 -74
  509. package/dist/test/health-snapshot.test.js.map +0 -1
  510. package/dist/test/helpers/coalescing-fixture.d.ts +0 -72
  511. package/dist/test/helpers/coalescing-fixture.d.ts.map +0 -1
  512. package/dist/test/helpers/coalescing-fixture.js +0 -146
  513. package/dist/test/helpers/coalescing-fixture.js.map +0 -1
  514. package/dist/test/helpers/coalescing-kill-child.d.ts +0 -2
  515. package/dist/test/helpers/coalescing-kill-child.d.ts.map +0 -1
  516. package/dist/test/helpers/coalescing-kill-child.js +0 -24
  517. package/dist/test/helpers/coalescing-kill-child.js.map +0 -1
  518. package/dist/test/helpers/mock-membrane.d.ts +0 -53
  519. package/dist/test/helpers/mock-membrane.d.ts.map +0 -1
  520. package/dist/test/helpers/mock-membrane.js +0 -168
  521. package/dist/test/helpers/mock-membrane.js.map +0 -1
  522. package/dist/test/helpers/pytc-stop-rows.d.ts +0 -11
  523. package/dist/test/helpers/pytc-stop-rows.d.ts.map +0 -1
  524. package/dist/test/helpers/pytc-stop-rows.js +0 -143
  525. package/dist/test/helpers/pytc-stop-rows.js.map +0 -1
  526. package/dist/test/helpers/quiesce-crash-child.d.ts +0 -2
  527. package/dist/test/helpers/quiesce-crash-child.d.ts.map +0 -1
  528. package/dist/test/helpers/quiesce-crash-child.js +0 -156
  529. package/dist/test/helpers/quiesce-crash-child.js.map +0 -1
  530. package/dist/test/history-module-overview.test.d.ts +0 -2
  531. package/dist/test/history-module-overview.test.d.ts.map +0 -1
  532. package/dist/test/history-module-overview.test.js +0 -711
  533. package/dist/test/history-module-overview.test.js.map +0 -1
  534. package/dist/test/history-module-realstore.test.d.ts +0 -2
  535. package/dist/test/history-module-realstore.test.d.ts.map +0 -1
  536. package/dist/test/history-module-realstore.test.js +0 -363
  537. package/dist/test/history-module-realstore.test.js.map +0 -1
  538. package/dist/test/history-module-semantic.test.d.ts +0 -2
  539. package/dist/test/history-module-semantic.test.d.ts.map +0 -1
  540. package/dist/test/history-module-semantic.test.js +0 -213
  541. package/dist/test/history-module-semantic.test.js.map +0 -1
  542. package/dist/test/history-module-ux.test.d.ts +0 -2
  543. package/dist/test/history-module-ux.test.d.ts.map +0 -1
  544. package/dist/test/history-module-ux.test.js +0 -304
  545. package/dist/test/history-module-ux.test.js.map +0 -1
  546. package/dist/test/history-module.test.d.ts +0 -2
  547. package/dist/test/history-module.test.d.ts.map +0 -1
  548. package/dist/test/history-module.test.js +0 -619
  549. package/dist/test/history-module.test.js.map +0 -1
  550. package/dist/test/history-semantic-review-findings.test.d.ts +0 -2
  551. package/dist/test/history-semantic-review-findings.test.d.ts.map +0 -1
  552. package/dist/test/history-semantic-review-findings.test.js +0 -338
  553. package/dist/test/history-semantic-review-findings.test.js.map +0 -1
  554. package/dist/test/history-semantic-sync-converges.test.d.ts +0 -2
  555. package/dist/test/history-semantic-sync-converges.test.d.ts.map +0 -1
  556. package/dist/test/history-semantic-sync-converges.test.js +0 -109
  557. package/dist/test/history-semantic-sync-converges.test.js.map +0 -1
  558. package/dist/test/host-quiesce.test.d.ts +0 -2
  559. package/dist/test/host-quiesce.test.d.ts.map +0 -1
  560. package/dist/test/host-quiesce.test.js +0 -863
  561. package/dist/test/host-quiesce.test.js.map +0 -1
  562. package/dist/test/inference-exhaustion-rewind.test.d.ts +0 -2
  563. package/dist/test/inference-exhaustion-rewind.test.d.ts.map +0 -1
  564. package/dist/test/inference-exhaustion-rewind.test.js +0 -309
  565. package/dist/test/inference-exhaustion-rewind.test.js.map +0 -1
  566. package/dist/test/inference-failure-bounds.test.d.ts +0 -2
  567. package/dist/test/inference-failure-bounds.test.d.ts.map +0 -1
  568. package/dist/test/inference-failure-bounds.test.js +0 -1201
  569. package/dist/test/inference-failure-bounds.test.js.map +0 -1
  570. package/dist/test/inference-failure-observability.test.d.ts +0 -2
  571. package/dist/test/inference-failure-observability.test.d.ts.map +0 -1
  572. package/dist/test/inference-failure-observability.test.js +0 -84
  573. package/dist/test/inference-failure-observability.test.js.map +0 -1
  574. package/dist/test/journal-tool.test.d.ts +0 -2
  575. package/dist/test/journal-tool.test.d.ts.map +0 -1
  576. package/dist/test/journal-tool.test.js +0 -33
  577. package/dist/test/journal-tool.test.js.map +0 -1
  578. package/dist/test/kv-unified-open-flight-retry.test.d.ts +0 -2
  579. package/dist/test/kv-unified-open-flight-retry.test.d.ts.map +0 -1
  580. package/dist/test/kv-unified-open-flight-retry.test.js +0 -189
  581. package/dist/test/kv-unified-open-flight-retry.test.js.map +0 -1
  582. package/dist/test/kv-unified-wiring.test.d.ts +0 -2
  583. package/dist/test/kv-unified-wiring.test.d.ts.map +0 -1
  584. package/dist/test/kv-unified-wiring.test.js +0 -95
  585. package/dist/test/kv-unified-wiring.test.js.map +0 -1
  586. package/dist/test/late-events-after-stop.test.d.ts +0 -2
  587. package/dist/test/late-events-after-stop.test.d.ts.map +0 -1
  588. package/dist/test/late-events-after-stop.test.js +0 -122
  589. package/dist/test/late-events-after-stop.test.js.map +0 -1
  590. package/dist/test/liveness-watchdog.test.d.ts +0 -2
  591. package/dist/test/liveness-watchdog.test.d.ts.map +0 -1
  592. package/dist/test/liveness-watchdog.test.js +0 -94
  593. package/dist/test/liveness-watchdog.test.js.map +0 -1
  594. package/dist/test/machine-close-provenance.test.d.ts +0 -2
  595. package/dist/test/machine-close-provenance.test.d.ts.map +0 -1
  596. package/dist/test/machine-close-provenance.test.js +0 -116
  597. package/dist/test/machine-close-provenance.test.js.map +0 -1
  598. package/dist/test/maintenance-timer.test.d.ts +0 -2
  599. package/dist/test/maintenance-timer.test.d.ts.map +0 -1
  600. package/dist/test/maintenance-timer.test.js +0 -265
  601. package/dist/test/maintenance-timer.test.js.map +0 -1
  602. package/dist/test/mcpl-access-provider.test.d.ts +0 -2
  603. package/dist/test/mcpl-access-provider.test.d.ts.map +0 -1
  604. package/dist/test/mcpl-access-provider.test.js +0 -20
  605. package/dist/test/mcpl-access-provider.test.js.map +0 -1
  606. package/dist/test/mcpl-awareness-barrier.test.d.ts +0 -2
  607. package/dist/test/mcpl-awareness-barrier.test.d.ts.map +0 -1
  608. package/dist/test/mcpl-awareness-barrier.test.js +0 -769
  609. package/dist/test/mcpl-awareness-barrier.test.js.map +0 -1
  610. package/dist/test/mcpl-capability-grant.test.d.ts +0 -10
  611. package/dist/test/mcpl-capability-grant.test.d.ts.map +0 -1
  612. package/dist/test/mcpl-capability-grant.test.js +0 -111
  613. package/dist/test/mcpl-capability-grant.test.js.map +0 -1
  614. package/dist/test/mcpl-capability-scoping.test.d.ts +0 -2
  615. package/dist/test/mcpl-capability-scoping.test.d.ts.map +0 -1
  616. package/dist/test/mcpl-capability-scoping.test.js +0 -266
  617. package/dist/test/mcpl-capability-scoping.test.js.map +0 -1
  618. package/dist/test/mcpl-child-env.test.d.ts +0 -2
  619. package/dist/test/mcpl-child-env.test.d.ts.map +0 -1
  620. package/dist/test/mcpl-child-env.test.js +0 -158
  621. package/dist/test/mcpl-child-env.test.js.map +0 -1
  622. package/dist/test/mcpl-coalescing.test.d.ts +0 -2
  623. package/dist/test/mcpl-coalescing.test.d.ts.map +0 -1
  624. package/dist/test/mcpl-coalescing.test.js +0 -1125
  625. package/dist/test/mcpl-coalescing.test.js.map +0 -1
  626. package/dist/test/mcpl-config-diagnostics.test.d.ts +0 -2
  627. package/dist/test/mcpl-config-diagnostics.test.d.ts.map +0 -1
  628. package/dist/test/mcpl-config-diagnostics.test.js +0 -452
  629. package/dist/test/mcpl-config-diagnostics.test.js.map +0 -1
  630. package/dist/test/mcpl-empty-content.test.d.ts +0 -2
  631. package/dist/test/mcpl-empty-content.test.d.ts.map +0 -1
  632. package/dist/test/mcpl-empty-content.test.js +0 -368
  633. package/dist/test/mcpl-empty-content.test.js.map +0 -1
  634. package/dist/test/mcpl-gate-roundtrip.test.d.ts +0 -2
  635. package/dist/test/mcpl-gate-roundtrip.test.d.ts.map +0 -1
  636. package/dist/test/mcpl-gate-roundtrip.test.js +0 -285
  637. package/dist/test/mcpl-gate-roundtrip.test.js.map +0 -1
  638. package/dist/test/mcpl-list-status.test.d.ts +0 -2
  639. package/dist/test/mcpl-list-status.test.d.ts.map +0 -1
  640. package/dist/test/mcpl-list-status.test.js +0 -82
  641. package/dist/test/mcpl-list-status.test.js.map +0 -1
  642. package/dist/test/mcpl-manifest-changed.test.d.ts +0 -2
  643. package/dist/test/mcpl-manifest-changed.test.d.ts.map +0 -1
  644. package/dist/test/mcpl-manifest-changed.test.js +0 -178
  645. package/dist/test/mcpl-manifest-changed.test.js.map +0 -1
  646. package/dist/test/mcpl-push-convert.test.d.ts +0 -2
  647. package/dist/test/mcpl-push-convert.test.d.ts.map +0 -1
  648. package/dist/test/mcpl-push-convert.test.js +0 -42
  649. package/dist/test/mcpl-push-convert.test.js.map +0 -1
  650. package/dist/test/mcpl-reconnect-events.test.d.ts +0 -2
  651. package/dist/test/mcpl-reconnect-events.test.d.ts.map +0 -1
  652. package/dist/test/mcpl-reconnect-events.test.js +0 -144
  653. package/dist/test/mcpl-reconnect-events.test.js.map +0 -1
  654. package/dist/test/mcpl-reconnect-reregistration.test.d.ts +0 -2
  655. package/dist/test/mcpl-reconnect-reregistration.test.d.ts.map +0 -1
  656. package/dist/test/mcpl-reconnect-reregistration.test.js +0 -236
  657. package/dist/test/mcpl-reconnect-reregistration.test.js.map +0 -1
  658. package/dist/test/mcpl-reference-fetcher.test.d.ts +0 -2
  659. package/dist/test/mcpl-reference-fetcher.test.d.ts.map +0 -1
  660. package/dist/test/mcpl-reference-fetcher.test.js +0 -427
  661. package/dist/test/mcpl-reference-fetcher.test.js.map +0 -1
  662. package/dist/test/mcpl-reference-fields.test.d.ts +0 -2
  663. package/dist/test/mcpl-reference-fields.test.d.ts.map +0 -1
  664. package/dist/test/mcpl-reference-fields.test.js +0 -149
  665. package/dist/test/mcpl-reference-fields.test.js.map +0 -1
  666. package/dist/test/mcpl-request-timeout.test.d.ts +0 -2
  667. package/dist/test/mcpl-request-timeout.test.d.ts.map +0 -1
  668. package/dist/test/mcpl-request-timeout.test.js +0 -138
  669. package/dist/test/mcpl-request-timeout.test.js.map +0 -1
  670. package/dist/test/mcpl-runtime-lifecycle.test.d.ts +0 -7
  671. package/dist/test/mcpl-runtime-lifecycle.test.d.ts.map +0 -1
  672. package/dist/test/mcpl-runtime-lifecycle.test.js +0 -142
  673. package/dist/test/mcpl-runtime-lifecycle.test.js.map +0 -1
  674. package/dist/test/mcpl-tool-class-listing.test.d.ts +0 -2
  675. package/dist/test/mcpl-tool-class-listing.test.d.ts.map +0 -1
  676. package/dist/test/mcpl-tool-class-listing.test.js +0 -147
  677. package/dist/test/mcpl-tool-class-listing.test.js.map +0 -1
  678. package/dist/test/mcpl-tool-classes.test.d.ts +0 -7
  679. package/dist/test/mcpl-tool-classes.test.d.ts.map +0 -1
  680. package/dist/test/mcpl-tool-classes.test.js +0 -80
  681. package/dist/test/mcpl-tool-classes.test.js.map +0 -1
  682. package/dist/test/mcpl-tool-lifecycle-e2e.test.d.ts +0 -2
  683. package/dist/test/mcpl-tool-lifecycle-e2e.test.d.ts.map +0 -1
  684. package/dist/test/mcpl-tool-lifecycle-e2e.test.js +0 -237
  685. package/dist/test/mcpl-tool-lifecycle-e2e.test.js.map +0 -1
  686. package/dist/test/mcpl-tool-lifecycle-emitter.test.d.ts +0 -11
  687. package/dist/test/mcpl-tool-lifecycle-emitter.test.d.ts.map +0 -1
  688. package/dist/test/mcpl-tool-lifecycle-emitter.test.js +0 -412
  689. package/dist/test/mcpl-tool-lifecycle-emitter.test.js.map +0 -1
  690. package/dist/test/mcpl-tool-lifecycle-script.test.d.ts +0 -2
  691. package/dist/test/mcpl-tool-lifecycle-script.test.d.ts.map +0 -1
  692. package/dist/test/mcpl-tool-lifecycle-script.test.js +0 -288
  693. package/dist/test/mcpl-tool-lifecycle-script.test.js.map +0 -1
  694. package/dist/test/mcpl-tool-lifecycle.test.d.ts +0 -11
  695. package/dist/test/mcpl-tool-lifecycle.test.d.ts.map +0 -1
  696. package/dist/test/mcpl-tool-lifecycle.test.js +0 -270
  697. package/dist/test/mcpl-tool-lifecycle.test.js.map +0 -1
  698. package/dist/test/mcpl-ws-transport.test.d.ts +0 -2
  699. package/dist/test/mcpl-ws-transport.test.d.ts.map +0 -1
  700. package/dist/test/mcpl-ws-transport.test.js +0 -258
  701. package/dist/test/mcpl-ws-transport.test.js.map +0 -1
  702. package/dist/test/module-context-integration.test.d.ts +0 -18
  703. package/dist/test/module-context-integration.test.d.ts.map +0 -1
  704. package/dist/test/module-context-integration.test.js +0 -181
  705. package/dist/test/module-context-integration.test.js.map +0 -1
  706. package/dist/test/offline-recovery-branch.test.d.ts +0 -2
  707. package/dist/test/offline-recovery-branch.test.d.ts.map +0 -1
  708. package/dist/test/offline-recovery-branch.test.js +0 -226
  709. package/dist/test/offline-recovery-branch.test.js.map +0 -1
  710. package/dist/test/operator-surgery.test.d.ts +0 -2
  711. package/dist/test/operator-surgery.test.d.ts.map +0 -1
  712. package/dist/test/operator-surgery.test.js +0 -398
  713. package/dist/test/operator-surgery.test.js.map +0 -1
  714. package/dist/test/ops-alert.test.d.ts +0 -2
  715. package/dist/test/ops-alert.test.d.ts.map +0 -1
  716. package/dist/test/ops-alert.test.js +0 -153
  717. package/dist/test/ops-alert.test.js.map +0 -1
  718. package/dist/test/overbudget-drain-breaker.test.d.ts +0 -2
  719. package/dist/test/overbudget-drain-breaker.test.d.ts.map +0 -1
  720. package/dist/test/overbudget-drain-breaker.test.js +0 -197
  721. package/dist/test/overbudget-drain-breaker.test.js.map +0 -1
  722. package/dist/test/per-agent-delivery.test.d.ts +0 -2
  723. package/dist/test/per-agent-delivery.test.d.ts.map +0 -1
  724. package/dist/test/per-agent-delivery.test.js +0 -108
  725. package/dist/test/per-agent-delivery.test.js.map +0 -1
  726. package/dist/test/physical-window-restart.test.d.ts +0 -14
  727. package/dist/test/physical-window-restart.test.d.ts.map +0 -1
  728. package/dist/test/physical-window-restart.test.js +0 -222
  729. package/dist/test/physical-window-restart.test.js.map +0 -1
  730. package/dist/test/placed-reaction-baseline.test.d.ts +0 -2
  731. package/dist/test/placed-reaction-baseline.test.d.ts.map +0 -1
  732. package/dist/test/placed-reaction-baseline.test.js +0 -312
  733. package/dist/test/placed-reaction-baseline.test.js.map +0 -1
  734. package/dist/test/present-while-acting.test.d.ts +0 -19
  735. package/dist/test/present-while-acting.test.d.ts.map +0 -1
  736. package/dist/test/present-while-acting.test.js +0 -706
  737. package/dist/test/present-while-acting.test.js.map +0 -1
  738. package/dist/test/prose-segments.test.d.ts +0 -2
  739. package/dist/test/prose-segments.test.d.ts.map +0 -1
  740. package/dist/test/prose-segments.test.js +0 -52
  741. package/dist/test/prose-segments.test.js.map +0 -1
  742. package/dist/test/prose-stream-router.test.d.ts +0 -2
  743. package/dist/test/prose-stream-router.test.d.ts.map +0 -1
  744. package/dist/test/prose-stream-router.test.js +0 -171
  745. package/dist/test/prose-stream-router.test.js.map +0 -1
  746. package/dist/test/provider-acceleration-cooldown.test.d.ts +0 -2
  747. package/dist/test/provider-acceleration-cooldown.test.d.ts.map +0 -1
  748. package/dist/test/provider-acceleration-cooldown.test.js +0 -435
  749. package/dist/test/provider-acceleration-cooldown.test.js.map +0 -1
  750. package/dist/test/provider-waits.test.d.ts +0 -2
  751. package/dist/test/provider-waits.test.d.ts.map +0 -1
  752. package/dist/test/provider-waits.test.js +0 -2196
  753. package/dist/test/provider-waits.test.js.map +0 -1
  754. package/dist/test/puppet-tool-call.test.d.ts +0 -2
  755. package/dist/test/puppet-tool-call.test.d.ts.map +0 -1
  756. package/dist/test/puppet-tool-call.test.js +0 -224
  757. package/dist/test/puppet-tool-call.test.js.map +0 -1
  758. package/dist/test/puppet-turn-reservation.test.d.ts +0 -2
  759. package/dist/test/puppet-turn-reservation.test.d.ts.map +0 -1
  760. package/dist/test/puppet-turn-reservation.test.js +0 -139
  761. package/dist/test/puppet-turn-reservation.test.js.map +0 -1
  762. package/dist/test/reaction-baseline-platform.test.d.ts +0 -2
  763. package/dist/test/reaction-baseline-platform.test.d.ts.map +0 -1
  764. package/dist/test/reaction-baseline-platform.test.js +0 -124
  765. package/dist/test/reaction-baseline-platform.test.js.map +0 -1
  766. package/dist/test/record-journal.test.d.ts +0 -6
  767. package/dist/test/record-journal.test.d.ts.map +0 -1
  768. package/dist/test/record-journal.test.js +0 -269
  769. package/dist/test/record-journal.test.js.map +0 -1
  770. package/dist/test/refusal-reaction-baseline.test.d.ts +0 -2
  771. package/dist/test/refusal-reaction-baseline.test.d.ts.map +0 -1
  772. package/dist/test/refusal-reaction-baseline.test.js +0 -81
  773. package/dist/test/refusal-reaction-baseline.test.js.map +0 -1
  774. package/dist/test/refusal-rewind.test.d.ts +0 -2
  775. package/dist/test/refusal-rewind.test.d.ts.map +0 -1
  776. package/dist/test/refusal-rewind.test.js +0 -108
  777. package/dist/test/refusal-rewind.test.js.map +0 -1
  778. package/dist/test/refusal-single-call.test.d.ts +0 -2
  779. package/dist/test/refusal-single-call.test.d.ts.map +0 -1
  780. package/dist/test/refusal-single-call.test.js +0 -177
  781. package/dist/test/refusal-single-call.test.js.map +0 -1
  782. package/dist/test/release-changelog.test.d.ts +0 -2
  783. package/dist/test/release-changelog.test.d.ts.map +0 -1
  784. package/dist/test/release-changelog.test.js +0 -159
  785. package/dist/test/release-changelog.test.js.map +0 -1
  786. package/dist/test/same-round-think-policy.test.d.ts +0 -2
  787. package/dist/test/same-round-think-policy.test.d.ts.map +0 -1
  788. package/dist/test/same-round-think-policy.test.js +0 -853
  789. package/dist/test/same-round-think-policy.test.js.map +0 -1
  790. package/dist/test/save-recent-image.test.d.ts +0 -26
  791. package/dist/test/save-recent-image.test.d.ts.map +0 -1
  792. package/dist/test/save-recent-image.test.js +0 -974
  793. package/dist/test/save-recent-image.test.js.map +0 -1
  794. package/dist/test/shutdown-errors.test.d.ts +0 -2
  795. package/dist/test/shutdown-errors.test.d.ts.map +0 -1
  796. package/dist/test/shutdown-errors.test.js +0 -662
  797. package/dist/test/shutdown-errors.test.js.map +0 -1
  798. package/dist/test/silent-heartbeat-rows.test.d.ts +0 -2
  799. package/dist/test/silent-heartbeat-rows.test.d.ts.map +0 -1
  800. package/dist/test/silent-heartbeat-rows.test.js +0 -451
  801. package/dist/test/silent-heartbeat-rows.test.js.map +0 -1
  802. package/dist/test/silent-heartbeat.test.d.ts +0 -2
  803. package/dist/test/silent-heartbeat.test.d.ts.map +0 -1
  804. package/dist/test/silent-heartbeat.test.js +0 -165
  805. package/dist/test/silent-heartbeat.test.js.map +0 -1
  806. package/dist/test/state-scaling-e2e.test.d.ts +0 -22
  807. package/dist/test/state-scaling-e2e.test.d.ts.map +0 -1
  808. package/dist/test/state-scaling-e2e.test.js +0 -206
  809. package/dist/test/state-scaling-e2e.test.js.map +0 -1
  810. package/dist/test/state-scaling.test.d.ts +0 -12
  811. package/dist/test/state-scaling.test.d.ts.map +0 -1
  812. package/dist/test/state-scaling.test.js +0 -251
  813. package/dist/test/state-scaling.test.js.map +0 -1
  814. package/dist/test/stop-with-work-in-flight.test.d.ts +0 -23
  815. package/dist/test/stop-with-work-in-flight.test.d.ts.map +0 -1
  816. package/dist/test/stop-with-work-in-flight.test.js +0 -672
  817. package/dist/test/stop-with-work-in-flight.test.js.map +0 -1
  818. package/dist/test/surgery-marks-receipt.test.d.ts +0 -2
  819. package/dist/test/surgery-marks-receipt.test.d.ts.map +0 -1
  820. package/dist/test/surgery-marks-receipt.test.js +0 -540
  821. package/dist/test/surgery-marks-receipt.test.js.map +0 -1
  822. package/dist/test/thinking-token-stamp.test.d.ts +0 -12
  823. package/dist/test/thinking-token-stamp.test.d.ts.map +0 -1
  824. package/dist/test/thinking-token-stamp.test.js +0 -129
  825. package/dist/test/thinking-token-stamp.test.js.map +0 -1
  826. package/dist/test/timezone.test.d.ts +0 -2
  827. package/dist/test/timezone.test.d.ts.map +0 -1
  828. package/dist/test/timezone.test.js +0 -18
  829. package/dist/test/timezone.test.js.map +0 -1
  830. package/dist/test/tool-batch-hook.test.d.ts +0 -8
  831. package/dist/test/tool-batch-hook.test.d.ts.map +0 -1
  832. package/dist/test/tool-batch-hook.test.js +0 -275
  833. package/dist/test/tool-batch-hook.test.js.map +0 -1
  834. package/dist/test/tool-policy.test.d.ts +0 -2
  835. package/dist/test/tool-policy.test.d.ts.map +0 -1
  836. package/dist/test/tool-policy.test.js +0 -51
  837. package/dist/test/tool-policy.test.js.map +0 -1
  838. package/dist/test/tool-presentation.test.d.ts +0 -2
  839. package/dist/test/tool-presentation.test.d.ts.map +0 -1
  840. package/dist/test/tool-presentation.test.js +0 -268
  841. package/dist/test/tool-presentation.test.js.map +0 -1
  842. package/dist/test/tool-result-content.test.d.ts +0 -2
  843. package/dist/test/tool-result-content.test.d.ts.map +0 -1
  844. package/dist/test/tool-result-content.test.js +0 -37
  845. package/dist/test/tool-result-content.test.js.map +0 -1
  846. package/dist/test/tool-result-guard.test.d.ts +0 -2
  847. package/dist/test/tool-result-guard.test.d.ts.map +0 -1
  848. package/dist/test/tool-result-guard.test.js +0 -3607
  849. package/dist/test/tool-result-guard.test.js.map +0 -1
  850. package/dist/test/tool-result-history.test.d.ts +0 -7
  851. package/dist/test/tool-result-history.test.d.ts.map +0 -1
  852. package/dist/test/tool-result-history.test.js +0 -156
  853. package/dist/test/tool-result-history.test.js.map +0 -1
  854. package/dist/test/tool-result-spill.test.d.ts +0 -13
  855. package/dist/test/tool-result-spill.test.d.ts.map +0 -1
  856. package/dist/test/tool-result-spill.test.js +0 -586
  857. package/dist/test/tool-result-spill.test.js.map +0 -1
  858. package/dist/test/tool-wrapper-prose-guard-integration.test.d.ts +0 -2
  859. package/dist/test/tool-wrapper-prose-guard-integration.test.d.ts.map +0 -1
  860. package/dist/test/tool-wrapper-prose-guard-integration.test.js +0 -485
  861. package/dist/test/tool-wrapper-prose-guard-integration.test.js.map +0 -1
  862. package/dist/test/tool-wrapper-prose-guard.test.d.ts +0 -2
  863. package/dist/test/tool-wrapper-prose-guard.test.d.ts.map +0 -1
  864. package/dist/test/tool-wrapper-prose-guard.test.js +0 -34
  865. package/dist/test/tool-wrapper-prose-guard.test.js.map +0 -1
  866. package/dist/test/tools-observe-parser-conformance.test.d.ts +0 -2
  867. package/dist/test/tools-observe-parser-conformance.test.d.ts.map +0 -1
  868. package/dist/test/tools-observe-parser-conformance.test.js +0 -129
  869. package/dist/test/tools-observe-parser-conformance.test.js.map +0 -1
  870. package/dist/test/trunk-channel-routing.test.d.ts +0 -19
  871. package/dist/test/trunk-channel-routing.test.d.ts.map +0 -1
  872. package/dist/test/trunk-channel-routing.test.js +0 -329
  873. package/dist/test/trunk-channel-routing.test.js.map +0 -1
  874. package/dist/test/tune-out-e2e.test.d.ts +0 -2
  875. package/dist/test/tune-out-e2e.test.d.ts.map +0 -1
  876. package/dist/test/tune-out-e2e.test.js +0 -142
  877. package/dist/test/tune-out-e2e.test.js.map +0 -1
  878. package/dist/test/tune-out-gate-composition.test.d.ts +0 -2
  879. package/dist/test/tune-out-gate-composition.test.d.ts.map +0 -1
  880. package/dist/test/tune-out-gate-composition.test.js +0 -221
  881. package/dist/test/tune-out-gate-composition.test.js.map +0 -1
  882. package/dist/test/tune-out-lifecycle.test.d.ts +0 -2
  883. package/dist/test/tune-out-lifecycle.test.d.ts.map +0 -1
  884. package/dist/test/tune-out-lifecycle.test.js +0 -121
  885. package/dist/test/tune-out-lifecycle.test.js.map +0 -1
  886. package/dist/test/turn-trigger-provenance.test.d.ts +0 -2
  887. package/dist/test/turn-trigger-provenance.test.d.ts.map +0 -1
  888. package/dist/test/turn-trigger-provenance.test.js +0 -137
  889. package/dist/test/turn-trigger-provenance.test.js.map +0 -1
  890. package/dist/test/unconvertible-tool-result.test.d.ts +0 -2
  891. package/dist/test/unconvertible-tool-result.test.d.ts.map +0 -1
  892. package/dist/test/unconvertible-tool-result.test.js +0 -358
  893. package/dist/test/unconvertible-tool-result.test.js.map +0 -1
  894. package/dist/test/usage-accounting.test.d.ts +0 -2
  895. package/dist/test/usage-accounting.test.d.ts.map +0 -1
  896. package/dist/test/usage-accounting.test.js +0 -13
  897. package/dist/test/usage-accounting.test.js.map +0 -1
  898. package/dist/test/usage-tracker.test.d.ts +0 -2
  899. package/dist/test/usage-tracker.test.d.ts.map +0 -1
  900. package/dist/test/usage-tracker.test.js +0 -129
  901. package/dist/test/usage-tracker.test.js.map +0 -1
  902. package/dist/test/utils-surface.test.d.ts +0 -2
  903. package/dist/test/utils-surface.test.d.ts.map +0 -1
  904. package/dist/test/utils-surface.test.js +0 -145
  905. package/dist/test/utils-surface.test.js.map +0 -1
  906. package/dist/test/workspace-branch-continuation.test.d.ts +0 -15
  907. package/dist/test/workspace-branch-continuation.test.d.ts.map +0 -1
  908. package/dist/test/workspace-branch-continuation.test.js +0 -183
  909. package/dist/test/workspace-branch-continuation.test.js.map +0 -1
  910. package/dist/test/workspace-materialize-freshness.test.d.ts +0 -16
  911. package/dist/test/workspace-materialize-freshness.test.d.ts.map +0 -1
  912. package/dist/test/workspace-materialize-freshness.test.js +0 -252
  913. package/dist/test/workspace-materialize-freshness.test.js.map +0 -1
  914. package/dist/test/workspace-path-containment.test.d.ts +0 -19
  915. package/dist/test/workspace-path-containment.test.d.ts.map +0 -1
  916. package/dist/test/workspace-path-containment.test.js +0 -91
  917. package/dist/test/workspace-path-containment.test.js.map +0 -1
  918. package/dist/test/workspace-read-file-from-disk.test.d.ts +0 -17
  919. package/dist/test/workspace-read-file-from-disk.test.d.ts.map +0 -1
  920. package/dist/test/workspace-read-file-from-disk.test.js +0 -174
  921. package/dist/test/workspace-read-file-from-disk.test.js.map +0 -1
  922. package/dist/test/workspace-read-image.test.d.ts +0 -2
  923. package/dist/test/workspace-read-image.test.d.ts.map +0 -1
  924. package/dist/test/workspace-read-image.test.js +0 -597
  925. package/dist/test/workspace-read-image.test.js.map +0 -1
  926. package/dist/test/workspace-read-text.test.d.ts +0 -2
  927. package/dist/test/workspace-read-text.test.d.ts.map +0 -1
  928. package/dist/test/workspace-read-text.test.js +0 -101
  929. package/dist/test/workspace-read-text.test.js.map +0 -1
  930. package/dist/test/workspace-restore-order.test.d.ts +0 -16
  931. package/dist/test/workspace-restore-order.test.d.ts.map +0 -1
  932. package/dist/test/workspace-restore-order.test.js +0 -140
  933. package/dist/test/workspace-restore-order.test.js.map +0 -1
  934. package/dist/test/workspace-three-way.test.d.ts +0 -12
  935. package/dist/test/workspace-three-way.test.d.ts.map +0 -1
  936. package/dist/test/workspace-three-way.test.js +0 -3194
  937. package/dist/test/workspace-three-way.test.js.map +0 -1
  938. package/dist/test/workspace-watcher.test.d.ts +0 -2
  939. package/dist/test/workspace-watcher.test.d.ts.map +0 -1
  940. package/dist/test/workspace-watcher.test.js +0 -281
  941. package/dist/test/workspace-watcher.test.js.map +0 -1
  942. package/dist/test/xml-round-persist.test.d.ts +0 -19
  943. package/dist/test/xml-round-persist.test.d.ts.map +0 -1
  944. package/dist/test/xml-round-persist.test.js +0 -235
  945. package/dist/test/xml-round-persist.test.js.map +0 -1
  946. package/dist/tsconfig.tsbuildinfo +0 -1
@@ -9,14 +9,45 @@
9
9
  * stdio and WebSocket behave identically above the transport seam.
10
10
  */
11
11
  import { EventEmitter } from 'node:events';
12
- import { openTransport } from './transport.js';
12
+ import { openTransport, STDERR_END_WAIT_MS } from './transport.js';
13
13
  import { maskNegotiatedCapabilities } from './capability-mask.js';
14
14
  import { CapabilityGrant, expandAdvertisementShorthand } from './capability-grant.js';
15
- import { CAPABILITY_DISABLED } from './errors.js';
15
+ import { CAPABILITY_DISABLED, boundedForLog, describeCause } from './errors.js';
16
+ import { logDetail, logValue } from './log-value.js';
16
17
  import { McplMethod } from './types.js';
17
18
  /** Timeout for the initialize handshake in milliseconds.
18
19
  * Spring Boot + JDA servers can take 5-10s to boot, so 30s is safe. */
19
20
  const INITIALIZE_TIMEOUT_MS = 30_000;
21
+ /** A failed connect's `stderrTail`, the last of the server's stderr that its
22
+ * handshake's error keeps, when there is one. */
23
+ export function stderrTailOf(error) {
24
+ const tail = error?.stderrTail;
25
+ return typeof tail === 'string' && tail !== '' ? tail : undefined;
26
+ }
27
+ /** For the host's own log line about a failed connect: the server's stderr
28
+ * that the error keeps as `stderrTail`, one marked line per line of it,
29
+ * each through log-value, since it's the server's text. '' when there's
30
+ * none. */
31
+ export function withStderr(error) {
32
+ const tail = stderrTailOf(error);
33
+ if (tail === undefined)
34
+ return '';
35
+ return '. The last of its stderr:' + tail.split('\n').map((line) => `\n stderr: ${logDetail(line)}`).join('');
36
+ }
37
+ /** A transport close's reason, as an error message gives it: the transport's
38
+ * own words. A WebSocket peer's close reason is the server's text
39
+ * (`reasonFromPeer`), so an error gives the words the transport uses for a
40
+ * close without one, as `mcpl:server-closed` leaves that text out. A
41
+ * WebSocket close's code, a number, says what the server meant (4001: a
42
+ * refused credential), with or without a reason, so each error gives it too:
43
+ * a pending request's error has `code=`, and the handshake's adds it for any
44
+ * WebSocket close, since a close before the handshake completes reaches no
45
+ * 'close' event. A stdio child's exit reads as before. */
46
+ function closeReasonText(info) {
47
+ if (info.reasonFromPeer)
48
+ return 'websocket closed';
49
+ return info.reason ?? 'unknown';
50
+ }
20
51
  /** Default per-request timeout in milliseconds (see McplServerConfig.requestTimeoutMs).
21
52
  * A live-but-wedged server (accepts requests, never answers, never closes its
22
53
  * transport) would otherwise freeze the awaiting agent turn forever — no
@@ -25,6 +56,39 @@ const INITIALIZE_TIMEOUT_MS = 30_000;
25
56
  const DEFAULT_REQUEST_TIMEOUT_MS = 60_000;
26
57
  /** MCP protocol version used in the initialize handshake. */
27
58
  const MCP_PROTOCOL_VERSION = '2024-11-05';
59
+ /**
60
+ * Why a request to an MCPL server produced no result, as far as the host can
61
+ * know it. Messages are unchanged from plain errors; the `outcome` makes the
62
+ * difference between "never left the host" and "left, and no answer came
63
+ * back" a fact a caller can act on instead of a string to match:
64
+ * - `not-sent`: the request was refused before anything was written (the
65
+ * connection was already closed);
66
+ * - `error-response`: the server answered with a JSON-RPC error (it may have
67
+ * acted before failing; the error alone does not say);
68
+ * - `no-response`: the request was handed to the transport and no answer
69
+ * came back (timeout, or the connection closed while awaiting). It does
70
+ * not prove the request reached the server — the transport can decline or
71
+ * drop a write — only that the host can no longer say it didn't.
72
+ */
73
+ export class McplRequestError extends Error {
74
+ outcome;
75
+ data;
76
+ constructor(message, outcome,
77
+ /** The JSON-RPC error's `data`, verbatim, when the server supplied one
78
+ * (e.g. which parts of a multi-part send were posted). */
79
+ data) {
80
+ super(message);
81
+ this.outcome = outcome;
82
+ this.data = data;
83
+ this.name = 'McplRequestError';
84
+ }
85
+ }
86
+ /** A request's method for a log line, whatever the server sent there. */
87
+ function describeMethod(method) {
88
+ return typeof method === 'string'
89
+ ? `method ${logValue(method)}`
90
+ : `a method of type ${method === null ? 'null' : typeof method}`;
91
+ }
28
92
  /**
29
93
  * McplServerConnection manages a single JSON-RPC 2.0 connection to an
30
94
  * MCPL server over stdio. Use the static `connect()` factory to create
@@ -39,8 +103,13 @@ const MCP_PROTOCOL_VERSION = '2024-11-05';
39
103
  * - `'channels-incoming'` — Server sent `channels/incoming`
40
104
  * - `'error'` — Connection-level error
41
105
  * - `'close'` — Connection closed: `(code, signal, info: McplConnectionCloseInfo)`
42
- * - `'connect-failed'` — Initial connect failed; background retry scheduled
43
- * - `'reconnect-failed'` — A background reconnect attempt failed; next retry scheduled
106
+ * - `'connect-failed'` — Initial connect failed; background retry scheduled:
107
+ * `{ error, stderrTail?, attempt }`
108
+ * - `'reconnect-failed'` — A background reconnect attempt failed; next retry scheduled:
109
+ * `{ error, stderrTail?, attempt }`. `stderrTail` is the last of the
110
+ * server's stderr when its handshake failed by its transport closing, a
111
+ * transport error or its timeout and it had written any; `error` never
112
+ * carries it.
44
113
  * - `'reconnect'` — Background reconnect succeeded
45
114
  */
46
115
  export class McplServerConnection extends EventEmitter {
@@ -142,6 +211,9 @@ export class McplServerConnection extends EventEmitter {
142
211
  reconnectPromise = null;
143
212
  /** Per-request timeout in ms (0 disables). See McplServerConfig.requestTimeoutMs. */
144
213
  requestTimeoutMs = DEFAULT_REQUEST_TIMEOUT_MS;
214
+ /** The deadline a channels/publish or channels/open request keeps when
215
+ * requestTimeoutMs is 0 (see sendChannelsPublish). */
216
+ publishDeadlineMs = DEFAULT_REQUEST_TIMEOUT_MS;
145
217
  // Event buffering: control-plane traffic can be released independently from
146
218
  // inference-bearing data-plane traffic. This lets a server finish its own
147
219
  // registration (and answer host tools/call requests) while startup/reconnect
@@ -149,15 +221,24 @@ export class McplServerConnection extends EventEmitter {
149
221
  controlPlaneReady = false;
150
222
  dataPlaneReady = false;
151
223
  bufferedEvents = [];
152
- /** Cap on buffered responder-less events during a plane pause (issue #122).
153
- * Held server→host requests are never dropped and may exceed this. */
154
- static MAX_BUFFERED_EVENTS = 1000;
224
+ /** How many of bufferedEvents are server→host requests, each holding a
225
+ * responder its server waits on. Every change to bufferedEvents keeps it. */
226
+ heldRequests = 0;
227
+ /** Cap on held notifications (responder-less events) during a plane pause
228
+ * (issue #122), counted apart from requests: past it, the oldest held
229
+ * notification is dropped. */
230
+ static MAX_HELD_NOTIFICATIONS = 1000;
231
+ /** Budget of held requests during a plane pause (#387), counted apart from
232
+ * notifications: past it, a request is refused at once, never dropped. It
233
+ * bounds a server that pipelines requests without waiting for answers. A
234
+ * server that doesn't send a refused request again loses it (discord-mcpl
235
+ * doesn't), so the budget sits far above the notifications' cap, to leave
236
+ * a busy server's long pause room. */
237
+ static MAX_HELD_REQUESTS = 10_000;
155
238
  droppedBufferedEvents = 0;
156
- /** True while ready()/readyControlPlane() re-emit a buffer snapshot. Items
157
- * re-buffering mid-flush were already admitted once — applying the cap to
158
- * them again would evict events that were legally held (the cap targets
159
- * NEW arrivals during a pause, not churn from control-plane flushes). */
160
- flushDepth = 0;
239
+ /** Requests refused at the budget since the planes last opened (ready()),
240
+ * so each pause's first refusal is logged. */
241
+ refusedHeldRequests = 0;
161
242
  // Reconnect state (adapted from Anarchid/agent-framework@mcpl-module-proto)
162
243
  config = null;
163
244
  hostCapabilities = null;
@@ -173,6 +254,12 @@ export class McplServerConnection extends EventEmitter {
173
254
  get willReconnect() {
174
255
  return this.reconnectEnabled;
175
256
  }
257
+ /** Closed with no reconnect to come: after close(), whether or not its
258
+ * transport close succeeded, or a drop with reconnect off. A connection
259
+ * between retries keeps reconnectEnabled, so it isn't closed for good. */
260
+ get closedForGood() {
261
+ return this.closed && !this.reconnectEnabled;
262
+ }
176
263
  /**
177
264
  * Private constructor. Use `McplServerConnection.connect()` instead.
178
265
  */
@@ -193,52 +280,60 @@ export class McplServerConnection extends EventEmitter {
193
280
  * Mark the connection as ready — flushes any events that arrived between
194
281
  * construction (when setupMessageRouting starts emitting) and now (when
195
282
  * the caller has attached listeners via wireMcplEvents).
283
+ *
284
+ * Does nothing once the connection is closed for good. Its policy was reset
285
+ * when it closed, so what it held that needs a grant would be refused, and a
286
+ * closed connection sends no response, so nothing it held could be answered.
287
+ * Only what needs no grant would pass, to listeners of a server that won't
288
+ * be served again. A connection between retries isn't closed for good: what
289
+ * it held, such as a reconnect stub's connect-failed, still reaches its
290
+ * listeners.
196
291
  */
197
292
  ready() {
293
+ if (this.closedForGood)
294
+ return;
198
295
  this.controlPlaneReady = true;
199
296
  this.dataPlaneReady = true;
200
297
  const pending = this.bufferedEvents;
201
298
  this.bufferedEvents = [];
299
+ // The cap's drops are counted per pause: this flush ends one, so its line
300
+ // reports that pause's drops, and the next pause counts (and logs) its own.
301
+ const dropped = this.droppedBufferedEvents;
302
+ this.droppedBufferedEvents = 0;
303
+ this.heldRequests = 0;
304
+ this.refusedHeldRequests = 0;
202
305
  if (pending.length > 200) {
203
306
  console.error(`[mcpl] ${this.id}: flushing ${pending.length} buffered event(s) synchronously ` +
204
- `(long pause backlog${this.droppedBufferedEvents > 0 ? `; ${this.droppedBufferedEvents} dropped at cap` : ''})`);
307
+ `(long pause backlog${dropped > 0 ? `; ${dropped} dropped at cap` : ''})`);
205
308
  }
206
- this.flushDepth++;
207
- try {
208
- for (const { event, args } of pending) {
209
- // Re-enter the gate for every buffered item. A control handler (notably
210
- // tools/list_changed) may install a newer data-plane barrier while this
211
- // snapshot is being flushed; later data items must observe that pause.
212
- this.emit(event, ...args);
213
- }
214
- }
215
- finally {
216
- this.flushDepth--;
309
+ for (const { event, args } of pending) {
310
+ // Re-enter the gate for every buffered item. A control handler (notably
311
+ // tools/list_changed) may install a newer data-plane barrier while this
312
+ // snapshot is being flushed; later data items must observe that pause.
313
+ this.dispatchInboundEvent(event, ...args);
217
314
  }
218
315
  }
219
316
  /**
220
317
  * Release only server-establishment and lifecycle/control traffic. Responses
221
318
  * to host requests are never event-buffered, so tools/list and tools/call
222
319
  * responses remain live as well. Inference-bearing requests stay queued in
223
- * their original relative order until {@link ready} is called.
320
+ * their original relative order until {@link ready} is called. Like
321
+ * {@link ready}, it does nothing once the connection is closed for good.
224
322
  */
225
323
  readyControlPlane() {
324
+ if (this.closedForGood)
325
+ return;
226
326
  this.controlPlaneReady = true;
227
327
  const pending = this.bufferedEvents;
228
328
  this.bufferedEvents = [];
229
- this.flushDepth++;
230
- try {
231
- for (const item of pending) {
232
- // Re-enter the ADMISSION gate (this.emit), never super.emit: control
233
- // events include channels-register/changed, which are grant-gated —
234
- // the old direct flush bypassed positive-grant enforcement entirely
235
- // (PR #79 review blocker 3). Data-plane items re-buffer in order via
236
- // the same call, since dataPlaneReady is still false.
237
- this.emit(item.event, ...item.args);
238
- }
239
- }
240
- finally {
241
- this.flushDepth--;
329
+ this.heldRequests = 0;
330
+ for (const item of pending) {
331
+ // Re-enter the ADMISSION gate (this.emit), never super.emit: control
332
+ // events include channels-register/changed, which are grant-gated —
333
+ // the old direct flush bypassed positive-grant enforcement entirely
334
+ // (PR #79 review blocker 3). Data-plane items re-buffer in order via
335
+ // the same call, since dataPlaneReady is still false.
336
+ this.dispatchInboundEvent(item.event, ...item.args);
242
337
  }
243
338
  }
244
339
  /**
@@ -291,41 +386,74 @@ export class McplServerConnection extends EventEmitter {
291
386
  responder.respondError(CAPABILITY_DISABLED, `${name} rejected: capability "${requiredCap}" ${phase}`, { capability: requiredCap });
292
387
  }
293
388
  else {
294
- console.error(`[mcpl] ${this.id}: discarded ${name} — "${requiredCap}" ${phase}`);
389
+ console.error(`[mcpl] ${this.id}: discarded ${logValue(name)} — "${requiredCap}" ${phase}`);
295
390
  }
296
391
  return true;
297
392
  }
393
+ // §6.6: a request that will never be answered MUST get an error. A
394
+ // request whose event nothing on this host listens for would never be.
395
+ const request = args[1];
396
+ if (typeof request?.respondError === 'function' && this.listenerCount(event) === 0) {
397
+ request.respondError(-32601, 'Method not found');
398
+ console.error(`[mcpl] ${this.id}: answered -32601 to ${logValue(name)}, which nothing on this host handles`);
399
+ return true;
400
+ }
401
+ // mcpl/manifestChanged (§17.3) and tools/list_changed are notifications.
402
+ // Sent as a request, either is answered with an empty result as it's
403
+ // admitted, and passed on as the notification is, with no responder:
404
+ // the host acts on it the same way, so the answer doesn't depend on what
405
+ // the refresh does, and it's written before any request the refresh
406
+ // sends. This is where live routing and buffer flushes meet, so a request
407
+ // held while its plane is closed is answered only when it's let through,
408
+ // never by a startup that fails first.
409
+ if ((name === 'manifest-changed' || name === 'tools-list-changed') && typeof request?.respond === 'function') {
410
+ request.respond({});
411
+ return super.emit(event, args[0]);
412
+ }
298
413
  return super.emit(event, ...args);
299
414
  }
300
- // Buffer cap (issue #122): a long data-plane pause (quiesce window) on a
301
- // busy server would otherwise grow this array without bound. Only
302
- // responder-LESS events are ever dropped — a buffered server→host REQUEST
303
- // holds a live responder the server is blocking on, and dropping it would
304
- // strand that call forever (the server timing out and reconnecting is the
305
- // accepted bound there, and reconnect re-runs the barrier funnel).
306
- if (this.flushDepth === 0 && this.bufferedEvents.length >= McplServerConnection.MAX_BUFFERED_EVENTS) {
307
- const hasResponder = (item) => {
308
- const responder = item.args[1];
309
- return typeof responder?.respond === 'function';
310
- };
311
- if (!hasResponder({ args })) {
312
- this.droppedBufferedEvents++;
313
- if (this.droppedBufferedEvents % 100 === 1) {
314
- console.error(`[mcpl] ${this.id}: buffered-event cap (${McplServerConnection.MAX_BUFFERED_EVENTS}) — ` +
315
- `dropped ${this.droppedBufferedEvents} responder-less event(s) while the plane is paused`);
316
- }
317
- const dropIndex = this.bufferedEvents.findIndex((item) => !hasResponder(item));
318
- if (dropIndex >= 0) {
319
- this.bufferedEvents.splice(dropIndex, 1); // drop-oldest non-request
320
- this.bufferedEvents.push({ event: name, args });
321
- }
322
- // else: buffer is all held requests — drop the incoming event instead.
323
- return true;
415
+ // Held until the plane opens. A long pause (a quiesce, say) on a busy or a
416
+ // runaway server would otherwise grow this array without bound, so
417
+ // requests and notifications each have a bound, counted apart. A request
418
+ // holds a responder its server waits on, and dropping it would strand that
419
+ // call, so past MAX_HELD_REQUESTS (#387) it's refused at once with -32000,
420
+ // the code of the host's other transient refusals, and its server can send
421
+ // it again. A notification has no one to tell, so past
422
+ // MAX_HELD_NOTIFICATIONS (issue #122) the oldest held notification is
423
+ // dropped to make room. A flush takes the whole buffer and zeroes its
424
+ // count, so what it holds again was admitted within these bounds and
425
+ // stays within them.
426
+ const responder = args[1];
427
+ const isRequest = McplServerConnection.hasResponder({ args });
428
+ if (isRequest && this.heldRequests >= McplServerConnection.MAX_HELD_REQUESTS) {
429
+ this.refusedHeldRequests++;
430
+ if (this.refusedHeldRequests % 100 === 1) {
431
+ console.error(`[mcpl] ${this.id}: held-request budget (${McplServerConnection.MAX_HELD_REQUESTS}) — ` +
432
+ `refused ${this.refusedHeldRequests} request(s) with -32000 while the plane is paused`);
433
+ }
434
+ responder?.respondError?.(-32000, `the host is busy: ${McplServerConnection.MAX_HELD_REQUESTS} of this server's requests are already waiting; send this one again later`);
435
+ return true;
436
+ }
437
+ if (!isRequest && this.bufferedEvents.length - this.heldRequests >= McplServerConnection.MAX_HELD_NOTIFICATIONS) {
438
+ this.droppedBufferedEvents++;
439
+ if (this.droppedBufferedEvents % 100 === 1) {
440
+ console.error(`[mcpl] ${this.id}: buffered-event cap (${McplServerConnection.MAX_HELD_NOTIFICATIONS}) — ` +
441
+ `dropped ${this.droppedBufferedEvents} responder-less event(s) while the plane is paused`);
324
442
  }
443
+ const oldest = this.bufferedEvents.findIndex((item) => !McplServerConnection.hasResponder(item));
444
+ if (oldest >= 0)
445
+ this.bufferedEvents.splice(oldest, 1);
325
446
  }
326
447
  this.bufferedEvents.push({ event: name, args });
448
+ if (isRequest)
449
+ this.heldRequests++;
327
450
  return true;
328
451
  }
452
+ /** A buffered server→host request: it carries a responder its server waits on. */
453
+ static hasResponder(item) {
454
+ const responder = item.args[1];
455
+ return typeof responder?.respond === 'function';
456
+ }
329
457
  /** Event-name form of METHOD_TO_REQUIRED_CAPABILITY, for admission-time
330
458
  * enforcement in emit(). */
331
459
  static EVENT_TO_REQUIRED_CAPABILITY = {
@@ -383,8 +511,9 @@ export class McplServerConnection extends EventEmitter {
383
511
  connection.mcpToolsAdvertised = mcpToolsAdvertised;
384
512
  connection.allowHostCommands = config.allowHostCommands === true;
385
513
  connection.requestTimeoutMs = config.requestTimeoutMs ?? DEFAULT_REQUEST_TIMEOUT_MS;
386
- // Store config for reconnection
387
- if (config.reconnect) {
514
+ // Store config for reconnection. Only `true` turns reconnect on, as at
515
+ // every other reader of it.
516
+ if (config.reconnect === true) {
388
517
  connection.config = config;
389
518
  connection.hostCapabilities = hostCapabilities;
390
519
  connection.reconnectEnabled = true;
@@ -402,6 +531,15 @@ export class McplServerConnection extends EventEmitter {
402
531
  */
403
532
  static async handshake(config, hostCapabilities) {
404
533
  const transport = await openTransport(config);
534
+ // Once the handshake stops listening for 'error', this logs what the
535
+ // transport reports, until the handshake hands the transport on, or for
536
+ // good if the handshake fails. EventEmitter throws an 'error' that has no
537
+ // listener, and from an I/O callback nothing catches it. A malformed
538
+ // WebSocket frame that arrives with the initialize response, or while a
539
+ // failed handshake's close() runs, is such an error.
540
+ const logAfterSettled = (err) => {
541
+ console.error(`[mcpl] ${config.id}: transport error after the handshake settled: ${err.message}`);
542
+ };
405
543
  try {
406
544
  const initId = 0; // use id=0 for the handshake
407
545
  const initRequest = {
@@ -417,10 +555,20 @@ export class McplServerConnection extends EventEmitter {
417
555
  // Await the initialize response, racing an early transport close/error and
418
556
  // a timeout. All three paths clean up their listeners.
419
557
  const { mcpl: rawCapabilities, mcpToolsAdvertised } = await new Promise((resolve, reject) => {
558
+ // When the transport fails, the end of the server's stderr often says
559
+ // why, such as a missing token or a crash at startup. It goes on the
560
+ // error as `stderrTail`, never into the message: an error's message
561
+ // travels to traces and tool results, and a server's stderr is its
562
+ // own text, which can hold a credential.
563
+ const failed = (failure) => {
564
+ const tail = transport.stderrTail.trimEnd();
565
+ return Object.assign(new Error(failure), tail ? { stderrTail: tail } : {});
566
+ };
420
567
  const cleanup = () => {
421
568
  transport.off('line', onLine);
422
569
  transport.off('close', onClose);
423
570
  transport.off('error', onError);
571
+ transport.on('error', logAfterSettled);
424
572
  clearTimeout(timer);
425
573
  };
426
574
  const onLine = (line) => {
@@ -431,11 +579,32 @@ export class McplServerConnection extends EventEmitter {
431
579
  catch {
432
580
  return; // Ignore non-JSON lines (e.g. logback output from Java servers)
433
581
  }
582
+ if (msg === null || typeof msg !== 'object' || Array.isArray(msg))
583
+ return;
584
+ // A request or a notification from the server is never the
585
+ // initialize response, whatever its id: a server's own ids can start
586
+ // at 0, this handshake's. MCP lets a server ping before
587
+ // initialization completes, and the ping gets its empty result, as
588
+ // on a connected transport. Anything else it sends now is ignored.
589
+ if ('method' in msg) {
590
+ const request = msg;
591
+ if (request.method === 'ping' && request.id != null) {
592
+ transport.writeLine(JSON.stringify({ jsonrpc: '2.0', id: request.id, result: {} }));
593
+ }
594
+ return;
595
+ }
434
596
  if (msg.id !== initId)
435
597
  return;
436
598
  cleanup();
437
599
  if (msg.error) {
438
- reject(new Error(`MCPL server "${config.id}" initialize error: ${msg.error.message}`));
600
+ // describeCause rather than the template's own conversion: the
601
+ // server's `message` can be any JSON value, and one that has no
602
+ // primitive form, such as {"toString":1}, would throw out of this
603
+ // listener after cleanup() has cleared the timeout: an uncaught
604
+ // exception, which ends a host that doesn't catch them, and a
605
+ // handshake left to wait forever. It's the server's text in an
606
+ // error's message, so it's bounded as errors.ts says.
607
+ reject(new Error(`MCPL server "${config.id}" initialize error: ${boundedForLog(describeCause(msg.error.message))}`));
439
608
  return;
440
609
  }
441
610
  const result = msg.result;
@@ -451,15 +620,22 @@ export class McplServerConnection extends EventEmitter {
451
620
  };
452
621
  const onClose = (info) => {
453
622
  cleanup();
454
- reject(new Error(`MCPL server "${config.id}" transport closed before handshake completed (${info.reason ?? 'unknown'})`));
623
+ const code = transport.kind === 'websocket' && typeof info.code === 'number' ? `, code ${info.code}` : '';
624
+ const failure = `MCPL server "${config.id}" transport closed before handshake completed (${closeReasonText(info)}${code})`;
625
+ // The close comes at a stdio child's exit, which Node can emit before
626
+ // it has read the last of the child's stderr, or when the host closes
627
+ // the transport, which then ends the child. The tail is taken once
628
+ // stderr has ended, waiting at most STDERR_END_WAIT_MS. A WebSocket
629
+ // transport has no stderr to wait for.
630
+ void transport.stderrEnded(STDERR_END_WAIT_MS).then(() => reject(failed(failure)));
455
631
  };
456
632
  const onError = (err) => {
457
633
  cleanup();
458
- reject(new Error(`MCPL server "${config.id}" transport error during handshake: ${err.message}`));
634
+ reject(failed(`MCPL server "${config.id}" transport error during handshake: ${err.message}`));
459
635
  };
460
636
  const timer = setTimeout(() => {
461
637
  cleanup();
462
- reject(new Error(`MCPL server "${config.id}" initialize handshake timed out`));
638
+ reject(failed(`MCPL server "${config.id}" initialize handshake timed out`));
463
639
  }, INITIALIZE_TIMEOUT_MS);
464
640
  transport.on('line', onLine);
465
641
  transport.on('close', onClose);
@@ -478,8 +654,12 @@ export class McplServerConnection extends EventEmitter {
478
654
  // had never been advertised (hooks, streaming, queries all read this).
479
655
  const { capabilities: scoped, dropped } = maskNegotiatedCapabilities(capabilities, config);
480
656
  if (dropped.length > 0) {
481
- console.error(`MCPL server "${config.id}" capabilities masked by host config: ${dropped.join(', ')}`);
657
+ console.error(`MCPL server "${config.id}" capabilities masked by host config: ${dropped.map(logValue).join(', ')}`);
482
658
  }
659
+ // The caller wires the transport, or keeps it for close() with a
660
+ // listener of its own, in the continuation of this return, before any
661
+ // I/O callback can emit.
662
+ transport.off('error', logAfterSettled);
483
663
  return { transport, capabilities: scoped, droppedCapabilities: new Set(dropped), mcpToolsAdvertised };
484
664
  }
485
665
  catch (err) {
@@ -499,16 +679,17 @@ export class McplServerConnection extends EventEmitter {
499
679
  return await McplServerConnection.connect(config, hostCapabilities);
500
680
  }
501
681
  catch (error) {
502
- if (!config.reconnect) {
682
+ if (config.reconnect !== true) {
503
683
  throw error;
504
684
  }
505
685
  // Non-blocking start: create a disconnected stub that will reconnect in background
506
- console.error(`MCPL server "${config.id}" initial connect failed, will retry:`, error.message);
686
+ console.error(`MCPL server "${config.id}" initial connect failed, will retry: ${error.message}${withStderr(error)}`);
507
687
  const stub = McplServerConnection.createDisconnectedStub(config, hostCapabilities);
508
688
  // Surface the initial failure. The event is buffered by the emit()
509
689
  // override until the host wires listeners and calls ready(), so it is
510
690
  // not lost in the window before wireMcplEvents runs.
511
- stub.emit('connect-failed', { error: error.message, attempt: 0 });
691
+ const stderrTail = stderrTailOf(error);
692
+ stub.emit('connect-failed', { error: error.message, ...(stderrTail ? { stderrTail } : {}), attempt: 0 });
512
693
  return stub;
513
694
  }
514
695
  }
@@ -587,9 +768,13 @@ export class McplServerConnection extends EventEmitter {
587
768
  sendStateRollback(params) {
588
769
  return this.sendRequest(McplMethod.StateRollback, params);
589
770
  }
590
- /** Send `channels/open` request and await result. */
771
+ /** Send `channels/open` request and await result. It keeps a deadline as
772
+ * channels/publish does: a delivery opens a closed channel before it
773
+ * publishes, so an open that is never answered would hold the delivery,
774
+ * and the turn that waits for it, for good. */
591
775
  sendChannelsOpen(params) {
592
- return this.sendRequest(McplMethod.ChannelsOpen, params);
776
+ const timeoutMs = this.requestTimeoutMs > 0 ? this.requestTimeoutMs : this.publishDeadlineMs;
777
+ return this.sendRequest(McplMethod.ChannelsOpen, params, { timeoutMs });
593
778
  }
594
779
  /** Send `channels/close` request and await result. */
595
780
  sendChannelsClose(params) {
@@ -607,13 +792,20 @@ export class McplServerConnection extends EventEmitter {
607
792
  * Send `channels/publish`.
608
793
  * May be sent as a request (if an ACK is desired) or notification.
609
794
  * When `params.stream` is true, sends as a notification (no ACK).
795
+ *
796
+ * A request always has a deadline: the server's requestTimeoutMs, or
797
+ * publishDeadlineMs when that is 0 (disabled). A publish is a side effect
798
+ * whose outcome the resident is told and a held draft's attempt records,
799
+ * so one that is never answered would hold both open for good. Its expiry
800
+ * is a no-response, which the caller reads as unknown.
610
801
  */
611
802
  sendChannelsPublish(params) {
612
803
  if (params.stream) {
613
804
  this.sendNotification(McplMethod.ChannelsPublish, params);
614
805
  return Promise.resolve();
615
806
  }
616
- return this.sendRequest(McplMethod.ChannelsPublish, params);
807
+ const timeoutMs = this.requestTimeoutMs > 0 ? this.requestTimeoutMs : this.publishDeadlineMs;
808
+ return this.sendRequest(McplMethod.ChannelsPublish, params, { timeoutMs });
617
809
  }
618
810
  /** Send `channels/outgoing/chunk` notification. */
619
811
  sendChannelsOutgoingChunk(params) {
@@ -689,7 +881,7 @@ export class McplServerConnection extends EventEmitter {
689
881
  for (const [id, pending] of this.pendingRequests) {
690
882
  if (pending.timer)
691
883
  clearTimeout(pending.timer);
692
- pending.reject(new Error(`Connection to MCPL server "${this.id}" closed while awaiting response for ${pending.method} (id=${id})`));
884
+ pending.reject(new McplRequestError(`Connection to MCPL server "${this.id}" closed while awaiting response for ${pending.method} (id=${id})`, 'no-response'));
693
885
  }
694
886
  this.pendingRequests.clear();
695
887
  this.orphanedRequests.clear();
@@ -699,7 +891,8 @@ export class McplServerConnection extends EventEmitter {
699
891
  const attempt = Promise.resolve().then(async () => {
700
892
  // An already opened handshake owns a transport too. It hands that
701
893
  // transport back without admission once reconnect has been disabled.
702
- // The registry bounds this wait; retry reuses this real close attempt.
894
+ // Only the registry's closeAll bounds its caller's wait for this; retry
895
+ // reuses this real close attempt.
703
896
  if (this.reconnectPromise)
704
897
  await this.reconnectPromise;
705
898
  if (this.transport)
@@ -797,6 +990,13 @@ export class McplServerConnection extends EventEmitter {
797
990
  // The prior transport was disconnected before this retry began. Keep
798
991
  // the fresh, unadmitted transport owned by close(), including on a
799
992
  // failed transport cleanup, instead of reviving a stopped connection.
993
+ // It isn't wired, and the handshake has removed its own listeners, so
994
+ // an error it reports from here on, such as a malformed frame from a
995
+ // WebSocket server while close() closes it, is logged here rather than
996
+ // thrown where nothing catches it.
997
+ transport.on('error', (err) => {
998
+ console.error(`[mcpl] ${this.id}: a transport kept for close() reported an error: ${err.message}`);
999
+ });
800
1000
  this.transport = transport;
801
1001
  return;
802
1002
  }
@@ -820,9 +1020,10 @@ export class McplServerConnection extends EventEmitter {
820
1020
  this.emit('reconnect', { attempts: attempt });
821
1021
  }
822
1022
  catch (error) {
823
- console.error(`MCPL server "${this.id}" reconnect failed:`, error.message);
1023
+ console.error(`MCPL server "${this.id}" reconnect failed: ${error.message}${withStderr(error)}`);
824
1024
  this.reconnectAttempts = attempt + 1;
825
- this.emit('reconnect-failed', { error: error.message, attempt });
1025
+ const stderrTail = stderrTailOf(error);
1026
+ this.emit('reconnect-failed', { error: error.message, ...(stderrTail ? { stderrTail } : {}), attempt });
826
1027
  this.scheduleReconnect();
827
1028
  }
828
1029
  }
@@ -842,7 +1043,7 @@ export class McplServerConnection extends EventEmitter {
842
1043
  */
843
1044
  sendRequest(method, params, options = {}) {
844
1045
  if (this.closed) {
845
- return Promise.reject(new Error(`Cannot send request: connection to "${this.id}" is closed`));
1046
+ return Promise.reject(new McplRequestError(`Cannot send request: connection to "${this.id}" is closed`, 'not-sent'));
846
1047
  }
847
1048
  const id = this.nextRequestId++;
848
1049
  const request = {
@@ -858,22 +1059,44 @@ export class McplServerConnection extends EventEmitter {
858
1059
  pending.timer = setTimeout(() => {
859
1060
  this.pendingRequests.delete(id);
860
1061
  if (options.surfaceOrphanedResponse) {
861
- this.orphanedRequests.set(id, { method, ...(method === 'push/render' ? { renderParams: { featureSet: params.featureSet, key: params.key, eventId: params.eventId } } : {}) });
1062
+ this.orphanedRequests.set(id, {
1063
+ method,
1064
+ ...(method === 'push/render'
1065
+ ? {
1066
+ renderParams: {
1067
+ featureSet: params.featureSet,
1068
+ key: params.key,
1069
+ eventId: params.eventId,
1070
+ ...(typeof params.channelId === 'string' ? { channelId: params.channelId } : {}),
1071
+ },
1072
+ }
1073
+ : {}),
1074
+ });
862
1075
  if (this.orphanedRequests.size > 4096)
863
1076
  this.orphanedRequests.delete(this.orphanedRequests.keys().next().value);
864
1077
  }
865
- reject(new Error(`MCPL server "${this.id}" did not respond to ${method} (id=${id}) ` +
1078
+ reject(new McplRequestError(`MCPL server "${this.id}" did not respond to ${method} (id=${id}) ` +
866
1079
  `within ${timeoutMs}ms — the server may be hung. The response ` +
867
1080
  `outcome is unknown: the request was abandoned locally but was not ` +
868
1081
  `cancelled, so the tool may still have completed server-side; verify ` +
869
1082
  `state before retrying; a blind retry of a stateful/side-effecting ` +
870
- `tool may duplicate it.`));
1083
+ `tool may duplicate it.`, 'no-response'));
871
1084
  }, timeoutMs);
872
1085
  // Don't hold the event loop open for the watchdog alone.
873
1086
  pending.timer.unref?.();
874
1087
  }
875
1088
  this.pendingRequests.set(id, pending);
876
- this.transport.writeLine(JSON.stringify(request));
1089
+ try {
1090
+ this.transport.writeLine(JSON.stringify(request));
1091
+ }
1092
+ catch (err) {
1093
+ // A synchronous write rejection sent no request. Remove its pending
1094
+ // state and watchdog before reporting that it is safe to retry.
1095
+ this.pendingRequests.delete(id);
1096
+ if (pending.timer)
1097
+ clearTimeout(pending.timer);
1098
+ reject(new McplRequestError(`Cannot send ${method} to MCPL server "${this.id}": ${err instanceof Error ? err.message : String(err)}`, 'not-sent'));
1099
+ }
877
1100
  });
878
1101
  }
879
1102
  /**
@@ -957,7 +1180,9 @@ export class McplServerConnection extends EventEmitter {
957
1180
  this.setupLifecycle(transport);
958
1181
  // Surface transport diagnostics (stdio child stderr) as 'stderr' events,
959
1182
  // preserving the `{ line }` payload existing consumers expect.
960
- transport.on('stderr', (line) => this.emit('stderr', { line }));
1183
+ // Through the same containment boundary as every inbound event, so a
1184
+ // stderr listener that throws is reported, not thrown into the transport.
1185
+ transport.on('stderr', (line) => this.dispatchInboundEvent('stderr', { line }));
961
1186
  }
962
1187
  /**
963
1188
  * Wire up the transport's line stream to route incoming JSON-RPC messages.
@@ -972,57 +1197,142 @@ export class McplServerConnection extends EventEmitter {
972
1197
  // Ignore non-JSON lines
973
1198
  return;
974
1199
  }
975
- // Is this a response to one of our outbound requests?
976
- if ('id' in msg && msg.id != null && !('method' in msg)) {
977
- this.handleResponse(msg);
1200
+ // JSON-RPC messages must be objects. Ignore unrelated stdout/log values
1201
+ // before property access, just as malformed JSON lines are ignored.
1202
+ if (msg === null || typeof msg !== 'object' || Array.isArray(msg))
978
1203
  return;
1204
+ try {
1205
+ this.dispatchMessage(msg);
979
1206
  }
980
- // It is an inbound request or notification from the server
981
- const request = msg;
982
- const eventName = McplServerConnection.METHOD_TO_EVENT[request.method];
983
- // §7 is removed in 0.5.0: scope/elevate is no longer a method. Answer
984
- // rather than hang (§6.6 — a method that will never be answered MUST
985
- // return an error).
986
- // featureSets/changed is REMOVED in 0.5.0 (§6.7 — it carried a
987
- // server-authored change payload, the self-attestation defect; the
988
- // need is met by §17's host-diffed manifest fetch). It was still
989
- // routed, control-plane classified, and mutating declarations — a
990
- // live ungated self-attestation path (PR #79 review blocker 4).
991
- if (request.method === McplMethod.FeatureSetsChanged) {
992
- if (request.id != null) {
993
- this.sendErrorResponse(request.id, -32601, 'featureSets/changed removed in MCPL 0.5.0 (superseded by mcpl/manifestChanged, SPEC §17)');
994
- }
995
- else {
996
- console.error(`[mcpl] ${this.id}: discarded featureSets/changed — removed in 0.5.0 (§6.7/§17)`);
997
- }
998
- return;
1207
+ catch (error) {
1208
+ const request = msg;
1209
+ this.reportInboundFailure(error, {
1210
+ ...(typeof request.method === 'string' ? { event: request.method } : {}),
1211
+ ...(typeof request.id === 'string' || typeof request.id === 'number' ? { requestId: request.id } : {}),
1212
+ });
999
1213
  }
1000
- if (request.method === McplMethod.ScopeElevate) {
1001
- if (request.id != null) {
1002
- this.sendErrorResponse(request.id, -32601, 'scope/elevate removed in MCPL 0.5.0 (SPEC §7)');
1003
- }
1004
- return;
1214
+ });
1215
+ }
1216
+ /** Contain synchronous dispatch failures; async RPC handlers own their promises. */
1217
+ dispatchMessage(msg) {
1218
+ // Is this a response to one of our outbound requests?
1219
+ if ('id' in msg && msg.id != null && !('method' in msg)) {
1220
+ this.handleResponse(msg);
1221
+ return;
1222
+ }
1223
+ // It is an inbound request or notification from the server
1224
+ const request = msg;
1225
+ // MCP's ping, which either side may send: its receiver answers promptly
1226
+ // with an empty result. It's answered as it arrives, before admission and
1227
+ // buffering, since it asks only whether the connection is alive, and a
1228
+ // paused plane mustn't hold that answer. A ping sent as a notification
1229
+ // has nothing to answer. The handshake answers one too.
1230
+ if (request.method === 'ping') {
1231
+ if (request.id != null)
1232
+ this.sendResponse(request.id, {});
1233
+ return;
1234
+ }
1235
+ const eventName = typeof request.method === 'string' && Object.hasOwn(McplServerConnection.METHOD_TO_EVENT, request.method)
1236
+ ? McplServerConnection.METHOD_TO_EVENT[request.method] : undefined;
1237
+ // §7 is removed in 0.5.0: scope/elevate is no longer a method. Answer
1238
+ // rather than hang (§6.6 — a method that will never be answered MUST
1239
+ // return an error).
1240
+ // featureSets/changed is REMOVED in 0.5.0 (§6.7 — it carried a
1241
+ // server-authored change payload, the self-attestation defect; the
1242
+ // need is met by §17's host-diffed manifest fetch). It was still
1243
+ // routed, control-plane classified, and mutating declarations — a
1244
+ // live ungated self-attestation path (PR #79 review blocker 4).
1245
+ if (request.method === McplMethod.FeatureSetsChanged) {
1246
+ if (request.id != null) {
1247
+ this.sendErrorResponse(request.id, -32601, 'featureSets/changed removed in MCPL 0.5.0 (superseded by mcpl/manifestChanged, SPEC §17)');
1005
1248
  }
1006
- // Positive-grant enforcement (§5.4, §14.1) happens at ADMISSION, in
1007
- // the emit() override below — the one choke-point that live routing
1008
- // and staged-buffer flushes share. See the comment there for why
1009
- // rejecting here, at line receipt, was wrong for staged connections.
1010
- if (eventName) {
1011
- // Emit the typed event with params and (for requests) a respond callback
1012
- if (request.id != null) {
1013
- // Server expects a response — provide a respond helper
1014
- this.emit(eventName, request.params, {
1015
- id: request.id,
1016
- respond: (result) => this.sendResponse(request.id, result),
1017
- respondError: (code, message, data) => this.sendErrorResponse(request.id, code, message, data),
1018
- });
1019
- }
1020
- else {
1021
- // Notification — no response expected
1022
- this.emit(eventName, request.params);
1023
- }
1249
+ else {
1250
+ console.error(`[mcpl] ${this.id}: discarded featureSets/changed — removed in 0.5.0 (§6.7/§17)`);
1024
1251
  }
1025
- });
1252
+ return;
1253
+ }
1254
+ if (request.method === McplMethod.ScopeElevate) {
1255
+ if (request.id != null) {
1256
+ this.sendErrorResponse(request.id, -32601, 'scope/elevate removed in MCPL 0.5.0 (SPEC §7)');
1257
+ }
1258
+ return;
1259
+ }
1260
+ // Positive-grant enforcement (§5.4, §14.1) happens at ADMISSION, in
1261
+ // the emit() override below — the one choke-point that live routing
1262
+ // and staged-buffer flushes share. See the comment there for why
1263
+ // rejecting here, at line receipt, was wrong for staged connections.
1264
+ if (!eventName) {
1265
+ // §6.6: a request that will never be answered MUST get an error, so a
1266
+ // request (it has an id) whose method isn't a string, or isn't one this
1267
+ // host handles, is answered -32601. A notification nobody handles is
1268
+ // ignored, as JSON-RPC asks.
1269
+ if (request.id != null) {
1270
+ this.sendErrorResponse(request.id, -32601, 'Method not found');
1271
+ console.error(`[mcpl] ${this.id}: answered -32601 to a request for ${describeMethod(request.method)}, which this host doesn't handle`);
1272
+ }
1273
+ return;
1274
+ }
1275
+ // Emit the typed event with params and (for requests) a respond callback
1276
+ if (request.id != null) {
1277
+ // Server expects a response — provide a respond helper
1278
+ this.dispatchInboundEvent(eventName, request.params, {
1279
+ id: request.id,
1280
+ respond: (result) => this.sendResponse(request.id, result),
1281
+ respondError: (code, message, data) => this.sendErrorResponse(request.id, code, message, data),
1282
+ });
1283
+ }
1284
+ else {
1285
+ // Notification — no response expected
1286
+ this.dispatchInboundEvent(eventName, request.params);
1287
+ }
1288
+ }
1289
+ /** Live delivery and delayed plane flushes share the same containment boundary. */
1290
+ dispatchInboundEvent(event, ...args) {
1291
+ try {
1292
+ this.emit(event, ...args);
1293
+ }
1294
+ catch (error) {
1295
+ const requestId = args[1]?.id;
1296
+ this.reportInboundFailure(error, {
1297
+ event,
1298
+ ...(typeof requestId === 'string' || typeof requestId === 'number' ? { requestId } : {}),
1299
+ });
1300
+ }
1301
+ }
1302
+ /** Report a failure the containment boundary caught, naming the event (or
1303
+ * method) and request it was dispatching, and what failed. The message is
1304
+ * what the framework's 'error' listener traces. */
1305
+ reportInboundFailure(cause, context = {}) {
1306
+ const where = (show) => (context.event === undefined ? '' : ` for ${show(context.event)}`) +
1307
+ (context.requestId === undefined ? '' : ` (request ${show(String(context.requestId))})`);
1308
+ // The error's message is what the 'error' listener traces, as text a
1309
+ // reader parses, so it is bounded rather than escaped (boundedForLog);
1310
+ // the log line prints the same through log-value.
1311
+ const error = new Error(`MCPL server "${this.id}" inbound dispatch failed${where(boundedForLog)}: ${boundedForLog(describeCause(cause))}`, { cause });
1312
+ console.error(`[mcpl] ${this.id}: inbound dispatch failed${where(logValue)}: ${logDetail(describeCause(cause))}`);
1313
+ this.emitToErrorListeners(error);
1314
+ }
1315
+ /**
1316
+ * Give an error to the connection's 'error' listeners, and say whether it
1317
+ * has any. EventEmitter throws an 'error' that nothing listens for, and
1318
+ * from a transport's callback, where these errors arise, nothing catches
1319
+ * that throw, so it ends the process. A bare connection has no listener:
1320
+ * the class is exported, and a probe, a playtest or a harness often attaches
1321
+ * none. So with no listener, the error is the caller's to log, unless it
1322
+ * already has. A listener that throws is caught and logged, with the error
1323
+ * it was handling.
1324
+ */
1325
+ emitToErrorListeners(error) {
1326
+ if (this.listenerCount('error') === 0)
1327
+ return false;
1328
+ try {
1329
+ this.emit('error', error);
1330
+ }
1331
+ catch (listenerError) {
1332
+ console.error(`[mcpl] ${this.id}: an 'error' listener failed: ${logDetail(describeCause(listenerError))}` +
1333
+ `, handling ${logDetail(error.message)}`);
1334
+ }
1335
+ return true;
1026
1336
  }
1027
1337
  /**
1028
1338
  * Handle a JSON-RPC response by resolving/rejecting the corresponding pending request.
@@ -1038,10 +1348,17 @@ export class McplServerConnection extends EventEmitter {
1038
1348
  // re-inject either result because the original dispatch context is gone.
1039
1349
  const orphaned = this.orphanedRequests.get(response.id);
1040
1350
  this.orphanedRequests.delete(response.id);
1041
- if (orphaned?.renderParams) {
1042
- this.emit('orphaned-render-response', { params: orphaned.renderParams, result: response.result, error: response.error });
1043
- return; // audit only: a timeout fallback can never be replaced
1044
- }
1351
+ // A push/render answered after its timeout (RFC-006 §5.3) is reported
1352
+ // with the render's featureSet, key, eventId and, for a channel-scoped
1353
+ // subject, channelId, kept from its request when the timeout fired, so
1354
+ // its discarded answer can be recorded beside its batch's other
1355
+ // coalescing records (§11). It is only reported: the fallback the
1356
+ // timeout materialized stands (§5.4 rule 3). A late JSON-RPC error is
1357
+ // passed on as `error`, so its record can be told from a late result's,
1358
+ // and so is one beside a result, which JSON-RPC forbids: the live path
1359
+ // rejects such an answer as an error.
1360
+ const render = orphaned?.renderParams ?? {};
1361
+ const failure = response.error ? { error: { code: response.error.code, message: response.error.message } } : {};
1045
1362
  const result = response.result;
1046
1363
  if (result && typeof result === 'object') {
1047
1364
  const r = result;
@@ -1051,6 +1368,8 @@ export class McplServerConnection extends EventEmitter {
1051
1368
  method: orphaned?.method,
1052
1369
  hadState: r.state !== undefined,
1053
1370
  hadCheckpoint: r.checkpoint !== undefined,
1371
+ ...render,
1372
+ ...failure,
1054
1373
  });
1055
1374
  }
1056
1375
  }
@@ -1060,6 +1379,8 @@ export class McplServerConnection extends EventEmitter {
1060
1379
  method: orphaned.method,
1061
1380
  hadState: false,
1062
1381
  hadCheckpoint: false,
1382
+ ...render,
1383
+ ...failure,
1063
1384
  });
1064
1385
  }
1065
1386
  return; // Orphaned response — ignore
@@ -1068,7 +1389,14 @@ export class McplServerConnection extends EventEmitter {
1068
1389
  if (pending.timer)
1069
1390
  clearTimeout(pending.timer);
1070
1391
  if (response.error) {
1071
- pending.reject(new Error(`MCPL server "${this.id}" returned error for ${pending.method}: [${response.error.code}] ${response.error.message}`));
1392
+ // describeCause rather than the template's own conversion, as for an
1393
+ // initialize error: the server's code and message can be any JSON
1394
+ // value, and one with no primitive form, such as {"toString":1}, would
1395
+ // throw here, after the request has left pendingRequests and its timer
1396
+ // is cleared, so it would never settle. Both are the server's text, a
1397
+ // code as much as a message, since a server can send a string, so both
1398
+ // are bounded as errors.ts says.
1399
+ pending.reject(new McplRequestError(`MCPL server "${this.id}" returned error for ${pending.method}: [${boundedForLog(describeCause(response.error.code))}] ${boundedForLog(describeCause(response.error.message))}`, 'error-response', response.error.data));
1072
1400
  }
1073
1401
  else {
1074
1402
  pending.resolve(response.result);
@@ -1107,7 +1435,9 @@ export class McplServerConnection extends EventEmitter {
1107
1435
  setupLifecycle(transport) {
1108
1436
  this.hostCloseRequested = false;
1109
1437
  transport.on('error', (err) => {
1110
- this.emit('error', new Error(`MCPL server "${this.id}" transport error: ${err.message}`));
1438
+ const error = new Error(`MCPL server "${this.id}" transport error: ${err.message}`);
1439
+ if (!this.emitToErrorListeners(error))
1440
+ console.error(`[mcpl] ${this.id}: transport error: ${logDetail(err.message)}`);
1111
1441
  });
1112
1442
  transport.on('close', (info) => {
1113
1443
  if (!this.closed) {
@@ -1117,7 +1447,7 @@ export class McplServerConnection extends EventEmitter {
1117
1447
  for (const [id, pending] of this.pendingRequests) {
1118
1448
  if (pending.timer)
1119
1449
  clearTimeout(pending.timer);
1120
- pending.reject(new Error(`MCPL server "${this.id}" disconnected unexpectedly (code=${info.code ?? 'n/a'}, signal=${info.signal ?? 'n/a'}, reason=${info.reason ?? 'unknown'}) while awaiting ${pending.method} (id=${id})`));
1450
+ pending.reject(new McplRequestError(`MCPL server "${this.id}" disconnected unexpectedly (code=${info.code ?? 'n/a'}, signal=${info.signal ?? 'n/a'}, reason=${closeReasonText(info)}) while awaiting ${pending.method} (id=${id})`, 'no-response'));
1121
1451
  }
1122
1452
  this.pendingRequests.clear();
1123
1453
  this.orphanedRequests.clear();
@@ -1132,6 +1462,7 @@ export class McplServerConnection extends EventEmitter {
1132
1462
  code: info.code ?? null,
1133
1463
  signal: info.signal ?? null,
1134
1464
  reason: info.reason ?? (byHost ? 'closed by host' : undefined),
1465
+ ...(info.reasonFromPeer ? { reasonFromPeer: true } : {}),
1135
1466
  byHost,
1136
1467
  };
1137
1468
  this.emit('close', closeInfo.code, closeInfo.signal, closeInfo);