@animalabs/agent-framework 0.22.2 → 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 (935) hide show
  1. package/README.md +3 -1
  2. package/dist/src/agent.d.ts +77 -12
  3. package/dist/src/agent.d.ts.map +1 -1
  4. package/dist/src/agent.js +136 -40
  5. package/dist/src/agent.js.map +1 -1
  6. package/dist/src/api/mcp-server-core.js +1 -1
  7. package/dist/src/api/mcp-server-core.js.map +1 -1
  8. package/dist/src/api/server.d.ts.map +1 -1
  9. package/dist/src/api/server.js +5 -1
  10. package/dist/src/api/server.js.map +1 -1
  11. package/dist/src/api/types.d.ts +1 -1
  12. package/dist/src/api/types.d.ts.map +1 -1
  13. package/dist/src/branch-names.d.ts +14 -0
  14. package/dist/src/branch-names.d.ts.map +1 -0
  15. package/dist/src/branch-names.js +22 -0
  16. package/dist/src/branch-names.js.map +1 -0
  17. package/dist/src/closest-names.d.ts +28 -0
  18. package/dist/src/closest-names.d.ts.map +1 -0
  19. package/dist/src/closest-names.js +98 -0
  20. package/dist/src/closest-names.js.map +1 -0
  21. package/dist/src/code-execution/py-runner.d.ts +16 -5
  22. package/dist/src/code-execution/py-runner.d.ts.map +1 -1
  23. package/dist/src/code-execution/py-runner.js +186 -74
  24. package/dist/src/code-execution/py-runner.js.map +1 -1
  25. package/dist/src/code-execution/runtime-py.d.ts.map +1 -1
  26. package/dist/src/code-execution/runtime-py.js +49 -3
  27. package/dist/src/code-execution/runtime-py.js.map +1 -1
  28. package/dist/src/code-execution/tool-definition.d.ts +12 -1
  29. package/dist/src/code-execution/tool-definition.d.ts.map +1 -1
  30. package/dist/src/code-execution/tool-definition.js +21 -3
  31. package/dist/src/code-execution/tool-definition.js.map +1 -1
  32. package/dist/src/config-checks.d.ts +28 -0
  33. package/dist/src/config-checks.d.ts.map +1 -0
  34. package/dist/src/config-checks.js +52 -0
  35. package/dist/src/config-checks.js.map +1 -0
  36. package/dist/src/deadline-timer.d.ts +21 -0
  37. package/dist/src/deadline-timer.d.ts.map +1 -0
  38. package/dist/src/deadline-timer.js +43 -0
  39. package/dist/src/deadline-timer.js.map +1 -0
  40. package/dist/src/error-message.d.ts +30 -0
  41. package/dist/src/error-message.d.ts.map +1 -0
  42. package/dist/src/error-message.js +50 -0
  43. package/dist/src/error-message.js.map +1 -0
  44. package/dist/src/framework.d.ts +828 -88
  45. package/dist/src/framework.d.ts.map +1 -1
  46. package/dist/src/framework.js +5011 -1326
  47. package/dist/src/framework.js.map +1 -1
  48. package/dist/src/gate/event-gate.d.ts +8 -0
  49. package/dist/src/gate/event-gate.d.ts.map +1 -1
  50. package/dist/src/gate/event-gate.js +27 -3
  51. package/dist/src/gate/event-gate.js.map +1 -1
  52. package/dist/src/index.d.ts +4 -2
  53. package/dist/src/index.d.ts.map +1 -1
  54. package/dist/src/index.js +4 -2
  55. package/dist/src/index.js.map +1 -1
  56. package/dist/src/mcpl/channel-registry.d.ts +144 -6
  57. package/dist/src/mcpl/channel-registry.d.ts.map +1 -1
  58. package/dist/src/mcpl/channel-registry.js +424 -263
  59. package/dist/src/mcpl/channel-registry.js.map +1 -1
  60. package/dist/src/mcpl/checkpoint-manager.d.ts +21 -1
  61. package/dist/src/mcpl/checkpoint-manager.d.ts.map +1 -1
  62. package/dist/src/mcpl/checkpoint-manager.js +91 -30
  63. package/dist/src/mcpl/checkpoint-manager.js.map +1 -1
  64. package/dist/src/mcpl/conversation-router.d.ts +19 -3
  65. package/dist/src/mcpl/conversation-router.d.ts.map +1 -1
  66. package/dist/src/mcpl/conversation-router.js +23 -8
  67. package/dist/src/mcpl/conversation-router.js.map +1 -1
  68. package/dist/src/mcpl/convert-block.d.ts +20 -0
  69. package/dist/src/mcpl/convert-block.d.ts.map +1 -0
  70. package/dist/src/mcpl/convert-block.js +89 -0
  71. package/dist/src/mcpl/convert-block.js.map +1 -0
  72. package/dist/src/mcpl/errors.d.ts +13 -0
  73. package/dist/src/mcpl/errors.d.ts.map +1 -1
  74. package/dist/src/mcpl/errors.js +28 -0
  75. package/dist/src/mcpl/errors.js.map +1 -1
  76. package/dist/src/mcpl/hook-orchestrator.d.ts +23 -0
  77. package/dist/src/mcpl/hook-orchestrator.d.ts.map +1 -1
  78. package/dist/src/mcpl/hook-orchestrator.js +83 -72
  79. package/dist/src/mcpl/hook-orchestrator.js.map +1 -1
  80. package/dist/src/mcpl/inbound-source.d.ts +114 -0
  81. package/dist/src/mcpl/inbound-source.d.ts.map +1 -0
  82. package/dist/src/mcpl/inbound-source.js +83 -0
  83. package/dist/src/mcpl/inbound-source.js.map +1 -0
  84. package/dist/src/mcpl/index.d.ts +3 -1
  85. package/dist/src/mcpl/index.d.ts.map +1 -1
  86. package/dist/src/mcpl/index.js +3 -1
  87. package/dist/src/mcpl/index.js.map +1 -1
  88. package/dist/src/mcpl/inference-router.d.ts +15 -11
  89. package/dist/src/mcpl/inference-router.d.ts.map +1 -1
  90. package/dist/src/mcpl/inference-router.js +153 -84
  91. package/dist/src/mcpl/inference-router.js.map +1 -1
  92. package/dist/src/mcpl/push-coalescer.d.ts +33 -11
  93. package/dist/src/mcpl/push-coalescer.d.ts.map +1 -1
  94. package/dist/src/mcpl/push-coalescer.js +52 -20
  95. package/dist/src/mcpl/push-coalescer.js.map +1 -1
  96. package/dist/src/mcpl/push-handler.d.ts +16 -9
  97. package/dist/src/mcpl/push-handler.d.ts.map +1 -1
  98. package/dist/src/mcpl/push-handler.js +18 -83
  99. package/dist/src/mcpl/push-handler.js.map +1 -1
  100. package/dist/src/mcpl/reference-fetcher.d.ts +14 -2
  101. package/dist/src/mcpl/reference-fetcher.d.ts.map +1 -1
  102. package/dist/src/mcpl/reference-fetcher.js +72 -30
  103. package/dist/src/mcpl/reference-fetcher.js.map +1 -1
  104. package/dist/src/mcpl/references.d.ts +47 -12
  105. package/dist/src/mcpl/references.d.ts.map +1 -1
  106. package/dist/src/mcpl/references.js +74 -21
  107. package/dist/src/mcpl/references.js.map +1 -1
  108. package/dist/src/mcpl/server-connection.d.ts +89 -10
  109. package/dist/src/mcpl/server-connection.d.ts.map +1 -1
  110. package/dist/src/mcpl/server-connection.js +405 -129
  111. package/dist/src/mcpl/server-connection.js.map +1 -1
  112. package/dist/src/mcpl/server-registry.d.ts +10 -1
  113. package/dist/src/mcpl/server-registry.d.ts.map +1 -1
  114. package/dist/src/mcpl/server-registry.js +14 -3
  115. package/dist/src/mcpl/server-registry.js.map +1 -1
  116. package/dist/src/mcpl/skip-reply-wake.d.ts +36 -0
  117. package/dist/src/mcpl/skip-reply-wake.d.ts.map +1 -0
  118. package/dist/src/mcpl/skip-reply-wake.js +55 -0
  119. package/dist/src/mcpl/skip-reply-wake.js.map +1 -0
  120. package/dist/src/mcpl/transport.d.ts +51 -2
  121. package/dist/src/mcpl/transport.d.ts.map +1 -1
  122. package/dist/src/mcpl/transport.js +114 -20
  123. package/dist/src/mcpl/transport.js.map +1 -1
  124. package/dist/src/mcpl/types.d.ts +14 -3
  125. package/dist/src/mcpl/types.d.ts.map +1 -1
  126. package/dist/src/mcpl/types.js.map +1 -1
  127. package/dist/src/mcpl/visible-content.d.ts +15 -0
  128. package/dist/src/mcpl/visible-content.d.ts.map +1 -1
  129. package/dist/src/mcpl/visible-content.js +25 -0
  130. package/dist/src/mcpl/visible-content.js.map +1 -1
  131. package/dist/src/module-registry.d.ts +19 -1
  132. package/dist/src/module-registry.d.ts.map +1 -1
  133. package/dist/src/module-registry.js +54 -25
  134. package/dist/src/module-registry.js.map +1 -1
  135. package/dist/src/modules/api/index.js +1 -1
  136. package/dist/src/modules/api/index.js.map +1 -1
  137. package/dist/src/modules/discord/discord-js-client.d.ts +1 -0
  138. package/dist/src/modules/discord/discord-js-client.d.ts.map +1 -1
  139. package/dist/src/modules/discord/discord-js-client.js +25 -9
  140. package/dist/src/modules/discord/discord-js-client.js.map +1 -1
  141. package/dist/src/modules/discord/index.d.ts +29 -3
  142. package/dist/src/modules/discord/index.d.ts.map +1 -1
  143. package/dist/src/modules/discord/index.js +379 -143
  144. package/dist/src/modules/discord/index.js.map +1 -1
  145. package/dist/src/modules/discord/types.d.ts +14 -1
  146. package/dist/src/modules/discord/types.d.ts.map +1 -1
  147. package/dist/src/modules/health/index.d.ts.map +1 -1
  148. package/dist/src/modules/health/index.js +2 -1
  149. package/dist/src/modules/health/index.js.map +1 -1
  150. package/dist/src/modules/history/index.d.ts +3 -1
  151. package/dist/src/modules/history/index.d.ts.map +1 -1
  152. package/dist/src/modules/history/index.js +359 -127
  153. package/dist/src/modules/history/index.js.map +1 -1
  154. package/dist/src/modules/history/semantic.d.ts +28 -1
  155. package/dist/src/modules/history/semantic.d.ts.map +1 -1
  156. package/dist/src/modules/history/semantic.js +177 -32
  157. package/dist/src/modules/history/semantic.js.map +1 -1
  158. package/dist/src/modules/unknown-tool.d.ts +10 -0
  159. package/dist/src/modules/unknown-tool.d.ts.map +1 -0
  160. package/dist/src/modules/unknown-tool.js +17 -0
  161. package/dist/src/modules/unknown-tool.js.map +1 -0
  162. package/dist/src/modules/workspace/disk-agreement.d.ts +32 -2
  163. package/dist/src/modules/workspace/disk-agreement.d.ts.map +1 -1
  164. package/dist/src/modules/workspace/disk-agreement.js +30 -2
  165. package/dist/src/modules/workspace/disk-agreement.js.map +1 -1
  166. package/dist/src/modules/workspace/effects.d.ts +64 -6
  167. package/dist/src/modules/workspace/effects.d.ts.map +1 -1
  168. package/dist/src/modules/workspace/effects.js +291 -44
  169. package/dist/src/modules/workspace/effects.js.map +1 -1
  170. package/dist/src/modules/workspace/index.d.ts +119 -23
  171. package/dist/src/modules/workspace/index.d.ts.map +1 -1
  172. package/dist/src/modules/workspace/index.js +793 -247
  173. package/dist/src/modules/workspace/index.js.map +1 -1
  174. package/dist/src/modules/workspace/observe.d.ts +75 -8
  175. package/dist/src/modules/workspace/observe.d.ts.map +1 -1
  176. package/dist/src/modules/workspace/observe.js +174 -14
  177. package/dist/src/modules/workspace/observe.js.map +1 -1
  178. package/dist/src/modules/workspace/reconcile.d.ts +58 -7
  179. package/dist/src/modules/workspace/reconcile.d.ts.map +1 -1
  180. package/dist/src/modules/workspace/reconcile.js +521 -56
  181. package/dist/src/modules/workspace/reconcile.js.map +1 -1
  182. package/dist/src/modules/workspace/types.d.ts +18 -4
  183. package/dist/src/modules/workspace/types.d.ts.map +1 -1
  184. package/dist/src/modules/workspace/types.js.map +1 -1
  185. package/dist/src/modules/workspace/watcher.d.ts +7 -2
  186. package/dist/src/modules/workspace/watcher.d.ts.map +1 -1
  187. package/dist/src/modules/workspace/watcher.js +28 -4
  188. package/dist/src/modules/workspace/watcher.js.map +1 -1
  189. package/dist/src/prose-drafts.d.ts +240 -0
  190. package/dist/src/prose-drafts.d.ts.map +1 -0
  191. package/dist/src/prose-drafts.js +362 -0
  192. package/dist/src/prose-drafts.js.map +1 -0
  193. package/dist/src/prose-segments.d.ts +21 -2
  194. package/dist/src/prose-segments.d.ts.map +1 -1
  195. package/dist/src/prose-segments.js +46 -9
  196. package/dist/src/prose-segments.js.map +1 -1
  197. package/dist/src/recovery/offline-branch.d.ts +1 -0
  198. package/dist/src/recovery/offline-branch.d.ts.map +1 -1
  199. package/dist/src/recovery/offline-branch.js +3 -1
  200. package/dist/src/recovery/offline-branch.js.map +1 -1
  201. package/dist/src/safe-slice.d.ts +5 -1
  202. package/dist/src/safe-slice.d.ts.map +1 -1
  203. package/dist/src/safe-slice.js +9 -1
  204. package/dist/src/safe-slice.js.map +1 -1
  205. package/dist/src/tool-image-ledger.d.ts +87 -19
  206. package/dist/src/tool-image-ledger.d.ts.map +1 -1
  207. package/dist/src/tool-image-ledger.js +135 -32
  208. package/dist/src/tool-image-ledger.js.map +1 -1
  209. package/dist/src/tool-presentation.d.ts +9 -0
  210. package/dist/src/tool-presentation.d.ts.map +1 -1
  211. package/dist/src/tool-presentation.js +257 -60
  212. package/dist/src/tool-presentation.js.map +1 -1
  213. package/dist/src/tool-result-guard.d.ts.map +1 -1
  214. package/dist/src/tool-result-guard.js +7 -10
  215. package/dist/src/tool-result-guard.js.map +1 -1
  216. package/dist/src/tool-result-history.d.ts +32 -3
  217. package/dist/src/tool-result-history.d.ts.map +1 -1
  218. package/dist/src/tool-result-history.js +106 -19
  219. package/dist/src/tool-result-history.js.map +1 -1
  220. package/dist/src/tune-out/coordinator.d.ts +25 -1
  221. package/dist/src/tune-out/coordinator.d.ts.map +1 -1
  222. package/dist/src/tune-out/coordinator.js +260 -65
  223. package/dist/src/tune-out/coordinator.js.map +1 -1
  224. package/dist/src/types/agent.d.ts +17 -5
  225. package/dist/src/types/agent.d.ts.map +1 -1
  226. package/dist/src/types/events.d.ts +17 -0
  227. package/dist/src/types/events.d.ts.map +1 -1
  228. package/dist/src/types/framework.d.ts +21 -5
  229. package/dist/src/types/framework.d.ts.map +1 -1
  230. package/dist/src/types/inference-log.d.ts +1 -1
  231. package/dist/src/types/inference-log.d.ts.map +1 -1
  232. package/dist/src/types/module.d.ts +23 -4
  233. package/dist/src/types/module.d.ts.map +1 -1
  234. package/dist/src/types/trace.d.ts +95 -6
  235. package/dist/src/types/trace.d.ts.map +1 -1
  236. package/dist/src/usage/usage-tracker.d.ts +5 -0
  237. package/dist/src/usage/usage-tracker.d.ts.map +1 -1
  238. package/dist/src/usage/usage-tracker.js +35 -8
  239. package/dist/src/usage/usage-tracker.js.map +1 -1
  240. package/package.json +3 -4
  241. package/src/agent.ts +162 -40
  242. package/src/api/mcp-server-core.ts +1 -1
  243. package/src/api/server.ts +4 -1
  244. package/src/api/types.ts +1 -1
  245. package/src/branch-names.ts +19 -0
  246. package/src/closest-names.ts +94 -0
  247. package/src/code-execution/py-runner.ts +200 -76
  248. package/src/code-execution/runtime-py.ts +49 -3
  249. package/src/code-execution/tool-definition.ts +28 -4
  250. package/src/config-checks.ts +48 -0
  251. package/src/deadline-timer.ts +44 -0
  252. package/src/error-message.ts +48 -0
  253. package/src/framework.ts +5352 -1388
  254. package/src/gate/event-gate.ts +28 -3
  255. package/src/index.ts +11 -2
  256. package/src/mcpl/channel-registry.ts +517 -286
  257. package/src/mcpl/checkpoint-manager.ts +104 -29
  258. package/src/mcpl/conversation-router.ts +28 -8
  259. package/src/mcpl/convert-block.ts +97 -0
  260. package/src/mcpl/errors.ts +28 -0
  261. package/src/mcpl/hook-orchestrator.ts +84 -77
  262. package/src/mcpl/inbound-source.ts +156 -0
  263. package/src/mcpl/index.ts +10 -1
  264. package/src/mcpl/inference-router.ts +174 -99
  265. package/src/mcpl/push-coalescer.ts +60 -24
  266. package/src/mcpl/push-handler.ts +20 -90
  267. package/src/mcpl/reference-fetcher.ts +71 -26
  268. package/src/mcpl/references.ts +81 -22
  269. package/src/mcpl/server-connection.ts +427 -132
  270. package/src/mcpl/server-registry.ts +15 -4
  271. package/src/mcpl/skip-reply-wake.ts +73 -0
  272. package/src/mcpl/transport.ts +120 -18
  273. package/src/mcpl/types.ts +14 -3
  274. package/src/mcpl/visible-content.ts +27 -0
  275. package/src/module-registry.ts +58 -23
  276. package/src/modules/api/index.ts +1 -1
  277. package/src/modules/discord/discord-js-client.ts +26 -10
  278. package/src/modules/discord/index.ts +391 -158
  279. package/src/modules/discord/types.ts +15 -2
  280. package/src/modules/health/index.ts +2 -1
  281. package/src/modules/history/index.ts +410 -120
  282. package/src/modules/history/semantic.ts +189 -32
  283. package/src/modules/unknown-tool.ts +16 -0
  284. package/src/modules/workspace/disk-agreement.ts +51 -3
  285. package/src/modules/workspace/effects.ts +279 -35
  286. package/src/modules/workspace/index.ts +810 -260
  287. package/src/modules/workspace/observe.ts +194 -20
  288. package/src/modules/workspace/reconcile.ts +619 -64
  289. package/src/modules/workspace/types.ts +18 -4
  290. package/src/modules/workspace/watcher.ts +27 -4
  291. package/src/prose-drafts.ts +481 -0
  292. package/src/prose-segments.ts +51 -8
  293. package/src/recovery/offline-branch.ts +4 -1
  294. package/src/safe-slice.ts +9 -1
  295. package/src/tool-image-ledger.ts +153 -34
  296. package/src/tool-presentation.ts +224 -40
  297. package/src/tool-result-guard.ts +7 -8
  298. package/src/tool-result-history.ts +124 -20
  299. package/src/tune-out/coordinator.ts +259 -65
  300. package/src/types/agent.ts +17 -7
  301. package/src/types/events.ts +17 -0
  302. package/src/types/framework.ts +21 -5
  303. package/src/types/inference-log.ts +1 -1
  304. package/src/types/module.ts +24 -4
  305. package/src/types/trace.ts +101 -6
  306. package/src/usage/usage-tracker.ts +32 -8
  307. package/dist/test/activation-request-sanitize.test.d.ts +0 -2
  308. package/dist/test/activation-request-sanitize.test.d.ts.map +0 -1
  309. package/dist/test/activation-request-sanitize.test.js +0 -89
  310. package/dist/test/activation-request-sanitize.test.js.map +0 -1
  311. package/dist/test/agent-cache-ttl.test.d.ts +0 -2
  312. package/dist/test/agent-cache-ttl.test.d.ts.map +0 -1
  313. package/dist/test/agent-cache-ttl.test.js +0 -41
  314. package/dist/test/agent-cache-ttl.test.js.map +0 -1
  315. package/dist/test/agent-runtime-settings.test.d.ts +0 -2
  316. package/dist/test/agent-runtime-settings.test.d.ts.map +0 -1
  317. package/dist/test/agent-runtime-settings.test.js +0 -1598
  318. package/dist/test/agent-runtime-settings.test.js.map +0 -1
  319. package/dist/test/api-admin-gate.test.d.ts +0 -2
  320. package/dist/test/api-admin-gate.test.d.ts.map +0 -1
  321. package/dist/test/api-admin-gate.test.js +0 -116
  322. package/dist/test/api-admin-gate.test.js.map +0 -1
  323. package/dist/test/assistant-persist-refusal.test.d.ts +0 -2
  324. package/dist/test/assistant-persist-refusal.test.d.ts.map +0 -1
  325. package/dist/test/assistant-persist-refusal.test.js +0 -63
  326. package/dist/test/assistant-persist-refusal.test.js.map +0 -1
  327. package/dist/test/batched-wake-locus.test.d.ts +0 -2
  328. package/dist/test/batched-wake-locus.test.d.ts.map +0 -1
  329. package/dist/test/batched-wake-locus.test.js +0 -166
  330. package/dist/test/batched-wake-locus.test.js.map +0 -1
  331. package/dist/test/busy-agent-scheduler.test.d.ts +0 -2
  332. package/dist/test/busy-agent-scheduler.test.d.ts.map +0 -1
  333. package/dist/test/busy-agent-scheduler.test.js +0 -92
  334. package/dist/test/busy-agent-scheduler.test.js.map +0 -1
  335. package/dist/test/channel-incoming-targeting.test.d.ts +0 -2
  336. package/dist/test/channel-incoming-targeting.test.d.ts.map +0 -1
  337. package/dist/test/channel-incoming-targeting.test.js +0 -81
  338. package/dist/test/channel-incoming-targeting.test.js.map +0 -1
  339. package/dist/test/channel-label-history.test.d.ts +0 -2
  340. package/dist/test/channel-label-history.test.d.ts.map +0 -1
  341. package/dist/test/channel-label-history.test.js +0 -424
  342. package/dist/test/channel-label-history.test.js.map +0 -1
  343. package/dist/test/channel-lifecycle-provenance.test.d.ts +0 -2
  344. package/dist/test/channel-lifecycle-provenance.test.d.ts.map +0 -1
  345. package/dist/test/channel-lifecycle-provenance.test.js +0 -47
  346. package/dist/test/channel-lifecycle-provenance.test.js.map +0 -1
  347. package/dist/test/channel-registry-routing.test.d.ts +0 -2
  348. package/dist/test/channel-registry-routing.test.d.ts.map +0 -1
  349. package/dist/test/channel-registry-routing.test.js +0 -446
  350. package/dist/test/channel-registry-routing.test.js.map +0 -1
  351. package/dist/test/channel-registry-typing.test.d.ts +0 -2
  352. package/dist/test/channel-registry-typing.test.d.ts.map +0 -1
  353. package/dist/test/channel-registry-typing.test.js +0 -91
  354. package/dist/test/channel-registry-typing.test.js.map +0 -1
  355. package/dist/test/channels-changed-respond-first.test.d.ts +0 -2
  356. package/dist/test/channels-changed-respond-first.test.d.ts.map +0 -1
  357. package/dist/test/channels-changed-respond-first.test.js +0 -74
  358. package/dist/test/channels-changed-respond-first.test.js.map +0 -1
  359. package/dist/test/checkpoint-attribution.test.d.ts +0 -2
  360. package/dist/test/checkpoint-attribution.test.d.ts.map +0 -1
  361. package/dist/test/checkpoint-attribution.test.js +0 -200
  362. package/dist/test/checkpoint-attribution.test.js.map +0 -1
  363. package/dist/test/code-execution.test.d.ts +0 -11
  364. package/dist/test/code-execution.test.d.ts.map +0 -1
  365. package/dist/test/code-execution.test.js +0 -1272
  366. package/dist/test/code-execution.test.js.map +0 -1
  367. package/dist/test/component-defaults.test.d.ts +0 -2
  368. package/dist/test/component-defaults.test.d.ts.map +0 -1
  369. package/dist/test/component-defaults.test.js +0 -54
  370. package/dist/test/component-defaults.test.js.map +0 -1
  371. package/dist/test/conversation-fork-injection-scoping.test.d.ts +0 -2
  372. package/dist/test/conversation-fork-injection-scoping.test.d.ts.map +0 -1
  373. package/dist/test/conversation-fork-injection-scoping.test.js +0 -200
  374. package/dist/test/conversation-fork-injection-scoping.test.js.map +0 -1
  375. package/dist/test/conversation-router.test.d.ts +0 -2
  376. package/dist/test/conversation-router.test.d.ts.map +0 -1
  377. package/dist/test/conversation-router.test.js +0 -174
  378. package/dist/test/conversation-router.test.js.map +0 -1
  379. package/dist/test/conversation-routing.test.d.ts +0 -7
  380. package/dist/test/conversation-routing.test.d.ts.map +0 -1
  381. package/dist/test/conversation-routing.test.js +0 -621
  382. package/dist/test/conversation-routing.test.js.map +0 -1
  383. package/dist/test/deferred-wake-integrity.test.d.ts +0 -29
  384. package/dist/test/deferred-wake-integrity.test.d.ts.map +0 -1
  385. package/dist/test/deferred-wake-integrity.test.js +0 -320
  386. package/dist/test/deferred-wake-integrity.test.js.map +0 -1
  387. package/dist/test/discord-awareness-outbox.test.d.ts +0 -2
  388. package/dist/test/discord-awareness-outbox.test.d.ts.map +0 -1
  389. package/dist/test/discord-awareness-outbox.test.js +0 -371
  390. package/dist/test/discord-awareness-outbox.test.js.map +0 -1
  391. package/dist/test/discord-history-delete-window.test.d.ts +0 -2
  392. package/dist/test/discord-history-delete-window.test.d.ts.map +0 -1
  393. package/dist/test/discord-history-delete-window.test.js +0 -81
  394. package/dist/test/discord-history-delete-window.test.js.map +0 -1
  395. package/dist/test/discord-history-sync.test.d.ts +0 -2
  396. package/dist/test/discord-history-sync.test.d.ts.map +0 -1
  397. package/dist/test/discord-history-sync.test.js +0 -56
  398. package/dist/test/discord-history-sync.test.js.map +0 -1
  399. package/dist/test/discord-typing-keepalive.test.d.ts +0 -2
  400. package/dist/test/discord-typing-keepalive.test.d.ts.map +0 -1
  401. package/dist/test/discord-typing-keepalive.test.js +0 -77
  402. package/dist/test/discord-typing-keepalive.test.js.map +0 -1
  403. package/dist/test/ephemeral-settle.test.d.ts +0 -2
  404. package/dist/test/ephemeral-settle.test.d.ts.map +0 -1
  405. package/dist/test/ephemeral-settle.test.js +0 -354
  406. package/dist/test/ephemeral-settle.test.js.map +0 -1
  407. package/dist/test/event-gate-passthrough.test.d.ts +0 -15
  408. package/dist/test/event-gate-passthrough.test.d.ts.map +0 -1
  409. package/dist/test/event-gate-passthrough.test.js +0 -289
  410. package/dist/test/event-gate-passthrough.test.js.map +0 -1
  411. package/dist/test/event-gate-policy-mutation.test.d.ts +0 -2
  412. package/dist/test/event-gate-policy-mutation.test.d.ts.map +0 -1
  413. package/dist/test/event-gate-policy-mutation.test.js +0 -137
  414. package/dist/test/event-gate-policy-mutation.test.js.map +0 -1
  415. package/dist/test/event-gate-rate-limit.test.d.ts +0 -2
  416. package/dist/test/event-gate-rate-limit.test.d.ts.map +0 -1
  417. package/dist/test/event-gate-rate-limit.test.js +0 -627
  418. package/dist/test/event-gate-rate-limit.test.js.map +0 -1
  419. package/dist/test/event-gate-script.test.d.ts +0 -2
  420. package/dist/test/event-gate-script.test.d.ts.map +0 -1
  421. package/dist/test/event-gate-script.test.js +0 -95
  422. package/dist/test/event-gate-script.test.js.map +0 -1
  423. package/dist/test/event-gate-selfwake.test.d.ts +0 -15
  424. package/dist/test/event-gate-selfwake.test.d.ts.map +0 -1
  425. package/dist/test/event-gate-selfwake.test.js +0 -125
  426. package/dist/test/event-gate-selfwake.test.js.map +0 -1
  427. package/dist/test/event-gate-tags.test.d.ts +0 -2
  428. package/dist/test/event-gate-tags.test.d.ts.map +0 -1
  429. package/dist/test/event-gate-tags.test.js +0 -76
  430. package/dist/test/event-gate-tags.test.js.map +0 -1
  431. package/dist/test/event-gate.test.d.ts +0 -2
  432. package/dist/test/event-gate.test.d.ts.map +0 -1
  433. package/dist/test/event-gate.test.js +0 -919
  434. package/dist/test/event-gate.test.js.map +0 -1
  435. package/dist/test/explicit-prose-routing.test.d.ts +0 -11
  436. package/dist/test/explicit-prose-routing.test.d.ts.map +0 -1
  437. package/dist/test/explicit-prose-routing.test.js +0 -1715
  438. package/dist/test/explicit-prose-routing.test.js.map +0 -1
  439. package/dist/test/framework.test.d.ts +0 -5
  440. package/dist/test/framework.test.d.ts.map +0 -1
  441. package/dist/test/framework.test.js +0 -1048
  442. package/dist/test/framework.test.js.map +0 -1
  443. package/dist/test/gather-context-timeout.test.d.ts +0 -2
  444. package/dist/test/gather-context-timeout.test.d.ts.map +0 -1
  445. package/dist/test/gather-context-timeout.test.js +0 -120
  446. package/dist/test/gather-context-timeout.test.js.map +0 -1
  447. package/dist/test/health-snapshot.test.d.ts +0 -2
  448. package/dist/test/health-snapshot.test.d.ts.map +0 -1
  449. package/dist/test/health-snapshot.test.js +0 -74
  450. package/dist/test/health-snapshot.test.js.map +0 -1
  451. package/dist/test/helpers/coalescing-fixture.d.ts +0 -74
  452. package/dist/test/helpers/coalescing-fixture.d.ts.map +0 -1
  453. package/dist/test/helpers/coalescing-fixture.js +0 -152
  454. package/dist/test/helpers/coalescing-fixture.js.map +0 -1
  455. package/dist/test/helpers/coalescing-kill-child.d.ts +0 -2
  456. package/dist/test/helpers/coalescing-kill-child.d.ts.map +0 -1
  457. package/dist/test/helpers/coalescing-kill-child.js +0 -24
  458. package/dist/test/helpers/coalescing-kill-child.js.map +0 -1
  459. package/dist/test/helpers/mock-membrane.d.ts +0 -53
  460. package/dist/test/helpers/mock-membrane.d.ts.map +0 -1
  461. package/dist/test/helpers/mock-membrane.js +0 -168
  462. package/dist/test/helpers/mock-membrane.js.map +0 -1
  463. package/dist/test/helpers/pytc-stop-rows.d.ts +0 -11
  464. package/dist/test/helpers/pytc-stop-rows.d.ts.map +0 -1
  465. package/dist/test/helpers/pytc-stop-rows.js +0 -143
  466. package/dist/test/helpers/pytc-stop-rows.js.map +0 -1
  467. package/dist/test/helpers/quiesce-crash-child.d.ts +0 -2
  468. package/dist/test/helpers/quiesce-crash-child.d.ts.map +0 -1
  469. package/dist/test/helpers/quiesce-crash-child.js +0 -156
  470. package/dist/test/helpers/quiesce-crash-child.js.map +0 -1
  471. package/dist/test/hide-then-turn.test.d.ts +0 -2
  472. package/dist/test/hide-then-turn.test.d.ts.map +0 -1
  473. package/dist/test/hide-then-turn.test.js +0 -101
  474. package/dist/test/hide-then-turn.test.js.map +0 -1
  475. package/dist/test/history-module-overview.test.d.ts +0 -2
  476. package/dist/test/history-module-overview.test.d.ts.map +0 -1
  477. package/dist/test/history-module-overview.test.js +0 -711
  478. package/dist/test/history-module-overview.test.js.map +0 -1
  479. package/dist/test/history-module-realstore.test.d.ts +0 -2
  480. package/dist/test/history-module-realstore.test.d.ts.map +0 -1
  481. package/dist/test/history-module-realstore.test.js +0 -363
  482. package/dist/test/history-module-realstore.test.js.map +0 -1
  483. package/dist/test/history-module-semantic.test.d.ts +0 -2
  484. package/dist/test/history-module-semantic.test.d.ts.map +0 -1
  485. package/dist/test/history-module-semantic.test.js +0 -213
  486. package/dist/test/history-module-semantic.test.js.map +0 -1
  487. package/dist/test/history-module-ux.test.d.ts +0 -2
  488. package/dist/test/history-module-ux.test.d.ts.map +0 -1
  489. package/dist/test/history-module-ux.test.js +0 -304
  490. package/dist/test/history-module-ux.test.js.map +0 -1
  491. package/dist/test/history-module.test.d.ts +0 -2
  492. package/dist/test/history-module.test.d.ts.map +0 -1
  493. package/dist/test/history-module.test.js +0 -619
  494. package/dist/test/history-module.test.js.map +0 -1
  495. package/dist/test/history-semantic-review-findings.test.d.ts +0 -2
  496. package/dist/test/history-semantic-review-findings.test.d.ts.map +0 -1
  497. package/dist/test/history-semantic-review-findings.test.js +0 -338
  498. package/dist/test/history-semantic-review-findings.test.js.map +0 -1
  499. package/dist/test/history-semantic-sync-converges.test.d.ts +0 -2
  500. package/dist/test/history-semantic-sync-converges.test.d.ts.map +0 -1
  501. package/dist/test/history-semantic-sync-converges.test.js +0 -109
  502. package/dist/test/history-semantic-sync-converges.test.js.map +0 -1
  503. package/dist/test/host-quiesce.test.d.ts +0 -2
  504. package/dist/test/host-quiesce.test.d.ts.map +0 -1
  505. package/dist/test/host-quiesce.test.js +0 -988
  506. package/dist/test/host-quiesce.test.js.map +0 -1
  507. package/dist/test/inference-exhaustion-rewind.test.d.ts +0 -2
  508. package/dist/test/inference-exhaustion-rewind.test.d.ts.map +0 -1
  509. package/dist/test/inference-exhaustion-rewind.test.js +0 -387
  510. package/dist/test/inference-exhaustion-rewind.test.js.map +0 -1
  511. package/dist/test/inference-failure-bounds.test.d.ts +0 -2
  512. package/dist/test/inference-failure-bounds.test.d.ts.map +0 -1
  513. package/dist/test/inference-failure-bounds.test.js +0 -1202
  514. package/dist/test/inference-failure-bounds.test.js.map +0 -1
  515. package/dist/test/inference-failure-observability.test.d.ts +0 -2
  516. package/dist/test/inference-failure-observability.test.d.ts.map +0 -1
  517. package/dist/test/inference-failure-observability.test.js +0 -84
  518. package/dist/test/inference-failure-observability.test.js.map +0 -1
  519. package/dist/test/journal-tool.test.d.ts +0 -2
  520. package/dist/test/journal-tool.test.d.ts.map +0 -1
  521. package/dist/test/journal-tool.test.js +0 -33
  522. package/dist/test/journal-tool.test.js.map +0 -1
  523. package/dist/test/kv-unified-open-flight-retry.test.d.ts +0 -2
  524. package/dist/test/kv-unified-open-flight-retry.test.d.ts.map +0 -1
  525. package/dist/test/kv-unified-open-flight-retry.test.js +0 -189
  526. package/dist/test/kv-unified-open-flight-retry.test.js.map +0 -1
  527. package/dist/test/kv-unified-wiring.test.d.ts +0 -2
  528. package/dist/test/kv-unified-wiring.test.d.ts.map +0 -1
  529. package/dist/test/kv-unified-wiring.test.js +0 -95
  530. package/dist/test/kv-unified-wiring.test.js.map +0 -1
  531. package/dist/test/late-events-after-stop.test.d.ts +0 -2
  532. package/dist/test/late-events-after-stop.test.d.ts.map +0 -1
  533. package/dist/test/late-events-after-stop.test.js +0 -122
  534. package/dist/test/late-events-after-stop.test.js.map +0 -1
  535. package/dist/test/liveness-watchdog.test.d.ts +0 -2
  536. package/dist/test/liveness-watchdog.test.d.ts.map +0 -1
  537. package/dist/test/liveness-watchdog.test.js +0 -94
  538. package/dist/test/liveness-watchdog.test.js.map +0 -1
  539. package/dist/test/machine-close-provenance.test.d.ts +0 -2
  540. package/dist/test/machine-close-provenance.test.d.ts.map +0 -1
  541. package/dist/test/machine-close-provenance.test.js +0 -116
  542. package/dist/test/machine-close-provenance.test.js.map +0 -1
  543. package/dist/test/maintenance-timer.test.d.ts +0 -2
  544. package/dist/test/maintenance-timer.test.d.ts.map +0 -1
  545. package/dist/test/maintenance-timer.test.js +0 -1827
  546. package/dist/test/maintenance-timer.test.js.map +0 -1
  547. package/dist/test/mcp-server-bin.test.d.ts +0 -2
  548. package/dist/test/mcp-server-bin.test.d.ts.map +0 -1
  549. package/dist/test/mcp-server-bin.test.js +0 -142
  550. package/dist/test/mcp-server-bin.test.js.map +0 -1
  551. package/dist/test/mcpl-access-provider.test.d.ts +0 -2
  552. package/dist/test/mcpl-access-provider.test.d.ts.map +0 -1
  553. package/dist/test/mcpl-access-provider.test.js +0 -20
  554. package/dist/test/mcpl-access-provider.test.js.map +0 -1
  555. package/dist/test/mcpl-awareness-barrier.test.d.ts +0 -2
  556. package/dist/test/mcpl-awareness-barrier.test.d.ts.map +0 -1
  557. package/dist/test/mcpl-awareness-barrier.test.js +0 -769
  558. package/dist/test/mcpl-awareness-barrier.test.js.map +0 -1
  559. package/dist/test/mcpl-capability-grant.test.d.ts +0 -10
  560. package/dist/test/mcpl-capability-grant.test.d.ts.map +0 -1
  561. package/dist/test/mcpl-capability-grant.test.js +0 -111
  562. package/dist/test/mcpl-capability-grant.test.js.map +0 -1
  563. package/dist/test/mcpl-capability-scoping.test.d.ts +0 -2
  564. package/dist/test/mcpl-capability-scoping.test.d.ts.map +0 -1
  565. package/dist/test/mcpl-capability-scoping.test.js +0 -266
  566. package/dist/test/mcpl-capability-scoping.test.js.map +0 -1
  567. package/dist/test/mcpl-child-env.test.d.ts +0 -2
  568. package/dist/test/mcpl-child-env.test.d.ts.map +0 -1
  569. package/dist/test/mcpl-child-env.test.js +0 -158
  570. package/dist/test/mcpl-child-env.test.js.map +0 -1
  571. package/dist/test/mcpl-coalesced-content-parity.test.d.ts +0 -2
  572. package/dist/test/mcpl-coalesced-content-parity.test.d.ts.map +0 -1
  573. package/dist/test/mcpl-coalesced-content-parity.test.js +0 -532
  574. package/dist/test/mcpl-coalesced-content-parity.test.js.map +0 -1
  575. package/dist/test/mcpl-coalescing.test.d.ts +0 -2
  576. package/dist/test/mcpl-coalescing.test.d.ts.map +0 -1
  577. package/dist/test/mcpl-coalescing.test.js +0 -1125
  578. package/dist/test/mcpl-coalescing.test.js.map +0 -1
  579. package/dist/test/mcpl-config-diagnostics.test.d.ts +0 -2
  580. package/dist/test/mcpl-config-diagnostics.test.d.ts.map +0 -1
  581. package/dist/test/mcpl-config-diagnostics.test.js +0 -452
  582. package/dist/test/mcpl-config-diagnostics.test.js.map +0 -1
  583. package/dist/test/mcpl-empty-content.test.d.ts +0 -2
  584. package/dist/test/mcpl-empty-content.test.d.ts.map +0 -1
  585. package/dist/test/mcpl-empty-content.test.js +0 -368
  586. package/dist/test/mcpl-empty-content.test.js.map +0 -1
  587. package/dist/test/mcpl-gate-roundtrip.test.d.ts +0 -2
  588. package/dist/test/mcpl-gate-roundtrip.test.d.ts.map +0 -1
  589. package/dist/test/mcpl-gate-roundtrip.test.js +0 -285
  590. package/dist/test/mcpl-gate-roundtrip.test.js.map +0 -1
  591. package/dist/test/mcpl-list-status.test.d.ts +0 -2
  592. package/dist/test/mcpl-list-status.test.d.ts.map +0 -1
  593. package/dist/test/mcpl-list-status.test.js +0 -82
  594. package/dist/test/mcpl-list-status.test.js.map +0 -1
  595. package/dist/test/mcpl-manifest-changed.test.d.ts +0 -2
  596. package/dist/test/mcpl-manifest-changed.test.d.ts.map +0 -1
  597. package/dist/test/mcpl-manifest-changed.test.js +0 -178
  598. package/dist/test/mcpl-manifest-changed.test.js.map +0 -1
  599. package/dist/test/mcpl-push-convert.test.d.ts +0 -2
  600. package/dist/test/mcpl-push-convert.test.d.ts.map +0 -1
  601. package/dist/test/mcpl-push-convert.test.js +0 -42
  602. package/dist/test/mcpl-push-convert.test.js.map +0 -1
  603. package/dist/test/mcpl-reconnect-events.test.d.ts +0 -2
  604. package/dist/test/mcpl-reconnect-events.test.d.ts.map +0 -1
  605. package/dist/test/mcpl-reconnect-events.test.js +0 -144
  606. package/dist/test/mcpl-reconnect-events.test.js.map +0 -1
  607. package/dist/test/mcpl-reconnect-reregistration.test.d.ts +0 -2
  608. package/dist/test/mcpl-reconnect-reregistration.test.d.ts.map +0 -1
  609. package/dist/test/mcpl-reconnect-reregistration.test.js +0 -238
  610. package/dist/test/mcpl-reconnect-reregistration.test.js.map +0 -1
  611. package/dist/test/mcpl-reference-fetcher.test.d.ts +0 -2
  612. package/dist/test/mcpl-reference-fetcher.test.d.ts.map +0 -1
  613. package/dist/test/mcpl-reference-fetcher.test.js +0 -427
  614. package/dist/test/mcpl-reference-fetcher.test.js.map +0 -1
  615. package/dist/test/mcpl-reference-fields.test.d.ts +0 -2
  616. package/dist/test/mcpl-reference-fields.test.d.ts.map +0 -1
  617. package/dist/test/mcpl-reference-fields.test.js +0 -149
  618. package/dist/test/mcpl-reference-fields.test.js.map +0 -1
  619. package/dist/test/mcpl-rejection-log-lines.test.d.ts +0 -2
  620. package/dist/test/mcpl-rejection-log-lines.test.d.ts.map +0 -1
  621. package/dist/test/mcpl-rejection-log-lines.test.js +0 -349
  622. package/dist/test/mcpl-rejection-log-lines.test.js.map +0 -1
  623. package/dist/test/mcpl-request-timeout.test.d.ts +0 -2
  624. package/dist/test/mcpl-request-timeout.test.d.ts.map +0 -1
  625. package/dist/test/mcpl-request-timeout.test.js +0 -138
  626. package/dist/test/mcpl-request-timeout.test.js.map +0 -1
  627. package/dist/test/mcpl-runtime-lifecycle.test.d.ts +0 -7
  628. package/dist/test/mcpl-runtime-lifecycle.test.d.ts.map +0 -1
  629. package/dist/test/mcpl-runtime-lifecycle.test.js +0 -142
  630. package/dist/test/mcpl-runtime-lifecycle.test.js.map +0 -1
  631. package/dist/test/mcpl-stderr-tail.test.d.ts +0 -2
  632. package/dist/test/mcpl-stderr-tail.test.d.ts.map +0 -1
  633. package/dist/test/mcpl-stderr-tail.test.js +0 -210
  634. package/dist/test/mcpl-stderr-tail.test.js.map +0 -1
  635. package/dist/test/mcpl-tool-class-listing.test.d.ts +0 -2
  636. package/dist/test/mcpl-tool-class-listing.test.d.ts.map +0 -1
  637. package/dist/test/mcpl-tool-class-listing.test.js +0 -147
  638. package/dist/test/mcpl-tool-class-listing.test.js.map +0 -1
  639. package/dist/test/mcpl-tool-classes.test.d.ts +0 -7
  640. package/dist/test/mcpl-tool-classes.test.d.ts.map +0 -1
  641. package/dist/test/mcpl-tool-classes.test.js +0 -80
  642. package/dist/test/mcpl-tool-classes.test.js.map +0 -1
  643. package/dist/test/mcpl-tool-lifecycle-e2e.test.d.ts +0 -2
  644. package/dist/test/mcpl-tool-lifecycle-e2e.test.d.ts.map +0 -1
  645. package/dist/test/mcpl-tool-lifecycle-e2e.test.js +0 -237
  646. package/dist/test/mcpl-tool-lifecycle-e2e.test.js.map +0 -1
  647. package/dist/test/mcpl-tool-lifecycle-emitter.test.d.ts +0 -11
  648. package/dist/test/mcpl-tool-lifecycle-emitter.test.d.ts.map +0 -1
  649. package/dist/test/mcpl-tool-lifecycle-emitter.test.js +0 -412
  650. package/dist/test/mcpl-tool-lifecycle-emitter.test.js.map +0 -1
  651. package/dist/test/mcpl-tool-lifecycle-script.test.d.ts +0 -2
  652. package/dist/test/mcpl-tool-lifecycle-script.test.d.ts.map +0 -1
  653. package/dist/test/mcpl-tool-lifecycle-script.test.js +0 -288
  654. package/dist/test/mcpl-tool-lifecycle-script.test.js.map +0 -1
  655. package/dist/test/mcpl-tool-lifecycle.test.d.ts +0 -11
  656. package/dist/test/mcpl-tool-lifecycle.test.d.ts.map +0 -1
  657. package/dist/test/mcpl-tool-lifecycle.test.js +0 -270
  658. package/dist/test/mcpl-tool-lifecycle.test.js.map +0 -1
  659. package/dist/test/mcpl-transport-close.test.d.ts +0 -2
  660. package/dist/test/mcpl-transport-close.test.d.ts.map +0 -1
  661. package/dist/test/mcpl-transport-close.test.js +0 -373
  662. package/dist/test/mcpl-transport-close.test.js.map +0 -1
  663. package/dist/test/mcpl-transport-spawn.test.d.ts +0 -2
  664. package/dist/test/mcpl-transport-spawn.test.d.ts.map +0 -1
  665. package/dist/test/mcpl-transport-spawn.test.js +0 -58
  666. package/dist/test/mcpl-transport-spawn.test.js.map +0 -1
  667. package/dist/test/mcpl-ws-transport.test.d.ts +0 -2
  668. package/dist/test/mcpl-ws-transport.test.d.ts.map +0 -1
  669. package/dist/test/mcpl-ws-transport.test.js +0 -259
  670. package/dist/test/mcpl-ws-transport.test.js.map +0 -1
  671. package/dist/test/module-context-integration.test.d.ts +0 -18
  672. package/dist/test/module-context-integration.test.d.ts.map +0 -1
  673. package/dist/test/module-context-integration.test.js +0 -181
  674. package/dist/test/module-context-integration.test.js.map +0 -1
  675. package/dist/test/offline-recovery-branch.test.d.ts +0 -2
  676. package/dist/test/offline-recovery-branch.test.d.ts.map +0 -1
  677. package/dist/test/offline-recovery-branch.test.js +0 -570
  678. package/dist/test/offline-recovery-branch.test.js.map +0 -1
  679. package/dist/test/operator-surgery.test.d.ts +0 -2
  680. package/dist/test/operator-surgery.test.d.ts.map +0 -1
  681. package/dist/test/operator-surgery.test.js +0 -595
  682. package/dist/test/operator-surgery.test.js.map +0 -1
  683. package/dist/test/ops-alert.test.d.ts +0 -2
  684. package/dist/test/ops-alert.test.d.ts.map +0 -1
  685. package/dist/test/ops-alert.test.js +0 -153
  686. package/dist/test/ops-alert.test.js.map +0 -1
  687. package/dist/test/overbudget-drain-breaker.test.d.ts +0 -2
  688. package/dist/test/overbudget-drain-breaker.test.d.ts.map +0 -1
  689. package/dist/test/overbudget-drain-breaker.test.js +0 -198
  690. package/dist/test/overbudget-drain-breaker.test.js.map +0 -1
  691. package/dist/test/pack-installs-alone.test.d.ts +0 -2
  692. package/dist/test/pack-installs-alone.test.d.ts.map +0 -1
  693. package/dist/test/pack-installs-alone.test.js +0 -284
  694. package/dist/test/pack-installs-alone.test.js.map +0 -1
  695. package/dist/test/per-agent-delivery.test.d.ts +0 -2
  696. package/dist/test/per-agent-delivery.test.d.ts.map +0 -1
  697. package/dist/test/per-agent-delivery.test.js +0 -108
  698. package/dist/test/per-agent-delivery.test.js.map +0 -1
  699. package/dist/test/physical-window-restart.test.d.ts +0 -16
  700. package/dist/test/physical-window-restart.test.d.ts.map +0 -1
  701. package/dist/test/physical-window-restart.test.js +0 -487
  702. package/dist/test/physical-window-restart.test.js.map +0 -1
  703. package/dist/test/placed-reaction-baseline.test.d.ts +0 -2
  704. package/dist/test/placed-reaction-baseline.test.d.ts.map +0 -1
  705. package/dist/test/placed-reaction-baseline.test.js +0 -312
  706. package/dist/test/placed-reaction-baseline.test.js.map +0 -1
  707. package/dist/test/present-while-acting.test.d.ts +0 -19
  708. package/dist/test/present-while-acting.test.d.ts.map +0 -1
  709. package/dist/test/present-while-acting.test.js +0 -1649
  710. package/dist/test/present-while-acting.test.js.map +0 -1
  711. package/dist/test/prose-segments.test.d.ts +0 -2
  712. package/dist/test/prose-segments.test.d.ts.map +0 -1
  713. package/dist/test/prose-segments.test.js +0 -52
  714. package/dist/test/prose-segments.test.js.map +0 -1
  715. package/dist/test/prose-stream-router.test.d.ts +0 -2
  716. package/dist/test/prose-stream-router.test.d.ts.map +0 -1
  717. package/dist/test/prose-stream-router.test.js +0 -171
  718. package/dist/test/prose-stream-router.test.js.map +0 -1
  719. package/dist/test/provider-acceleration-cooldown.test.d.ts +0 -2
  720. package/dist/test/provider-acceleration-cooldown.test.d.ts.map +0 -1
  721. package/dist/test/provider-acceleration-cooldown.test.js +0 -435
  722. package/dist/test/provider-acceleration-cooldown.test.js.map +0 -1
  723. package/dist/test/provider-waits.test.d.ts +0 -2
  724. package/dist/test/provider-waits.test.d.ts.map +0 -1
  725. package/dist/test/provider-waits.test.js +0 -2259
  726. package/dist/test/provider-waits.test.js.map +0 -1
  727. package/dist/test/puppet-tool-call.test.d.ts +0 -2
  728. package/dist/test/puppet-tool-call.test.d.ts.map +0 -1
  729. package/dist/test/puppet-tool-call.test.js +0 -226
  730. package/dist/test/puppet-tool-call.test.js.map +0 -1
  731. package/dist/test/puppet-turn-reservation.test.d.ts +0 -2
  732. package/dist/test/puppet-turn-reservation.test.d.ts.map +0 -1
  733. package/dist/test/puppet-turn-reservation.test.js +0 -139
  734. package/dist/test/puppet-turn-reservation.test.js.map +0 -1
  735. package/dist/test/reaction-baseline-platform.test.d.ts +0 -2
  736. package/dist/test/reaction-baseline-platform.test.d.ts.map +0 -1
  737. package/dist/test/reaction-baseline-platform.test.js +0 -124
  738. package/dist/test/reaction-baseline-platform.test.js.map +0 -1
  739. package/dist/test/record-journal.test.d.ts +0 -6
  740. package/dist/test/record-journal.test.d.ts.map +0 -1
  741. package/dist/test/record-journal.test.js +0 -269
  742. package/dist/test/record-journal.test.js.map +0 -1
  743. package/dist/test/refusal-reaction-baseline.test.d.ts +0 -2
  744. package/dist/test/refusal-reaction-baseline.test.d.ts.map +0 -1
  745. package/dist/test/refusal-reaction-baseline.test.js +0 -81
  746. package/dist/test/refusal-reaction-baseline.test.js.map +0 -1
  747. package/dist/test/refusal-rewind.test.d.ts +0 -2
  748. package/dist/test/refusal-rewind.test.d.ts.map +0 -1
  749. package/dist/test/refusal-rewind.test.js +0 -117
  750. package/dist/test/refusal-rewind.test.js.map +0 -1
  751. package/dist/test/refusal-single-call.test.d.ts +0 -2
  752. package/dist/test/refusal-single-call.test.d.ts.map +0 -1
  753. package/dist/test/refusal-single-call.test.js +0 -177
  754. package/dist/test/refusal-single-call.test.js.map +0 -1
  755. package/dist/test/release-bump.test.d.ts +0 -2
  756. package/dist/test/release-bump.test.d.ts.map +0 -1
  757. package/dist/test/release-bump.test.js +0 -248
  758. package/dist/test/release-bump.test.js.map +0 -1
  759. package/dist/test/release-changelog.test.d.ts +0 -2
  760. package/dist/test/release-changelog.test.d.ts.map +0 -1
  761. package/dist/test/release-changelog.test.js +0 -159
  762. package/dist/test/release-changelog.test.js.map +0 -1
  763. package/dist/test/release-holds.test.d.ts +0 -2
  764. package/dist/test/release-holds.test.d.ts.map +0 -1
  765. package/dist/test/release-holds.test.js +0 -456
  766. package/dist/test/release-holds.test.js.map +0 -1
  767. package/dist/test/same-round-think-policy.test.d.ts +0 -2
  768. package/dist/test/same-round-think-policy.test.d.ts.map +0 -1
  769. package/dist/test/same-round-think-policy.test.js +0 -853
  770. package/dist/test/same-round-think-policy.test.js.map +0 -1
  771. package/dist/test/save-recent-image.test.d.ts +0 -26
  772. package/dist/test/save-recent-image.test.d.ts.map +0 -1
  773. package/dist/test/save-recent-image.test.js +0 -974
  774. package/dist/test/save-recent-image.test.js.map +0 -1
  775. package/dist/test/shutdown-errors.test.d.ts +0 -2
  776. package/dist/test/shutdown-errors.test.d.ts.map +0 -1
  777. package/dist/test/shutdown-errors.test.js +0 -662
  778. package/dist/test/shutdown-errors.test.js.map +0 -1
  779. package/dist/test/silent-heartbeat-rows.test.d.ts +0 -2
  780. package/dist/test/silent-heartbeat-rows.test.d.ts.map +0 -1
  781. package/dist/test/silent-heartbeat-rows.test.js +0 -451
  782. package/dist/test/silent-heartbeat-rows.test.js.map +0 -1
  783. package/dist/test/silent-heartbeat.test.d.ts +0 -2
  784. package/dist/test/silent-heartbeat.test.d.ts.map +0 -1
  785. package/dist/test/silent-heartbeat.test.js +0 -165
  786. package/dist/test/silent-heartbeat.test.js.map +0 -1
  787. package/dist/test/state-scaling-e2e.test.d.ts +0 -22
  788. package/dist/test/state-scaling-e2e.test.d.ts.map +0 -1
  789. package/dist/test/state-scaling-e2e.test.js +0 -206
  790. package/dist/test/state-scaling-e2e.test.js.map +0 -1
  791. package/dist/test/state-scaling.test.d.ts +0 -12
  792. package/dist/test/state-scaling.test.d.ts.map +0 -1
  793. package/dist/test/state-scaling.test.js +0 -251
  794. package/dist/test/state-scaling.test.js.map +0 -1
  795. package/dist/test/stop-with-host-operations.test.d.ts +0 -20
  796. package/dist/test/stop-with-host-operations.test.d.ts.map +0 -1
  797. package/dist/test/stop-with-host-operations.test.js +0 -1174
  798. package/dist/test/stop-with-host-operations.test.js.map +0 -1
  799. package/dist/test/stop-with-work-in-flight.test.d.ts +0 -23
  800. package/dist/test/stop-with-work-in-flight.test.d.ts.map +0 -1
  801. package/dist/test/stop-with-work-in-flight.test.js +0 -784
  802. package/dist/test/stop-with-work-in-flight.test.js.map +0 -1
  803. package/dist/test/surgery-marks-receipt.test.d.ts +0 -2
  804. package/dist/test/surgery-marks-receipt.test.d.ts.map +0 -1
  805. package/dist/test/surgery-marks-receipt.test.js +0 -540
  806. package/dist/test/surgery-marks-receipt.test.js.map +0 -1
  807. package/dist/test/thinking-token-stamp.test.d.ts +0 -12
  808. package/dist/test/thinking-token-stamp.test.d.ts.map +0 -1
  809. package/dist/test/thinking-token-stamp.test.js +0 -129
  810. package/dist/test/thinking-token-stamp.test.js.map +0 -1
  811. package/dist/test/timezone.test.d.ts +0 -2
  812. package/dist/test/timezone.test.d.ts.map +0 -1
  813. package/dist/test/timezone.test.js +0 -18
  814. package/dist/test/timezone.test.js.map +0 -1
  815. package/dist/test/tool-batch-hook.test.d.ts +0 -8
  816. package/dist/test/tool-batch-hook.test.d.ts.map +0 -1
  817. package/dist/test/tool-batch-hook.test.js +0 -275
  818. package/dist/test/tool-batch-hook.test.js.map +0 -1
  819. package/dist/test/tool-policy.test.d.ts +0 -2
  820. package/dist/test/tool-policy.test.d.ts.map +0 -1
  821. package/dist/test/tool-policy.test.js +0 -51
  822. package/dist/test/tool-policy.test.js.map +0 -1
  823. package/dist/test/tool-presentation.test.d.ts +0 -2
  824. package/dist/test/tool-presentation.test.d.ts.map +0 -1
  825. package/dist/test/tool-presentation.test.js +0 -268
  826. package/dist/test/tool-presentation.test.js.map +0 -1
  827. package/dist/test/tool-result-content.test.d.ts +0 -2
  828. package/dist/test/tool-result-content.test.d.ts.map +0 -1
  829. package/dist/test/tool-result-content.test.js +0 -37
  830. package/dist/test/tool-result-content.test.js.map +0 -1
  831. package/dist/test/tool-result-guard.test.d.ts +0 -2
  832. package/dist/test/tool-result-guard.test.d.ts.map +0 -1
  833. package/dist/test/tool-result-guard.test.js +0 -3729
  834. package/dist/test/tool-result-guard.test.js.map +0 -1
  835. package/dist/test/tool-result-history.test.d.ts +0 -7
  836. package/dist/test/tool-result-history.test.d.ts.map +0 -1
  837. package/dist/test/tool-result-history.test.js +0 -156
  838. package/dist/test/tool-result-history.test.js.map +0 -1
  839. package/dist/test/tool-result-spill.test.d.ts +0 -13
  840. package/dist/test/tool-result-spill.test.d.ts.map +0 -1
  841. package/dist/test/tool-result-spill.test.js +0 -586
  842. package/dist/test/tool-result-spill.test.js.map +0 -1
  843. package/dist/test/tool-wrapper-prose-guard-integration.test.d.ts +0 -2
  844. package/dist/test/tool-wrapper-prose-guard-integration.test.d.ts.map +0 -1
  845. package/dist/test/tool-wrapper-prose-guard-integration.test.js +0 -485
  846. package/dist/test/tool-wrapper-prose-guard-integration.test.js.map +0 -1
  847. package/dist/test/tool-wrapper-prose-guard.test.d.ts +0 -2
  848. package/dist/test/tool-wrapper-prose-guard.test.d.ts.map +0 -1
  849. package/dist/test/tool-wrapper-prose-guard.test.js +0 -34
  850. package/dist/test/tool-wrapper-prose-guard.test.js.map +0 -1
  851. package/dist/test/tools-observe-parser-conformance.test.d.ts +0 -2
  852. package/dist/test/tools-observe-parser-conformance.test.d.ts.map +0 -1
  853. package/dist/test/tools-observe-parser-conformance.test.js +0 -129
  854. package/dist/test/tools-observe-parser-conformance.test.js.map +0 -1
  855. package/dist/test/trunk-channel-routing.test.d.ts +0 -19
  856. package/dist/test/trunk-channel-routing.test.d.ts.map +0 -1
  857. package/dist/test/trunk-channel-routing.test.js +0 -652
  858. package/dist/test/trunk-channel-routing.test.js.map +0 -1
  859. package/dist/test/tune-out-e2e.test.d.ts +0 -2
  860. package/dist/test/tune-out-e2e.test.d.ts.map +0 -1
  861. package/dist/test/tune-out-e2e.test.js +0 -142
  862. package/dist/test/tune-out-e2e.test.js.map +0 -1
  863. package/dist/test/tune-out-gate-composition.test.d.ts +0 -2
  864. package/dist/test/tune-out-gate-composition.test.d.ts.map +0 -1
  865. package/dist/test/tune-out-gate-composition.test.js +0 -221
  866. package/dist/test/tune-out-gate-composition.test.js.map +0 -1
  867. package/dist/test/tune-out-lifecycle.test.d.ts +0 -2
  868. package/dist/test/tune-out-lifecycle.test.d.ts.map +0 -1
  869. package/dist/test/tune-out-lifecycle.test.js +0 -121
  870. package/dist/test/tune-out-lifecycle.test.js.map +0 -1
  871. package/dist/test/turn-trigger-provenance.test.d.ts +0 -2
  872. package/dist/test/turn-trigger-provenance.test.d.ts.map +0 -1
  873. package/dist/test/turn-trigger-provenance.test.js +0 -137
  874. package/dist/test/turn-trigger-provenance.test.js.map +0 -1
  875. package/dist/test/unconvertible-tool-result.test.d.ts +0 -2
  876. package/dist/test/unconvertible-tool-result.test.d.ts.map +0 -1
  877. package/dist/test/unconvertible-tool-result.test.js +0 -358
  878. package/dist/test/unconvertible-tool-result.test.js.map +0 -1
  879. package/dist/test/unsent-compiles.test.d.ts +0 -2
  880. package/dist/test/unsent-compiles.test.d.ts.map +0 -1
  881. package/dist/test/unsent-compiles.test.js +0 -139
  882. package/dist/test/unsent-compiles.test.js.map +0 -1
  883. package/dist/test/usage-accounting.test.d.ts +0 -2
  884. package/dist/test/usage-accounting.test.d.ts.map +0 -1
  885. package/dist/test/usage-accounting.test.js +0 -13
  886. package/dist/test/usage-accounting.test.js.map +0 -1
  887. package/dist/test/usage-tracker.test.d.ts +0 -2
  888. package/dist/test/usage-tracker.test.d.ts.map +0 -1
  889. package/dist/test/usage-tracker.test.js +0 -129
  890. package/dist/test/usage-tracker.test.js.map +0 -1
  891. package/dist/test/utils-surface.test.d.ts +0 -2
  892. package/dist/test/utils-surface.test.d.ts.map +0 -1
  893. package/dist/test/utils-surface.test.js +0 -145
  894. package/dist/test/utils-surface.test.js.map +0 -1
  895. package/dist/test/workspace-branch-continuation.test.d.ts +0 -15
  896. package/dist/test/workspace-branch-continuation.test.d.ts.map +0 -1
  897. package/dist/test/workspace-branch-continuation.test.js +0 -183
  898. package/dist/test/workspace-branch-continuation.test.js.map +0 -1
  899. package/dist/test/workspace-materialize-freshness.test.d.ts +0 -16
  900. package/dist/test/workspace-materialize-freshness.test.d.ts.map +0 -1
  901. package/dist/test/workspace-materialize-freshness.test.js +0 -252
  902. package/dist/test/workspace-materialize-freshness.test.js.map +0 -1
  903. package/dist/test/workspace-path-containment.test.d.ts +0 -19
  904. package/dist/test/workspace-path-containment.test.d.ts.map +0 -1
  905. package/dist/test/workspace-path-containment.test.js +0 -91
  906. package/dist/test/workspace-path-containment.test.js.map +0 -1
  907. package/dist/test/workspace-read-file-from-disk.test.d.ts +0 -17
  908. package/dist/test/workspace-read-file-from-disk.test.d.ts.map +0 -1
  909. package/dist/test/workspace-read-file-from-disk.test.js +0 -174
  910. package/dist/test/workspace-read-file-from-disk.test.js.map +0 -1
  911. package/dist/test/workspace-read-image.test.d.ts +0 -2
  912. package/dist/test/workspace-read-image.test.d.ts.map +0 -1
  913. package/dist/test/workspace-read-image.test.js +0 -597
  914. package/dist/test/workspace-read-image.test.js.map +0 -1
  915. package/dist/test/workspace-read-text.test.d.ts +0 -2
  916. package/dist/test/workspace-read-text.test.d.ts.map +0 -1
  917. package/dist/test/workspace-read-text.test.js +0 -101
  918. package/dist/test/workspace-read-text.test.js.map +0 -1
  919. package/dist/test/workspace-restore-order.test.d.ts +0 -16
  920. package/dist/test/workspace-restore-order.test.d.ts.map +0 -1
  921. package/dist/test/workspace-restore-order.test.js +0 -140
  922. package/dist/test/workspace-restore-order.test.js.map +0 -1
  923. package/dist/test/workspace-three-way.test.d.ts +0 -12
  924. package/dist/test/workspace-three-way.test.d.ts.map +0 -1
  925. package/dist/test/workspace-three-way.test.js +0 -4094
  926. package/dist/test/workspace-three-way.test.js.map +0 -1
  927. package/dist/test/workspace-watcher.test.d.ts +0 -2
  928. package/dist/test/workspace-watcher.test.d.ts.map +0 -1
  929. package/dist/test/workspace-watcher.test.js +0 -281
  930. package/dist/test/workspace-watcher.test.js.map +0 -1
  931. package/dist/test/xml-round-persist.test.d.ts +0 -19
  932. package/dist/test/xml-round-persist.test.d.ts.map +0 -1
  933. package/dist/test/xml-round-persist.test.js +0 -235
  934. package/dist/test/xml-round-persist.test.js.map +0 -1
  935. package/dist/tsconfig.tsbuildinfo +0 -1
@@ -11,10 +11,10 @@
11
11
 
12
12
  import { EventEmitter } from 'node:events';
13
13
 
14
- import { openTransport, type McplTransport, type TransportCloseInfo } from './transport.js';
14
+ import { openTransport, STDERR_END_WAIT_MS, type McplTransport, type TransportCloseInfo } from './transport.js';
15
15
  import { maskNegotiatedCapabilities } from './capability-mask.js';
16
16
  import { CapabilityGrant, expandAdvertisementShorthand } from './capability-grant.js';
17
- import { CAPABILITY_DISABLED } from './errors.js';
17
+ import { CAPABILITY_DISABLED, boundedForLog, describeCause } from './errors.js';
18
18
  import { logDetail, logValue } from './log-value.js';
19
19
 
20
20
  import type {
@@ -95,6 +95,20 @@ export function withStderr(error: unknown): string {
95
95
  return '. The last of its stderr:' + tail.split('\n').map((line) => `\n stderr: ${logDetail(line)}`).join('');
96
96
  }
97
97
 
98
+ /** A transport close's reason, as an error message gives it: the transport's
99
+ * own words. A WebSocket peer's close reason is the server's text
100
+ * (`reasonFromPeer`), so an error gives the words the transport uses for a
101
+ * close without one, as `mcpl:server-closed` leaves that text out. A
102
+ * WebSocket close's code, a number, says what the server meant (4001: a
103
+ * refused credential), with or without a reason, so each error gives it too:
104
+ * a pending request's error has `code=`, and the handshake's adds it for any
105
+ * WebSocket close, since a close before the handshake completes reaches no
106
+ * 'close' event. A stdio child's exit reads as before. */
107
+ function closeReasonText(info: TransportCloseInfo): string {
108
+ if (info.reasonFromPeer) return 'websocket closed';
109
+ return info.reason ?? 'unknown';
110
+ }
111
+
98
112
  /** Default per-request timeout in milliseconds (see McplServerConfig.requestTimeoutMs).
99
113
  * A live-but-wedged server (accepts requests, never answers, never closes its
100
114
  * transport) would otherwise freeze the awaiting agent turn forever — no
@@ -105,6 +119,33 @@ const DEFAULT_REQUEST_TIMEOUT_MS = 60_000;
105
119
  /** MCP protocol version used in the initialize handshake. */
106
120
  const MCP_PROTOCOL_VERSION = '2024-11-05';
107
121
 
122
+ /**
123
+ * Why a request to an MCPL server produced no result, as far as the host can
124
+ * know it. Messages are unchanged from plain errors; the `outcome` makes the
125
+ * difference between "never left the host" and "left, and no answer came
126
+ * back" a fact a caller can act on instead of a string to match:
127
+ * - `not-sent`: the request was refused before anything was written (the
128
+ * connection was already closed);
129
+ * - `error-response`: the server answered with a JSON-RPC error (it may have
130
+ * acted before failing; the error alone does not say);
131
+ * - `no-response`: the request was handed to the transport and no answer
132
+ * came back (timeout, or the connection closed while awaiting). It does
133
+ * not prove the request reached the server — the transport can decline or
134
+ * drop a write — only that the host can no longer say it didn't.
135
+ */
136
+ export class McplRequestError extends Error {
137
+ constructor(
138
+ message: string,
139
+ readonly outcome: 'not-sent' | 'error-response' | 'no-response',
140
+ /** The JSON-RPC error's `data`, verbatim, when the server supplied one
141
+ * (e.g. which parts of a multi-part send were posted). */
142
+ readonly data?: unknown,
143
+ ) {
144
+ super(message);
145
+ this.name = 'McplRequestError';
146
+ }
147
+ }
148
+
108
149
  /**
109
150
  * Represents a pending JSON-RPC request awaiting a response.
110
151
  */
@@ -123,6 +164,13 @@ interface RequestOptions {
123
164
  surfaceOrphanedResponse?: boolean;
124
165
  }
125
166
 
167
+ /** A request's method for a log line, whatever the server sent there. */
168
+ function describeMethod(method: unknown): string {
169
+ return typeof method === 'string'
170
+ ? `method ${logValue(method)}`
171
+ : `a method of type ${method === null ? 'null' : typeof method}`;
172
+ }
173
+
126
174
  /**
127
175
  * McplServerConnection manages a single JSON-RPC 2.0 connection to an
128
176
  * MCPL server over stdio. Use the static `connect()` factory to create
@@ -255,7 +303,10 @@ export class McplServerConnection extends EventEmitter {
255
303
  private pendingRequests = new Map<string | number, PendingRequest>();
256
304
  /** Metadata retained after selected request deadlines so a late response is
257
305
  * observable even though its original promise has already been rejected. */
258
- private orphanedRequests = new Map<string | number, { method: string; renderParams?: Record<string, unknown> }>();
306
+ private orphanedRequests = new Map<string | number, {
307
+ method: string;
308
+ renderParams?: { featureSet: string; key: string; eventId: string; channelId?: string };
309
+ }>();
259
310
  private closed = false;
260
311
  /** Set by `reconnectAfterFailure()` before it closes a live transport, so
261
312
  * the transport close handler reports that teardown as `byHost: true`. */
@@ -266,6 +317,9 @@ export class McplServerConnection extends EventEmitter {
266
317
 
267
318
  /** Per-request timeout in ms (0 disables). See McplServerConfig.requestTimeoutMs. */
268
319
  private requestTimeoutMs = DEFAULT_REQUEST_TIMEOUT_MS;
320
+ /** The deadline a channels/publish or channels/open request keeps when
321
+ * requestTimeoutMs is 0 (see sendChannelsPublish). */
322
+ private publishDeadlineMs = DEFAULT_REQUEST_TIMEOUT_MS;
269
323
 
270
324
  // Event buffering: control-plane traffic can be released independently from
271
325
  // inference-bearing data-plane traffic. This lets a server finish its own
@@ -274,15 +328,24 @@ export class McplServerConnection extends EventEmitter {
274
328
  private controlPlaneReady = false;
275
329
  private dataPlaneReady = false;
276
330
  private bufferedEvents: Array<{ event: string; args: unknown[] }> = [];
277
- /** Cap on buffered responder-less events during a plane pause (issue #122).
278
- * Held server→host requests are never dropped and may exceed this. */
279
- private static readonly MAX_BUFFERED_EVENTS = 1000;
331
+ /** How many of bufferedEvents are server→host requests, each holding a
332
+ * responder its server waits on. Every change to bufferedEvents keeps it. */
333
+ private heldRequests = 0;
334
+ /** Cap on held notifications (responder-less events) during a plane pause
335
+ * (issue #122), counted apart from requests: past it, the oldest held
336
+ * notification is dropped. */
337
+ private static readonly MAX_HELD_NOTIFICATIONS = 1000;
338
+ /** Budget of held requests during a plane pause (#387), counted apart from
339
+ * notifications: past it, a request is refused at once, never dropped. It
340
+ * bounds a server that pipelines requests without waiting for answers. A
341
+ * server that doesn't send a refused request again loses it (discord-mcpl
342
+ * doesn't), so the budget sits far above the notifications' cap, to leave
343
+ * a busy server's long pause room. */
344
+ private static readonly MAX_HELD_REQUESTS = 10_000;
280
345
  private droppedBufferedEvents = 0;
281
- /** True while ready()/readyControlPlane() re-emit a buffer snapshot. Items
282
- * re-buffering mid-flush were already admitted once — applying the cap to
283
- * them again would evict events that were legally held (the cap targets
284
- * NEW arrivals during a pause, not churn from control-plane flushes). */
285
- private flushDepth = 0;
346
+ /** Requests refused at the budget since the planes last opened (ready()),
347
+ * so each pause's first refusal is logged. */
348
+ private refusedHeldRequests = 0;
286
349
 
287
350
  // Reconnect state (adapted from Anarchid/agent-framework@mcpl-module-proto)
288
351
  private config: McplServerConfig | null = null;
@@ -301,6 +364,13 @@ export class McplServerConnection extends EventEmitter {
301
364
  return this.reconnectEnabled;
302
365
  }
303
366
 
367
+ /** Closed with no reconnect to come: after close(), whether or not its
368
+ * transport close succeeded, or a drop with reconnect off. A connection
369
+ * between retries keeps reconnectEnabled, so it isn't closed for good. */
370
+ private get closedForGood(): boolean {
371
+ return this.closed && !this.reconnectEnabled;
372
+ }
373
+
304
374
  /**
305
375
  * Private constructor. Use `McplServerConnection.connect()` instead.
306
376
  */
@@ -328,28 +398,38 @@ export class McplServerConnection extends EventEmitter {
328
398
  * Mark the connection as ready — flushes any events that arrived between
329
399
  * construction (when setupMessageRouting starts emitting) and now (when
330
400
  * the caller has attached listeners via wireMcplEvents).
401
+ *
402
+ * Does nothing once the connection is closed for good. Its policy was reset
403
+ * when it closed, so what it held that needs a grant would be refused, and a
404
+ * closed connection sends no response, so nothing it held could be answered.
405
+ * Only what needs no grant would pass, to listeners of a server that won't
406
+ * be served again. A connection between retries isn't closed for good: what
407
+ * it held, such as a reconnect stub's connect-failed, still reaches its
408
+ * listeners.
331
409
  */
332
410
  ready(): void {
411
+ if (this.closedForGood) return;
333
412
  this.controlPlaneReady = true;
334
413
  this.dataPlaneReady = true;
335
414
  const pending = this.bufferedEvents;
336
415
  this.bufferedEvents = [];
416
+ // The cap's drops are counted per pause: this flush ends one, so its line
417
+ // reports that pause's drops, and the next pause counts (and logs) its own.
418
+ const dropped = this.droppedBufferedEvents;
419
+ this.droppedBufferedEvents = 0;
420
+ this.heldRequests = 0;
421
+ this.refusedHeldRequests = 0;
337
422
  if (pending.length > 200) {
338
423
  console.error(
339
424
  `[mcpl] ${this.id}: flushing ${pending.length} buffered event(s) synchronously ` +
340
- `(long pause backlog${this.droppedBufferedEvents > 0 ? `; ${this.droppedBufferedEvents} dropped at cap` : ''})`,
425
+ `(long pause backlog${dropped > 0 ? `; ${dropped} dropped at cap` : ''})`,
341
426
  );
342
427
  }
343
- this.flushDepth++;
344
- try {
345
- for (const { event, args } of pending) {
346
- // Re-enter the gate for every buffered item. A control handler (notably
347
- // tools/list_changed) may install a newer data-plane barrier while this
348
- // snapshot is being flushed; later data items must observe that pause.
349
- this.emit(event, ...args);
350
- }
351
- } finally {
352
- this.flushDepth--;
428
+ for (const { event, args } of pending) {
429
+ // Re-enter the gate for every buffered item. A control handler (notably
430
+ // tools/list_changed) may install a newer data-plane barrier while this
431
+ // snapshot is being flushed; later data items must observe that pause.
432
+ this.dispatchInboundEvent(event, ...args);
353
433
  }
354
434
  }
355
435
 
@@ -357,24 +437,22 @@ export class McplServerConnection extends EventEmitter {
357
437
  * Release only server-establishment and lifecycle/control traffic. Responses
358
438
  * to host requests are never event-buffered, so tools/list and tools/call
359
439
  * responses remain live as well. Inference-bearing requests stay queued in
360
- * their original relative order until {@link ready} is called.
440
+ * their original relative order until {@link ready} is called. Like
441
+ * {@link ready}, it does nothing once the connection is closed for good.
361
442
  */
362
443
  readyControlPlane(): void {
444
+ if (this.closedForGood) return;
363
445
  this.controlPlaneReady = true;
364
446
  const pending = this.bufferedEvents;
365
447
  this.bufferedEvents = [];
366
- this.flushDepth++;
367
- try {
368
- for (const item of pending) {
369
- // Re-enter the ADMISSION gate (this.emit), never super.emit: control
370
- // events include channels-register/changed, which are grant-gated —
371
- // the old direct flush bypassed positive-grant enforcement entirely
372
- // (PR #79 review blocker 3). Data-plane items re-buffer in order via
373
- // the same call, since dataPlaneReady is still false.
374
- this.emit(item.event, ...item.args);
375
- }
376
- } finally {
377
- this.flushDepth--;
448
+ this.heldRequests = 0;
449
+ for (const item of pending) {
450
+ // Re-enter the ADMISSION gate (this.emit), never super.emit: control
451
+ // events include channels-register/changed, which are grant-gated —
452
+ // the old direct flush bypassed positive-grant enforcement entirely
453
+ // (PR #79 review blocker 3). Data-plane items re-buffer in order via
454
+ // the same call, since dataPlaneReady is still false.
455
+ this.dispatchInboundEvent(item.event, ...item.args);
378
456
  }
379
457
  }
380
458
 
@@ -433,40 +511,80 @@ export class McplServerConnection extends EventEmitter {
433
511
  }
434
512
  return true;
435
513
  }
514
+ // §6.6: a request that will never be answered MUST get an error. A
515
+ // request whose event nothing on this host listens for would never be.
516
+ const request = args[1] as {
517
+ respond?: (result: unknown) => void;
518
+ respondError?: (code: number, message: string, data?: unknown) => void;
519
+ } | undefined;
520
+ if (typeof request?.respondError === 'function' && this.listenerCount(event) === 0) {
521
+ request.respondError(-32601, 'Method not found');
522
+ console.error(`[mcpl] ${this.id}: answered -32601 to ${logValue(name)}, which nothing on this host handles`);
523
+ return true;
524
+ }
525
+ // mcpl/manifestChanged (§17.3) and tools/list_changed are notifications.
526
+ // Sent as a request, either is answered with an empty result as it's
527
+ // admitted, and passed on as the notification is, with no responder:
528
+ // the host acts on it the same way, so the answer doesn't depend on what
529
+ // the refresh does, and it's written before any request the refresh
530
+ // sends. This is where live routing and buffer flushes meet, so a request
531
+ // held while its plane is closed is answered only when it's let through,
532
+ // never by a startup that fails first.
533
+ if ((name === 'manifest-changed' || name === 'tools-list-changed') && typeof request?.respond === 'function') {
534
+ request.respond({});
535
+ return super.emit(event, args[0]);
536
+ }
436
537
  return super.emit(event, ...args);
437
538
  }
438
- // Buffer cap (issue #122): a long data-plane pause (quiesce window) on a
439
- // busy server would otherwise grow this array without bound. Only
440
- // responder-LESS events are ever dropped — a buffered server→host REQUEST
441
- // holds a live responder the server is blocking on, and dropping it would
442
- // strand that call forever (the server timing out and reconnecting is the
443
- // accepted bound there, and reconnect re-runs the barrier funnel).
444
- if (this.flushDepth === 0 && this.bufferedEvents.length >= McplServerConnection.MAX_BUFFERED_EVENTS) {
445
- const hasResponder = (item: { args: unknown[] }): boolean => {
446
- const responder = item.args[1] as { respond?: unknown } | undefined;
447
- return typeof responder?.respond === 'function';
448
- };
449
- if (!hasResponder({ args })) {
450
- this.droppedBufferedEvents++;
451
- if (this.droppedBufferedEvents % 100 === 1) {
452
- console.error(
453
- `[mcpl] ${this.id}: buffered-event cap (${McplServerConnection.MAX_BUFFERED_EVENTS}) — ` +
454
- `dropped ${this.droppedBufferedEvents} responder-less event(s) while the plane is paused`,
455
- );
456
- }
457
- const dropIndex = this.bufferedEvents.findIndex((item) => !hasResponder(item));
458
- if (dropIndex >= 0) {
459
- this.bufferedEvents.splice(dropIndex, 1); // drop-oldest non-request
460
- this.bufferedEvents.push({ event: name, args });
461
- }
462
- // else: buffer is all held requests — drop the incoming event instead.
463
- return true;
539
+ // Held until the plane opens. A long pause (a quiesce, say) on a busy or a
540
+ // runaway server would otherwise grow this array without bound, so
541
+ // requests and notifications each have a bound, counted apart. A request
542
+ // holds a responder its server waits on, and dropping it would strand that
543
+ // call, so past MAX_HELD_REQUESTS (#387) it's refused at once with -32000,
544
+ // the code of the host's other transient refusals, and its server can send
545
+ // it again. A notification has no one to tell, so past
546
+ // MAX_HELD_NOTIFICATIONS (issue #122) the oldest held notification is
547
+ // dropped to make room. A flush takes the whole buffer and zeroes its
548
+ // count, so what it holds again was admitted within these bounds and
549
+ // stays within them.
550
+ const responder = args[1] as { respond?: unknown; respondError?: (code: number, message: string) => void } | undefined;
551
+ const isRequest = McplServerConnection.hasResponder({ args });
552
+ if (isRequest && this.heldRequests >= McplServerConnection.MAX_HELD_REQUESTS) {
553
+ this.refusedHeldRequests++;
554
+ if (this.refusedHeldRequests % 100 === 1) {
555
+ console.error(
556
+ `[mcpl] ${this.id}: held-request budget (${McplServerConnection.MAX_HELD_REQUESTS}) — ` +
557
+ `refused ${this.refusedHeldRequests} request(s) with -32000 while the plane is paused`,
558
+ );
464
559
  }
560
+ responder?.respondError?.(
561
+ -32000,
562
+ `the host is busy: ${McplServerConnection.MAX_HELD_REQUESTS} of this server's requests are already waiting; send this one again later`,
563
+ );
564
+ return true;
565
+ }
566
+ if (!isRequest && this.bufferedEvents.length - this.heldRequests >= McplServerConnection.MAX_HELD_NOTIFICATIONS) {
567
+ this.droppedBufferedEvents++;
568
+ if (this.droppedBufferedEvents % 100 === 1) {
569
+ console.error(
570
+ `[mcpl] ${this.id}: buffered-event cap (${McplServerConnection.MAX_HELD_NOTIFICATIONS}) — ` +
571
+ `dropped ${this.droppedBufferedEvents} responder-less event(s) while the plane is paused`,
572
+ );
573
+ }
574
+ const oldest = this.bufferedEvents.findIndex((item) => !McplServerConnection.hasResponder(item));
575
+ if (oldest >= 0) this.bufferedEvents.splice(oldest, 1);
465
576
  }
466
577
  this.bufferedEvents.push({ event: name, args });
578
+ if (isRequest) this.heldRequests++;
467
579
  return true;
468
580
  }
469
581
 
582
+ /** A buffered server→host request: it carries a responder its server waits on. */
583
+ private static hasResponder(item: { args: unknown[] }): boolean {
584
+ const responder = item.args[1] as { respond?: unknown } | undefined;
585
+ return typeof responder?.respond === 'function';
586
+ }
587
+
470
588
  /** Event-name form of METHOD_TO_REQUIRED_CAPABILITY, for admission-time
471
589
  * enforcement in emit(). */
472
590
  private static readonly EVENT_TO_REQUIRED_CAPABILITY: Record<string, string> = {
@@ -533,8 +651,9 @@ export class McplServerConnection extends EventEmitter {
533
651
  connection.allowHostCommands = config.allowHostCommands === true;
534
652
  connection.requestTimeoutMs = config.requestTimeoutMs ?? DEFAULT_REQUEST_TIMEOUT_MS;
535
653
 
536
- // Store config for reconnection
537
- if (config.reconnect) {
654
+ // Store config for reconnection. Only `true` turns reconnect on, as at
655
+ // every other reader of it.
656
+ if (config.reconnect === true) {
538
657
  connection.config = config;
539
658
  connection.hostCapabilities = hostCapabilities;
540
659
  connection.reconnectEnabled = true;
@@ -606,10 +725,30 @@ export class McplServerConnection extends EventEmitter {
606
725
  } catch {
607
726
  return; // Ignore non-JSON lines (e.g. logback output from Java servers)
608
727
  }
728
+ if (msg === null || typeof msg !== 'object' || Array.isArray(msg)) return;
729
+ // A request or a notification from the server is never the
730
+ // initialize response, whatever its id: a server's own ids can start
731
+ // at 0, this handshake's. MCP lets a server ping before
732
+ // initialization completes, and the ping gets its empty result, as
733
+ // on a connected transport. Anything else it sends now is ignored.
734
+ if ('method' in msg) {
735
+ const request = msg as unknown as JsonRpcRequest;
736
+ if (request.method === 'ping' && request.id != null) {
737
+ transport.writeLine(JSON.stringify({ jsonrpc: '2.0', id: request.id, result: {} }));
738
+ }
739
+ return;
740
+ }
609
741
  if (msg.id !== initId) return;
610
742
  cleanup();
611
743
  if (msg.error) {
612
- reject(new Error(`MCPL server "${config.id}" initialize error: ${msg.error.message}`));
744
+ // describeCause rather than the template's own conversion: the
745
+ // server's `message` can be any JSON value, and one that has no
746
+ // primitive form, such as {"toString":1}, would throw out of this
747
+ // listener after cleanup() has cleared the timeout: an uncaught
748
+ // exception, which ends a host that doesn't catch them, and a
749
+ // handshake left to wait forever. It's the server's text in an
750
+ // error's message, so it's bounded as errors.ts says.
751
+ reject(new Error(`MCPL server "${config.id}" initialize error: ${boundedForLog(describeCause(msg.error.message))}`));
613
752
  return;
614
753
  }
615
754
  const result = msg.result as Record<string, unknown> | undefined;
@@ -625,7 +764,14 @@ export class McplServerConnection extends EventEmitter {
625
764
  };
626
765
  const onClose = (info: TransportCloseInfo) => {
627
766
  cleanup();
628
- reject(failed(`MCPL server "${config.id}" transport closed before handshake completed (${info.reason ?? 'unknown'})`));
767
+ const code = transport.kind === 'websocket' && typeof info.code === 'number' ? `, code ${info.code}` : '';
768
+ const failure = `MCPL server "${config.id}" transport closed before handshake completed (${closeReasonText(info)}${code})`;
769
+ // The close comes at a stdio child's exit, which Node can emit before
770
+ // it has read the last of the child's stderr, or when the host closes
771
+ // the transport, which then ends the child. The tail is taken once
772
+ // stderr has ended, waiting at most STDERR_END_WAIT_MS. A WebSocket
773
+ // transport has no stderr to wait for.
774
+ void transport.stderrEnded(STDERR_END_WAIT_MS).then(() => reject(failed(failure)));
629
775
  };
630
776
  const onError = (err: Error) => {
631
777
  cleanup();
@@ -683,7 +829,7 @@ export class McplServerConnection extends EventEmitter {
683
829
  try {
684
830
  return await McplServerConnection.connect(config, hostCapabilities);
685
831
  } catch (error) {
686
- if (!config.reconnect) {
832
+ if (config.reconnect !== true) {
687
833
  throw error;
688
834
  }
689
835
 
@@ -798,9 +944,13 @@ export class McplServerConnection extends EventEmitter {
798
944
  return this.sendRequest(McplMethod.StateRollback, params as unknown as Record<string, unknown>) as Promise<StateRollbackResult>;
799
945
  }
800
946
 
801
- /** Send `channels/open` request and await result. */
947
+ /** Send `channels/open` request and await result. It keeps a deadline as
948
+ * channels/publish does: a delivery opens a closed channel before it
949
+ * publishes, so an open that is never answered would hold the delivery,
950
+ * and the turn that waits for it, for good. */
802
951
  sendChannelsOpen(params: ChannelsOpenParams): Promise<ChannelsOpenResult> {
803
- return this.sendRequest(McplMethod.ChannelsOpen, params as unknown as Record<string, unknown>) as Promise<ChannelsOpenResult>;
952
+ const timeoutMs = this.requestTimeoutMs > 0 ? this.requestTimeoutMs : this.publishDeadlineMs;
953
+ return this.sendRequest(McplMethod.ChannelsOpen, params as unknown as Record<string, unknown>, { timeoutMs }) as Promise<ChannelsOpenResult>;
804
954
  }
805
955
 
806
956
  /** Send `channels/close` request and await result. */
@@ -825,13 +975,20 @@ export class McplServerConnection extends EventEmitter {
825
975
  * Send `channels/publish`.
826
976
  * May be sent as a request (if an ACK is desired) or notification.
827
977
  * When `params.stream` is true, sends as a notification (no ACK).
978
+ *
979
+ * A request always has a deadline: the server's requestTimeoutMs, or
980
+ * publishDeadlineMs when that is 0 (disabled). A publish is a side effect
981
+ * whose outcome the resident is told and a held draft's attempt records,
982
+ * so one that is never answered would hold both open for good. Its expiry
983
+ * is a no-response, which the caller reads as unknown.
828
984
  */
829
985
  sendChannelsPublish(params: ChannelsPublishParams): Promise<ChannelsPublishResult | void> {
830
986
  if (params.stream) {
831
987
  this.sendNotification(McplMethod.ChannelsPublish, params as unknown as Record<string, unknown>);
832
988
  return Promise.resolve();
833
989
  }
834
- return this.sendRequest(McplMethod.ChannelsPublish, params as unknown as Record<string, unknown>) as Promise<ChannelsPublishResult>;
990
+ const timeoutMs = this.requestTimeoutMs > 0 ? this.requestTimeoutMs : this.publishDeadlineMs;
991
+ return this.sendRequest(McplMethod.ChannelsPublish, params as unknown as Record<string, unknown>, { timeoutMs }) as Promise<ChannelsPublishResult>;
835
992
  }
836
993
 
837
994
  /** Send `channels/outgoing/chunk` notification. */
@@ -924,7 +1081,7 @@ export class McplServerConnection extends EventEmitter {
924
1081
  // Reject all pending requests
925
1082
  for (const [id, pending] of this.pendingRequests) {
926
1083
  if (pending.timer) clearTimeout(pending.timer);
927
- pending.reject(new Error(`Connection to MCPL server "${this.id}" closed while awaiting response for ${pending.method} (id=${id})`));
1084
+ pending.reject(new McplRequestError(`Connection to MCPL server "${this.id}" closed while awaiting response for ${pending.method} (id=${id})`, 'no-response'));
928
1085
  }
929
1086
  this.pendingRequests.clear();
930
1087
  this.orphanedRequests.clear();
@@ -935,7 +1092,8 @@ export class McplServerConnection extends EventEmitter {
935
1092
  const attempt = Promise.resolve().then(async () => {
936
1093
  // An already opened handshake owns a transport too. It hands that
937
1094
  // transport back without admission once reconnect has been disabled.
938
- // The registry bounds this wait; retry reuses this real close attempt.
1095
+ // Only the registry's closeAll bounds its caller's wait for this; retry
1096
+ // reuses this real close attempt.
939
1097
  if (this.reconnectPromise) await this.reconnectPromise;
940
1098
  if (this.transport) await this.transport.close();
941
1099
  this.closeIncomplete = false;
@@ -1099,7 +1257,7 @@ export class McplServerConnection extends EventEmitter {
1099
1257
  options: RequestOptions = {},
1100
1258
  ): Promise<unknown> {
1101
1259
  if (this.closed) {
1102
- return Promise.reject(new Error(`Cannot send request: connection to "${this.id}" is closed`));
1260
+ return Promise.reject(new McplRequestError(`Cannot send request: connection to "${this.id}" is closed`, 'not-sent'));
1103
1261
  }
1104
1262
 
1105
1263
  const id = this.nextRequestId++;
@@ -1117,23 +1275,47 @@ export class McplServerConnection extends EventEmitter {
1117
1275
  pending.timer = setTimeout(() => {
1118
1276
  this.pendingRequests.delete(id);
1119
1277
  if (options.surfaceOrphanedResponse) {
1120
- this.orphanedRequests.set(id, { method, ...(method === 'push/render' ? { renderParams: { featureSet: params.featureSet, key: params.key, eventId: params.eventId } } : {}) });
1278
+ this.orphanedRequests.set(id, {
1279
+ method,
1280
+ ...(method === 'push/render'
1281
+ ? {
1282
+ renderParams: {
1283
+ featureSet: params.featureSet as string,
1284
+ key: params.key as string,
1285
+ eventId: params.eventId as string,
1286
+ ...(typeof params.channelId === 'string' ? { channelId: params.channelId } : {}),
1287
+ },
1288
+ }
1289
+ : {}),
1290
+ });
1121
1291
  if (this.orphanedRequests.size > 4096) this.orphanedRequests.delete(this.orphanedRequests.keys().next().value!);
1122
1292
  }
1123
- reject(new Error(
1293
+ reject(new McplRequestError(
1124
1294
  `MCPL server "${this.id}" did not respond to ${method} (id=${id}) ` +
1125
1295
  `within ${timeoutMs}ms — the server may be hung. The response ` +
1126
1296
  `outcome is unknown: the request was abandoned locally but was not ` +
1127
1297
  `cancelled, so the tool may still have completed server-side; verify ` +
1128
1298
  `state before retrying; a blind retry of a stateful/side-effecting ` +
1129
1299
  `tool may duplicate it.`,
1300
+ 'no-response',
1130
1301
  ));
1131
1302
  }, timeoutMs);
1132
1303
  // Don't hold the event loop open for the watchdog alone.
1133
1304
  pending.timer.unref?.();
1134
1305
  }
1135
1306
  this.pendingRequests.set(id, pending);
1136
- this.transport!.writeLine(JSON.stringify(request));
1307
+ try {
1308
+ this.transport!.writeLine(JSON.stringify(request));
1309
+ } catch (err) {
1310
+ // A synchronous write rejection sent no request. Remove its pending
1311
+ // state and watchdog before reporting that it is safe to retry.
1312
+ this.pendingRequests.delete(id);
1313
+ if (pending.timer) clearTimeout(pending.timer);
1314
+ reject(new McplRequestError(
1315
+ `Cannot send ${method} to MCPL server "${this.id}": ${err instanceof Error ? err.message : String(err)}`,
1316
+ 'not-sent',
1317
+ ));
1318
+ }
1137
1319
  });
1138
1320
  }
1139
1321
 
@@ -1223,7 +1405,9 @@ export class McplServerConnection extends EventEmitter {
1223
1405
  this.setupLifecycle(transport);
1224
1406
  // Surface transport diagnostics (stdio child stderr) as 'stderr' events,
1225
1407
  // preserving the `{ line }` payload existing consumers expect.
1226
- transport.on('stderr', (line: string) => this.emit('stderr', { line }));
1408
+ // Through the same containment boundary as every inbound event, so a
1409
+ // stderr listener that throws is reported, not thrown into the transport.
1410
+ transport.on('stderr', (line: string) => this.dispatchInboundEvent('stderr', { line }));
1227
1411
  }
1228
1412
 
1229
1413
  /**
@@ -1239,61 +1423,148 @@ export class McplServerConnection extends EventEmitter {
1239
1423
  return;
1240
1424
  }
1241
1425
 
1242
- // Is this a response to one of our outbound requests?
1243
- if ('id' in msg && msg.id != null && !('method' in msg)) {
1244
- this.handleResponse(msg as JsonRpcResponse);
1245
- return;
1426
+ // JSON-RPC messages must be objects. Ignore unrelated stdout/log values
1427
+ // before property access, just as malformed JSON lines are ignored.
1428
+ if (msg === null || typeof msg !== 'object' || Array.isArray(msg)) return;
1429
+ try {
1430
+ this.dispatchMessage(msg);
1431
+ } catch (error) {
1432
+ const request = msg as { method?: unknown; id?: unknown };
1433
+ this.reportInboundFailure(error, {
1434
+ ...(typeof request.method === 'string' ? { event: request.method } : {}),
1435
+ ...(typeof request.id === 'string' || typeof request.id === 'number' ? { requestId: request.id } : {}),
1436
+ });
1246
1437
  }
1438
+ });
1439
+ }
1247
1440
 
1248
- // It is an inbound request or notification from the server
1249
- const request = msg as JsonRpcRequest;
1250
- const eventName = McplServerConnection.METHOD_TO_EVENT[request.method];
1251
-
1252
- // §7 is removed in 0.5.0: scope/elevate is no longer a method. Answer
1253
- // rather than hang (§6.6 — a method that will never be answered MUST
1254
- // return an error).
1255
- // featureSets/changed is REMOVED in 0.5.0 (§6.7 — it carried a
1256
- // server-authored change payload, the self-attestation defect; the
1257
- // need is met by §17's host-diffed manifest fetch). It was still
1258
- // routed, control-plane classified, and mutating declarations — a
1259
- // live ungated self-attestation path (PR #79 review blocker 4).
1260
- if (request.method === McplMethod.FeatureSetsChanged) {
1261
- if (request.id != null) {
1262
- this.sendErrorResponse(request.id, -32601, 'featureSets/changed removed in MCPL 0.5.0 (superseded by mcpl/manifestChanged, SPEC §17)');
1263
- } else {
1264
- console.error(`[mcpl] ${this.id}: discarded featureSets/changed — removed in 0.5.0 (§6.7/§17)`);
1265
- }
1266
- return;
1441
+ /** Contain synchronous dispatch failures; async RPC handlers own their promises. */
1442
+ private dispatchMessage(msg: JsonRpcRequest | JsonRpcResponse): void {
1443
+ // Is this a response to one of our outbound requests?
1444
+ if ('id' in msg && msg.id != null && !('method' in msg)) {
1445
+ this.handleResponse(msg as JsonRpcResponse);
1446
+ return;
1447
+ }
1448
+
1449
+ // It is an inbound request or notification from the server
1450
+ const request = msg as JsonRpcRequest;
1451
+
1452
+ // MCP's ping, which either side may send: its receiver answers promptly
1453
+ // with an empty result. It's answered as it arrives, before admission and
1454
+ // buffering, since it asks only whether the connection is alive, and a
1455
+ // paused plane mustn't hold that answer. A ping sent as a notification
1456
+ // has nothing to answer. The handshake answers one too.
1457
+ if (request.method === 'ping') {
1458
+ if (request.id != null) this.sendResponse(request.id, {});
1459
+ return;
1460
+ }
1461
+
1462
+ const eventName = typeof request.method === 'string' && Object.hasOwn(McplServerConnection.METHOD_TO_EVENT, request.method)
1463
+ ? McplServerConnection.METHOD_TO_EVENT[request.method] : undefined;
1464
+
1465
+ // §7 is removed in 0.5.0: scope/elevate is no longer a method. Answer
1466
+ // rather than hang (§6.6 — a method that will never be answered MUST
1467
+ // return an error).
1468
+ // featureSets/changed is REMOVED in 0.5.0 (§6.7 — it carried a
1469
+ // server-authored change payload, the self-attestation defect; the
1470
+ // need is met by §17's host-diffed manifest fetch). It was still
1471
+ // routed, control-plane classified, and mutating declarations — a
1472
+ // live ungated self-attestation path (PR #79 review blocker 4).
1473
+ if (request.method === McplMethod.FeatureSetsChanged) {
1474
+ if (request.id != null) {
1475
+ this.sendErrorResponse(request.id, -32601, 'featureSets/changed removed in MCPL 0.5.0 (superseded by mcpl/manifestChanged, SPEC §17)');
1476
+ } else {
1477
+ console.error(`[mcpl] ${this.id}: discarded featureSets/changed — removed in 0.5.0 (§6.7/§17)`);
1267
1478
  }
1479
+ return;
1480
+ }
1268
1481
 
1269
- if (request.method === McplMethod.ScopeElevate) {
1270
- if (request.id != null) {
1271
- this.sendErrorResponse(request.id, -32601, 'scope/elevate removed in MCPL 0.5.0 (SPEC §7)');
1272
- }
1273
- return;
1482
+ if (request.method === McplMethod.ScopeElevate) {
1483
+ if (request.id != null) {
1484
+ this.sendErrorResponse(request.id, -32601, 'scope/elevate removed in MCPL 0.5.0 (SPEC §7)');
1274
1485
  }
1486
+ return;
1487
+ }
1275
1488
 
1276
- // Positive-grant enforcement (§5.4, §14.1) happens at ADMISSION, in
1277
- // the emit() override below — the one choke-point that live routing
1278
- // and staged-buffer flushes share. See the comment there for why
1279
- // rejecting here, at line receipt, was wrong for staged connections.
1280
-
1281
- if (eventName) {
1282
- // Emit the typed event with params and (for requests) a respond callback
1283
- if (request.id != null) {
1284
- // Server expects a response — provide a respond helper
1285
- this.emit(eventName, request.params, {
1286
- id: request.id,
1287
- respond: (result: unknown) => this.sendResponse(request.id!, result),
1288
- respondError: (code: number, message: string, data?: unknown) =>
1289
- this.sendErrorResponse(request.id!, code, message, data),
1290
- });
1291
- } else {
1292
- // Notification — no response expected
1293
- this.emit(eventName, request.params);
1294
- }
1489
+ // Positive-grant enforcement (§5.4, §14.1) happens at ADMISSION, in
1490
+ // the emit() override below — the one choke-point that live routing
1491
+ // and staged-buffer flushes share. See the comment there for why
1492
+ // rejecting here, at line receipt, was wrong for staged connections.
1493
+
1494
+ if (!eventName) {
1495
+ // §6.6: a request that will never be answered MUST get an error, so a
1496
+ // request (it has an id) whose method isn't a string, or isn't one this
1497
+ // host handles, is answered -32601. A notification nobody handles is
1498
+ // ignored, as JSON-RPC asks.
1499
+ if (request.id != null) {
1500
+ this.sendErrorResponse(request.id, -32601, 'Method not found');
1501
+ console.error(`[mcpl] ${this.id}: answered -32601 to a request for ${describeMethod(request.method)}, which this host doesn't handle`);
1295
1502
  }
1296
- });
1503
+ return;
1504
+ }
1505
+
1506
+ // Emit the typed event with params and (for requests) a respond callback
1507
+ if (request.id != null) {
1508
+ // Server expects a response — provide a respond helper
1509
+ this.dispatchInboundEvent(eventName, request.params, {
1510
+ id: request.id,
1511
+ respond: (result: unknown) => this.sendResponse(request.id!, result),
1512
+ respondError: (code: number, message: string, data?: unknown) =>
1513
+ this.sendErrorResponse(request.id!, code, message, data),
1514
+ });
1515
+ } else {
1516
+ // Notification — no response expected
1517
+ this.dispatchInboundEvent(eventName, request.params);
1518
+ }
1519
+ }
1520
+
1521
+ /** Live delivery and delayed plane flushes share the same containment boundary. */
1522
+ private dispatchInboundEvent(event: string, ...args: unknown[]): void {
1523
+ try {
1524
+ this.emit(event, ...args);
1525
+ } catch (error) {
1526
+ const requestId = (args[1] as { id?: unknown } | undefined)?.id;
1527
+ this.reportInboundFailure(error, {
1528
+ event,
1529
+ ...(typeof requestId === 'string' || typeof requestId === 'number' ? { requestId } : {}),
1530
+ });
1531
+ }
1532
+ }
1533
+
1534
+ /** Report a failure the containment boundary caught, naming the event (or
1535
+ * method) and request it was dispatching, and what failed. The message is
1536
+ * what the framework's 'error' listener traces. */
1537
+ private reportInboundFailure(cause: unknown, context: { event?: string; requestId?: string | number } = {}): void {
1538
+ const where = (show: (text: string) => string): string => (context.event === undefined ? '' : ` for ${show(context.event)}`) +
1539
+ (context.requestId === undefined ? '' : ` (request ${show(String(context.requestId))})`);
1540
+ // The error's message is what the 'error' listener traces, as text a
1541
+ // reader parses, so it is bounded rather than escaped (boundedForLog);
1542
+ // the log line prints the same through log-value.
1543
+ const error = new Error(`MCPL server "${this.id}" inbound dispatch failed${where(boundedForLog)}: ${boundedForLog(describeCause(cause))}`, { cause });
1544
+ console.error(`[mcpl] ${this.id}: inbound dispatch failed${where(logValue)}: ${logDetail(describeCause(cause))}`);
1545
+ this.emitToErrorListeners(error);
1546
+ }
1547
+
1548
+ /**
1549
+ * Give an error to the connection's 'error' listeners, and say whether it
1550
+ * has any. EventEmitter throws an 'error' that nothing listens for, and
1551
+ * from a transport's callback, where these errors arise, nothing catches
1552
+ * that throw, so it ends the process. A bare connection has no listener:
1553
+ * the class is exported, and a probe, a playtest or a harness often attaches
1554
+ * none. So with no listener, the error is the caller's to log, unless it
1555
+ * already has. A listener that throws is caught and logged, with the error
1556
+ * it was handling.
1557
+ */
1558
+ private emitToErrorListeners(error: Error): boolean {
1559
+ if (this.listenerCount('error') === 0) return false;
1560
+ try { this.emit('error', error); }
1561
+ catch (listenerError) {
1562
+ console.error(
1563
+ `[mcpl] ${this.id}: an 'error' listener failed: ${logDetail(describeCause(listenerError))}` +
1564
+ `, handling ${logDetail(error.message)}`,
1565
+ );
1566
+ }
1567
+ return true;
1297
1568
  }
1298
1569
 
1299
1570
  /**
@@ -1310,10 +1581,17 @@ export class McplServerConnection extends EventEmitter {
1310
1581
  // re-inject either result because the original dispatch context is gone.
1311
1582
  const orphaned = this.orphanedRequests.get(response.id);
1312
1583
  this.orphanedRequests.delete(response.id);
1313
- if (orphaned?.renderParams) {
1314
- this.emit('orphaned-render-response', { params: orphaned.renderParams, result: response.result, error: response.error });
1315
- return; // audit only: a timeout fallback can never be replaced
1316
- }
1584
+ // A push/render answered after its timeout (RFC-006 §5.3) is reported
1585
+ // with the render's featureSet, key, eventId and, for a channel-scoped
1586
+ // subject, channelId, kept from its request when the timeout fired, so
1587
+ // its discarded answer can be recorded beside its batch's other
1588
+ // coalescing records (§11). It is only reported: the fallback the
1589
+ // timeout materialized stands (§5.4 rule 3). A late JSON-RPC error is
1590
+ // passed on as `error`, so its record can be told from a late result's,
1591
+ // and so is one beside a result, which JSON-RPC forbids: the live path
1592
+ // rejects such an answer as an error.
1593
+ const render = orphaned?.renderParams ?? {};
1594
+ const failure = response.error ? { error: { code: response.error.code, message: response.error.message } } : {};
1317
1595
  const result = response.result;
1318
1596
  if (result && typeof result === 'object') {
1319
1597
  const r = result as { state?: unknown; checkpoint?: unknown };
@@ -1323,6 +1601,8 @@ export class McplServerConnection extends EventEmitter {
1323
1601
  method: orphaned?.method,
1324
1602
  hadState: r.state !== undefined,
1325
1603
  hadCheckpoint: r.checkpoint !== undefined,
1604
+ ...render,
1605
+ ...failure,
1326
1606
  });
1327
1607
  }
1328
1608
  } else if (orphaned) {
@@ -1331,6 +1611,8 @@ export class McplServerConnection extends EventEmitter {
1331
1611
  method: orphaned.method,
1332
1612
  hadState: false,
1333
1613
  hadCheckpoint: false,
1614
+ ...render,
1615
+ ...failure,
1334
1616
  });
1335
1617
  }
1336
1618
  return; // Orphaned response — ignore
@@ -1340,8 +1622,19 @@ export class McplServerConnection extends EventEmitter {
1340
1622
  if (pending.timer) clearTimeout(pending.timer);
1341
1623
 
1342
1624
  if (response.error) {
1625
+ // describeCause rather than the template's own conversion, as for an
1626
+ // initialize error: the server's code and message can be any JSON
1627
+ // value, and one with no primitive form, such as {"toString":1}, would
1628
+ // throw here, after the request has left pendingRequests and its timer
1629
+ // is cleared, so it would never settle. Both are the server's text, a
1630
+ // code as much as a message, since a server can send a string, so both
1631
+ // are bounded as errors.ts says.
1343
1632
  pending.reject(
1344
- new Error(`MCPL server "${this.id}" returned error for ${pending.method}: [${response.error.code}] ${response.error.message}`),
1633
+ new McplRequestError(
1634
+ `MCPL server "${this.id}" returned error for ${pending.method}: [${boundedForLog(describeCause(response.error.code))}] ${boundedForLog(describeCause(response.error.message))}`,
1635
+ 'error-response',
1636
+ (response.error as { data?: unknown }).data,
1637
+ ),
1345
1638
  );
1346
1639
  } else {
1347
1640
  pending.resolve(response.result);
@@ -1382,7 +1675,8 @@ export class McplServerConnection extends EventEmitter {
1382
1675
  private setupLifecycle(transport: McplTransport): void {
1383
1676
  this.hostCloseRequested = false;
1384
1677
  transport.on('error', (err: Error) => {
1385
- this.emit('error', new Error(`MCPL server "${this.id}" transport error: ${err.message}`));
1678
+ const error = new Error(`MCPL server "${this.id}" transport error: ${err.message}`);
1679
+ if (!this.emitToErrorListeners(error)) console.error(`[mcpl] ${this.id}: transport error: ${logDetail(err.message)}`);
1386
1680
  });
1387
1681
 
1388
1682
  transport.on('close', (info: TransportCloseInfo) => {
@@ -1394,8 +1688,9 @@ export class McplServerConnection extends EventEmitter {
1394
1688
  for (const [id, pending] of this.pendingRequests) {
1395
1689
  if (pending.timer) clearTimeout(pending.timer);
1396
1690
  pending.reject(
1397
- new Error(
1398
- `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})`,
1691
+ new McplRequestError(
1692
+ `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})`,
1693
+ 'no-response',
1399
1694
  ),
1400
1695
  );
1401
1696
  }