@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
@@ -42,14 +42,16 @@ export class McplServerRegistry {
42
42
  throw new Error(`MCPL server "${config.id}" is already registered`);
43
43
  }
44
44
 
45
- const connection = config.reconnect
45
+ const connection = config.reconnect === true
46
46
  ? await McplServerConnection.connectWithReconnect(config, hostCapabilities)
47
47
  : await McplServerConnection.connect(config, hostCapabilities);
48
48
  this.servers.set(config.id, connection);
49
49
 
50
- // Auto-remove on unexpected close (unless reconnect will re-add)
50
+ // Auto-remove on close unless the connection will reconnect. That was
51
+ // decided once, from `reconnect === true` at connect, and a close() the
52
+ // host asks for disarms it first, so a server closed for good goes too.
51
53
  connection.on('close', () => {
52
- if (!config.reconnect) {
54
+ if (!connection.willReconnect) {
53
55
  this.servers.delete(config.id);
54
56
  }
55
57
  });
@@ -146,7 +148,16 @@ export class McplServerRegistry {
146
148
  })), timeoutMs);
147
149
  }
148
150
 
149
- private closeServer(id: string, connection: McplServerConnection): Promise<void> {
151
+ /**
152
+ * Close a server for good and drop its entry, if this connection is still
153
+ * the one registered under `id`. The entry goes when close() resolves,
154
+ * whatever the connection reports: close() emits no 'close' for a
155
+ * connection that's down between retries, such as a reconnect stub waiting
156
+ * for its next retry, so the 'close' listener alone would leave it
157
+ * registered. A close that fails keeps the entry and rejects; a close
158
+ * already under way is shared.
159
+ */
160
+ closeServer(id: string, connection: McplServerConnection): Promise<void> {
150
161
  const existing = this.closing.get(connection);
151
162
  if (existing) return existing;
152
163
  const attempt = Promise.resolve().then(() => connection.close()).then(() => {
@@ -0,0 +1,73 @@
1
+ /**
2
+ * How `skip_reply` reads its `wake_in_seconds`, for every site that acts on
3
+ * it: the framework arms the EventGate's timer or refuses the call, the turn's
4
+ * bookkeeping of a refused round asks whether it was refused, and the channel
5
+ * registry words the confirmation. One reading, so a value can't arm a timer
6
+ * at one site and read as no wake at another, and the confirmation names the
7
+ * seconds the timer is set for.
8
+ */
9
+ import { safeSlice } from '../safe-slice.js';
10
+
11
+ /** The range the tool's schema offers, in seconds: a larger number waits the most. */
12
+ export const SKIP_REPLY_WAKE_MIN_SECONDS = 1;
13
+ export const SKIP_REPLY_WAKE_MAX_SECONDS = 3600;
14
+
15
+ /**
16
+ * What a `skip_reply` call's `wake_in_seconds` asks for:
17
+ * - `none`: absent or `null`, an ordinary skip;
18
+ * - `wake`: a number of at least 1, or a string that `Number()` reads as one,
19
+ * in whole seconds and at most 3600, so 90.7 waits 90 s and anything over
20
+ * 3600, Infinity included, waits 3600 s;
21
+ * - `invalid`: anything else, which asks for no number of seconds the host can
22
+ * set: a number below 1, such as 0, a negative or 0.5, and "soon", "",
23
+ * `true`, an array or an object. Below 1 is refused rather than raised to 1:
24
+ * 0 is a value a model may write when it fills an optional number with a
25
+ * default, and as a 1 s wake it would wake the agent again a second after
26
+ * each turn, for as long as it kept skipping with 0.
27
+ */
28
+ export type SkipReplyWake =
29
+ | { kind: 'none' }
30
+ | { kind: 'wake'; seconds: number }
31
+ | { kind: 'invalid'; value: unknown };
32
+
33
+ export function readSkipReplyWake(input: unknown): SkipReplyWake {
34
+ const value = input !== null && typeof input === 'object'
35
+ ? (input as Record<string, unknown>).wake_in_seconds
36
+ : undefined;
37
+ if (value === undefined || value === null) return { kind: 'none' };
38
+ // A blank string reads as 0, so it's refused as a number below 1.
39
+ const seconds = typeof value === 'number' ? value
40
+ : typeof value === 'string' ? Number(value)
41
+ : Number.NaN;
42
+ if (Number.isNaN(seconds) || seconds < SKIP_REPLY_WAKE_MIN_SECONDS) return { kind: 'invalid', value };
43
+ return { kind: 'wake', seconds: Math.floor(Math.min(SKIP_REPLY_WAKE_MAX_SECONDS, seconds)) };
44
+ }
45
+
46
+ /** The refusal the model reads when its host has no EventGate to set a timer. */
47
+ export const SKIP_REPLY_WAKE_NO_GATE_REFUSAL =
48
+ "Your turn didn't end, and no wake was set: this host can't wake you on a timer, so skip_reply can't take wake_in_seconds here. To end the turn and wait for the next message, call skip_reply without it. Anything you meant to come back to, do now.";
49
+
50
+ /**
51
+ * Why a `skip_reply` call is refused, as the model will read it, or undefined
52
+ * when it isn't: without an EventGate, any `wake_in_seconds` but absent or
53
+ * `null`, since the host offers none; with one, a value that isn't a number of
54
+ * seconds. A refused call arms nothing and doesn't end the turn.
55
+ */
56
+ export function skipReplyWakeRefusal(wake: SkipReplyWake, gatePresent: boolean): string | undefined {
57
+ if (wake.kind === 'none') return undefined;
58
+ if (!gatePresent) return SKIP_REPLY_WAKE_NO_GATE_REFUSAL;
59
+ if (wake.kind === 'wake') return undefined;
60
+ return `Your turn didn't end, and no wake was set: wake_in_seconds takes a number of seconds from ${SKIP_REPLY_WAKE_MIN_SECONDS} to ${SKIP_REPLY_WAKE_MAX_SECONDS}, and ${describeValue(wake.value)} isn't one. Call skip_reply with a number of seconds to come back on your own, or without wake_in_seconds to end the turn and wait for the next message.`;
61
+ }
62
+
63
+ /**
64
+ * A value as the model wrote it, as JSON, cut to keep the refusal short,
65
+ * never between the halves of a surrogate pair. A tool call's input is parsed
66
+ * JSON, so it always has a JSON text, but JSON writes a number that isn't
67
+ * finite as `null`, and `-1e400` parses as -Infinity, so a number prints as
68
+ * `String()` of it.
69
+ */
70
+ function describeValue(value: unknown): string {
71
+ const text = typeof value === 'number' ? String(value) : JSON.stringify(value);
72
+ return text.length > 80 ? `${safeSlice(text, 0, 80)}…` : text;
73
+ }
@@ -23,6 +23,8 @@ import { StringDecoder } from 'node:string_decoder';
23
23
  import WebSocket from 'ws';
24
24
 
25
25
  import type { McplServerConfig } from './types.js';
26
+ import { assertBooleanSetting } from '../config-checks.js';
27
+ import { logDetail } from './log-value.js';
26
28
 
27
29
  /** Why/how a transport closed. `code`/`signal` are populated for stdio child
28
30
  * exits; `reason` carries a WebSocket close reason or an error message. */
@@ -55,7 +57,10 @@ export abstract class McplTransport extends EventEmitter {
55
57
  private lineBuffer: string[] = [];
56
58
  private stderrBuffer: string[] = [];
57
59
 
58
- protected constructor() {
60
+ /** The server's id from its config, so a line the transport logs names it.
61
+ * The stdio and WebSocket transports always give it; a test's stand-in
62
+ * transport may leave it out. */
63
+ protected constructor(protected readonly serverId?: string) {
59
64
  super();
60
65
  // Flush buffered inbound lines the moment a consumer subscribes.
61
66
  this.on('newListener', (event) => {
@@ -85,6 +90,15 @@ export abstract class McplTransport extends EventEmitter {
85
90
  return '';
86
91
  }
87
92
 
93
+ /**
94
+ * Resolves once the server's diagnostic stream has ended or closed, so that
95
+ * {@link stderrTail} holds what arrived on it, or once `ms` have passed while
96
+ * it hasn't. At once for a transport that has none.
97
+ */
98
+ stderrEnded(_ms: number): Promise<void> {
99
+ return Promise.resolve();
100
+ }
101
+
88
102
  /** Deliver an inbound line, buffering it if nobody is listening yet. */
89
103
  protected pushLine(line: string): void {
90
104
  if (this.listenerCount('line') > 0) this.emit('line', line);
@@ -97,6 +111,23 @@ export abstract class McplTransport extends EventEmitter {
97
111
  else this.stderrBuffer.push(line);
98
112
  }
99
113
 
114
+ /**
115
+ * Report a transport error: to the 'error' listeners if there are any, else
116
+ * as a log line. EventEmitter throws an 'error' that nothing listens for,
117
+ * and a transport reports its errors from I/O callbacks, where nothing
118
+ * catches that throw, so it would end the process. A transport has no
119
+ * listener from its creation until the handshake attaches one, and a
120
+ * WebSocket server that sends a malformed frame with its upgrade response
121
+ * makes ws raise an 'error' in that window.
122
+ */
123
+ protected reportError(err: Error): void {
124
+ if (this.listenerCount('error') > 0) this.emit('error', err);
125
+ else {
126
+ const server = this.serverId === undefined ? '' : `${this.serverId}: `;
127
+ console.error(`[mcpl] ${server}a ${this.kind} transport error, with nothing listening for it: ${logDetail(err.message)}`);
128
+ }
129
+ }
130
+
100
131
  /** Emit 'close' exactly once. */
101
132
  protected markClosed(info: TransportCloseInfo): void {
102
133
  if (this._closed) return;
@@ -141,15 +172,17 @@ export const CHILD_ENV_ALLOWLIST = [
141
172
 
142
173
  /** Environment for a stdio child: allowlisted host vars (+ LC_*), then the
143
174
  * server's declared `env` on top. Windows names merge case-insensitively;
144
- * POSIX names remain case-sensitive. `inheritEnv: true` restores full inheritance. */
175
+ * POSIX names remain case-sensitive. `inheritEnv: true` restores full inheritance,
176
+ * and only `true` does: a direct caller can pass any value, unchecked. */
145
177
  export function buildChildEnv(
146
178
  config: Pick<McplServerConfig, 'env' | 'inheritEnv'>,
147
179
  hostEnv: NodeJS.ProcessEnv = process.env,
148
180
  platform: NodeJS.Platform = process.platform,
149
181
  ): NodeJS.ProcessEnv {
150
182
  const win = platform === 'win32';
151
- const env: NodeJS.ProcessEnv = config.inheritEnv ? { ...hostEnv } : {};
152
- if (!config.inheritEnv) {
183
+ const inherit = config.inheritEnv === true;
184
+ const env: NodeJS.ProcessEnv = inherit ? { ...hostEnv } : {};
185
+ if (!inherit) {
153
186
  for (const [key, value] of Object.entries(hostEnv)) {
154
187
  if (value === undefined) continue;
155
188
  // Windows commonly enumerates Path/SystemRoot rather than PATH/SYSTEMROOT.
@@ -184,22 +217,58 @@ export function buildChildEnv(
184
217
  /** The most of a stdio child's stderr a transport keeps for {@link McplTransport.stderrTail}. */
185
218
  export const STDERR_TAIL_CHARS = 2_048;
186
219
 
220
+ /**
221
+ * How long a refusal at a stdio child's exit waits for the child's stderr to
222
+ * end, so that its `stderrTail` holds what the child wrote. Node can emit a
223
+ * child's `exit` before it has read the last of the child's stderr. When the
224
+ * child held the stream alone, the stream ends with it, and the wait is short.
225
+ * The bound binds when another process still holds the stream, such as one the
226
+ * server started that inherited it, or when the host's loop stalls past it
227
+ * before reading an end that is waiting. The tail then holds what had arrived.
228
+ * A process that keeps the stream open, such as one the server started and
229
+ * left running, holds the refusal up by the bound, a fifth of the reconnect's
230
+ * default first interval.
231
+ */
232
+ export const STDERR_END_WAIT_MS = 1_000;
233
+
187
234
  export class StdioTransport extends McplTransport {
188
235
  readonly kind = 'stdio' as const;
189
236
  /** The first error on the child's stdin or stdout, named in the close reason. */
190
237
  private pipeError: Error | undefined;
191
238
  private stderrEnd = '';
192
239
  private stderrCut = false;
240
+ /** True once the child's stderr has ended or closed. */
241
+ private stderrDone = false;
193
242
 
194
243
  override get stderrTail(): string {
195
244
  return (this.stderrCut ? '…' : '') + this.stderrEnd;
196
245
  }
197
246
 
247
+ override stderrEnded(ms: number): Promise<void> {
248
+ const stderr = this.child.stderr;
249
+ if (!stderr || this.stderrDone) return Promise.resolve();
250
+ return new Promise((resolve) => {
251
+ let timer: NodeJS.Timeout | undefined;
252
+ const done = () => {
253
+ clearTimeout(timer);
254
+ stderr.off('end', done);
255
+ stderr.off('close', done);
256
+ resolve();
257
+ };
258
+ // Added after the constructor's listeners, so the tail already holds the
259
+ // stream's last characters when these run.
260
+ stderr.once('end', done);
261
+ stderr.once('close', done);
262
+ timer = setTimeout(done, ms);
263
+ });
264
+ }
265
+
198
266
  private constructor(
199
267
  private readonly child: ChildProcess,
200
268
  private readonly rl: ReadlineInterface,
269
+ serverId: string,
201
270
  ) {
202
- super();
271
+ super(serverId);
203
272
 
204
273
  this.rl.on('line', (line: string) => this.pushLine(line));
205
274
 
@@ -224,9 +293,12 @@ export class StdioTransport extends McplTransport {
224
293
  this.child.stderr?.on('end', () => {
225
294
  received(decoder.end());
226
295
  if (carry.length > 0) this.pushStderr(carry);
296
+ this.stderrDone = true;
227
297
  });
298
+ // A stream destroyed by an error closes without ending: nothing more comes.
299
+ this.child.stderr?.on('close', () => { this.stderrDone = true; });
228
300
 
229
- this.child.on('error', (err) => this.emit('error', err));
301
+ this.child.on('error', (err) => this.reportError(err));
230
302
  // The child's stdin and stdout carry the protocol, so after an error on
231
303
  // either, a write's EPIPE or a read error, this transport can't reach the
232
304
  // child even if it's still running. The handler sends a running child
@@ -247,13 +319,11 @@ export class StdioTransport extends McplTransport {
247
319
  // listener absorbs that copy.
248
320
  this.child.stdout?.on('error', endOnPipeError);
249
321
  this.rl.on('error', () => { /* readline's copy of a stdout error, handled above */ });
250
- // stderr carries diagnostics only: a read error on it is reported if
251
- // anyone listens and never thrown. It ends nothing once the connection
252
- // is wired; during a handshake the listener is the handshake's, which
253
- // fails it.
254
- this.child.stderr?.on('error', (err) => {
255
- if (this.listenerCount('error') > 0) this.emit('error', err);
256
- });
322
+ // stderr carries diagnostics only: a read error on it is reported, to the
323
+ // listeners or else in the log, and never thrown. It ends nothing once
324
+ // the connection is wired; during a handshake the listener is the
325
+ // handshake's, which fails it.
326
+ this.child.stderr?.on('error', (err) => this.reportError(err));
257
327
  this.child.on('exit', (code, signal) => this.markClosed({
258
328
  code,
259
329
  signal,
@@ -293,7 +363,7 @@ export class StdioTransport extends McplTransport {
293
363
  });
294
364
  });
295
365
  const rl = createInterface({ input: child.stdout! });
296
- return new StdioTransport(child, rl);
366
+ return new StdioTransport(child, rl, config.id);
297
367
  }
298
368
 
299
369
  writeLine(json: string): void {
@@ -332,8 +402,8 @@ const WS_OPEN_TIMEOUT_MS = 15_000;
332
402
  export class WebSocketTransport extends McplTransport {
333
403
  readonly kind = 'websocket' as const;
334
404
 
335
- private constructor(private readonly ws: WebSocket) {
336
- super();
405
+ private constructor(private readonly ws: WebSocket, serverId: string) {
406
+ super(serverId);
337
407
 
338
408
  this.ws.on('message', (data: WebSocket.RawData, isBinary: boolean) => {
339
409
  // MCPL frames are UTF-8 JSON text. A frame MAY contain multiple
@@ -345,7 +415,7 @@ export class WebSocketTransport extends McplTransport {
345
415
  }
346
416
  });
347
417
 
348
- this.ws.on('error', (err: Error) => this.emit('error', err));
418
+ this.ws.on('error', (err: Error) => this.reportError(err));
349
419
  this.ws.on('close', (code: number, reason: Buffer) => {
350
420
  const text = reason?.toString('utf8');
351
421
  this.markClosed(text ? { code, reason: text, reasonFromPeer: true } : { code, reason: 'websocket closed' });
@@ -404,7 +474,7 @@ export class WebSocketTransport extends McplTransport {
404
474
  settled = true;
405
475
  clearTimeout(timer);
406
476
  ws.removeAllListeners('error'); // the instance re-attaches its own handlers
407
- resolve(new WebSocketTransport(ws));
477
+ resolve(new WebSocketTransport(ws, config.id));
408
478
  });
409
479
 
410
480
  ws.once('error', (err: Error) => {
@@ -481,6 +551,38 @@ export function isWebSocketTransport(config: McplServerConfig): boolean {
481
551
  return Boolean(config.url) && !config.command;
482
552
  }
483
553
 
554
+ /** The settings of McplServerConfig whose type is boolean. */
555
+ type BooleanSetting = {
556
+ [K in keyof McplServerConfig]-?: NonNullable<McplServerConfig[K]> extends boolean ? K : never;
557
+ }[keyof McplServerConfig];
558
+
559
+ /** What `true` does for each boolean setting, as its refusal says it. A
560
+ * boolean setting added to McplServerConfig doesn't compile until it has
561
+ * an entry here, so the check below covers it too. */
562
+ const SERVER_CONFIG_BOOLEANS: Record<BooleanSetting, string> = {
563
+ inheritEnv: 'true passes the server the host\'s whole environment, and false or leaving it out passes only the allowlisted and LC_* host variables',
564
+ reconnect: 'true retries in the background when the server can\'t be reached or its connection drops, and false or leaving it out doesn\'t',
565
+ allowHostCommands: 'true lets the server run the host\'s admin commands, such as undo, hide, unstick and quiesce, and false or leaving it out refuses them',
566
+ };
567
+
568
+ /**
569
+ * Refuse a server config whose `inheritEnv`, `reconnect` or `allowHostCommands`
570
+ * holds anything but true or false. A config read from JSON can carry a quoted
571
+ * "false" where the type says boolean, and every reader of these settings takes
572
+ * only `true` as on, so the quotes would hide what the value does. null counts
573
+ * as not set, so a generated config that writes an unset setting as null
574
+ * keeps working. `inheritEnv` is checked only for a stdio server, since a
575
+ * WebSocket server never reads it. The error names the server, the setting
576
+ * and the value's kind, not the value, which could be a secret pasted into
577
+ * the wrong field.
578
+ */
579
+ export function assertServerConfigBooleans(config: McplServerConfig): void {
580
+ for (const [setting, whatTrueDoes] of Object.entries(SERVER_CONFIG_BOOLEANS) as Array<[BooleanSetting, string]>) {
581
+ if (setting === 'inheritEnv' && isWebSocketTransport(config)) continue;
582
+ assertBooleanSetting(`MCPL server "${config.id}" ${setting}`, config[setting], whatTrueDoes);
583
+ }
584
+ }
585
+
484
586
  /**
485
587
  * Open the transport selected by `config` (WebSocket when `transport` is
486
588
  * 'websocket' or a bare `url` is given; stdio otherwise). The returned transport
package/src/mcpl/types.ts CHANGED
@@ -238,7 +238,10 @@ export interface McplServerConfig {
238
238
  /**
239
239
  * Escape hatch: pass the host's entire environment (including secrets) to
240
240
  * the stdio child, as older versions did. Only for servers that genuinely
241
- * need it. Default false.
241
+ * need it. Default false. Only `true` turns it on, and null counts as not
242
+ * set. For a stdio server, `create()`, `connectMcplServer` and
243
+ * `restartMcplServer` refuse any other value, such as a quoted "false". A
244
+ * WebSocket server never reads it.
242
245
  */
243
246
  inheritEnv?: boolean;
244
247
 
@@ -278,7 +281,9 @@ export interface McplServerConfig {
278
281
  * unstick). DEFAULT FALSE: no §6.2 capability path exists for it, and the
279
282
  * grant cannot confer it — only this config, decided by the operator, can
280
283
  * (PR #79 review blocker 9). The one legitimate fleet user is
281
- * discord-mcpl's slash-command relay.
284
+ * discord-mcpl's slash-command relay. Only `true` turns it on, and null
285
+ * counts as not set. `create()`, `connectMcplServer` and
286
+ * `restartMcplServer` refuse any other value, such as a quoted "true".
282
287
  */
283
288
  allowHostCommands?: boolean;
284
289
 
@@ -351,6 +356,9 @@ export interface McplServerConfig {
351
356
  * When true, connect() resolves immediately (with null capabilities) if the
352
357
  * server is unavailable, and retries in the background.
353
358
  * Adapted from Anarchid/agent-framework@mcpl-module-proto.
359
+ * Only `true` turns it on, and null counts as not set. `create()`,
360
+ * `connectMcplServer` and `restartMcplServer` refuse any other value, such
361
+ * as a quoted "false".
354
362
  */
355
363
  reconnect?: boolean;
356
364
 
@@ -378,7 +386,10 @@ export interface McplServerConfig {
378
386
  * stops reading its stdin without closing it: the host's writes are
379
387
  * buffered, no error is raised, and the connection stays up. This is the
380
388
  * timeout of every request that names none; the handshake's initialize has
381
- * its own. Set 0 to disable. Default: 60000 (60 seconds).
389
+ * its own. Set 0 to disable, except for channels/publish and the
390
+ * channels/open a delivery may send first, which keep the 60 s default: a
391
+ * publish's outcome is reported to the resident and recorded for its
392
+ * draft, so it must end. Default: 60000 (60 seconds).
382
393
  */
383
394
  requestTimeoutMs?: number;
384
395
 
@@ -31,6 +31,33 @@ export function isVisiblyEmptyContent(content: readonly unknown[] | null | undef
31
31
  return true;
32
32
  }
33
33
 
34
+ /**
35
+ * What the converter (convertBlock, on every lane) shows for a text
36
+ * block whose text isn't a string, which only a nonconformant sender writes,
37
+ * so the agent learns that a block was there. It is the host's word, not the
38
+ * sender's, so it never makes content visible (isVisiblyEmptyConversion).
39
+ */
40
+ export const NON_STRING_TEXT_PLACEHOLDER = "[Text not shown: the server's text block had no string text.]";
41
+
42
+ /** A wire text block whose text isn't a string, which the converter shows as
43
+ * NON_STRING_TEXT_PLACEHOLDER. */
44
+ function isNonStringTextBlock(block: unknown): boolean {
45
+ if (!block || typeof block !== 'object') return false;
46
+ const b = block as { type?: unknown; text?: unknown };
47
+ return b.type === 'text' && typeof b.text !== 'string';
48
+ }
49
+
50
+ /**
51
+ * isVisiblyEmptyContent for content as a converter showed it, `wire` being
52
+ * the content as it arrived, block for block: a block shown as
53
+ * NON_STRING_TEXT_PLACEHOLDER counts as the nothing it held. So content that
54
+ * is only such blocks (or blank text) is still empty, and anything else is
55
+ * judged as the converted blocks show it, placeholders included.
56
+ */
57
+ export function isVisiblyEmptyConversion(wire: readonly unknown[], converted: readonly unknown[]): boolean {
58
+ return isVisiblyEmptyContent(converted.filter((_, i) => !isNonStringTextBlock(wire[i])));
59
+ }
60
+
34
61
  /** The server id and feature set the marker must carry. */
35
62
  export const SILENT_HEARTBEAT_SERVER_ID = 'heartbeat';
36
63
  export const SILENT_HEARTBEAT_FEATURE_SET = 'heartbeat';
@@ -1,4 +1,4 @@
1
- import type { JsStore } from '@animalabs/chronicle';
1
+ import type { JsStateRegistration, JsStore } from '@animalabs/chronicle';
2
2
  import type { ContentBlock } from '@animalabs/membrane';
3
3
  import type {
4
4
  MessageId,
@@ -25,6 +25,7 @@ import type {
25
25
  } from './types/index.js';
26
26
  import type { Agent } from './agent.js';
27
27
  import { DEFAULT_SHUTDOWN_TIMEOUT_MS, validateShutdownTimeout, waitForShutdown } from './shutdown.js';
28
+ import { logValue } from './mcpl/log-value.js';
28
29
 
29
30
  /** How the registry queues a module's event: its push names the module. A
30
31
  * `ProcessQueue` serves too, ignoring the name. */
@@ -44,6 +45,25 @@ export function isStateExistsError(err: unknown): boolean {
44
45
  return err instanceof Error && err.message.includes('State already exists');
45
46
  }
46
47
 
48
+ /**
49
+ * Register a state, treating "already exists" as done: a store reopened after
50
+ * a restart already holds it. Every other failure is thrown here, where it
51
+ * happened, naming the state, with the store's own error as its cause. Each
52
+ * state the framework registers goes through this.
53
+ */
54
+ export function ensureStateRegistered(
55
+ store: Pick<JsStore, 'registerState'>,
56
+ registration: JsStateRegistration,
57
+ ): void {
58
+ try {
59
+ store.registerState(registration);
60
+ } catch (error) {
61
+ if (isStateExistsError(error)) return;
62
+ const reason = error instanceof Error ? error.message : String(error);
63
+ throw new Error(`Registering state '${registration.id}' failed: ${reason}`, { cause: error });
64
+ }
65
+ }
66
+
47
67
  /**
48
68
  * Hard ceiling for a single module's gatherContext budget, regardless of the
49
69
  * `contextTimeoutMs` it declares. gatherContext runs on the critical path of
@@ -81,6 +101,8 @@ export class ModuleRegistry {
81
101
 
82
102
  private modules: Map<string, Module> = new Map();
83
103
  private stopping = new Map<Module, Promise<void>>();
104
+ /** Module and namespace pairs already told that a system injection held a block that isn't text. */
105
+ private notShownWarned = new Set<string>();
84
106
  private moduleContexts: Map<string, ModuleContextImpl> = new Map();
85
107
  private speechHandlers: SpeechHandler[] = [];
86
108
  private store: JsStore;
@@ -146,14 +168,7 @@ export class ModuleRegistry {
146
168
 
147
169
  // Register module state in store
148
170
  const stateId = this.getStateId(module.name);
149
- try {
150
- this.store.registerState({
151
- id: stateId,
152
- strategy: 'snapshot',
153
- });
154
- } catch {
155
- // State already registered (from previous run)
156
- }
171
+ ensureStateRegistered(this.store, { id: stateId, strategy: 'snapshot' });
157
172
 
158
173
  // Check if this is a restart (state exists)
159
174
  const existingState = this.store.getStateJson(stateId);
@@ -318,12 +333,13 @@ export class ModuleRegistry {
318
333
  };
319
334
  }
320
335
 
321
- // Create a call with the un-prefixed name (preserving caller identity)
336
+ // Create a call with the un-prefixed name (preserving caller identity and turn)
322
337
  const moduleCall: ToolCall = {
323
338
  id: call.id,
324
339
  name: toolName,
325
340
  input: call.input,
326
341
  callerAgentName: call.callerAgentName,
342
+ ...(call.callerTurnId !== undefined ? { callerTurnId: call.callerTurnId } : {}),
327
343
  };
328
344
 
329
345
  try {
@@ -425,7 +441,10 @@ export class ModuleRegistry {
425
441
  );
426
442
  let timer: ReturnType<typeof setTimeout> | undefined;
427
443
  const promise = Promise.race([
428
- module.gatherContext(agentName).then(r => injections.push(...r)),
444
+ module.gatherContext(agentName).then(r => {
445
+ injections.push(...r);
446
+ this.noteBlocksNotShown(module.name, r);
447
+ }),
429
448
  new Promise<void>((_, rej) => {
430
449
  timer = setTimeout(
431
450
  () => rej(new Error(`gatherContext timed out after ${budgetMs}ms`)),
@@ -443,6 +462,28 @@ export class ModuleRegistry {
443
462
  return injections;
444
463
  }
445
464
 
465
+ /**
466
+ * The system prompt is text, so an agent given a `system` injection reads
467
+ * a line in place of each of its blocks that isn't text (the agent's
468
+ * buildSystemPrompt), though `ContextInjection`'s content may be any
469
+ * block. The module meant those blocks for the model, so its operator is
470
+ * told, once per module and namespace, as the module's injections are
471
+ * gathered, whichever agents are given them.
472
+ */
473
+ private noteBlocksNotShown(moduleName: string, injections: ContextInjection[]): void {
474
+ for (const injection of injections) {
475
+ if (injection.position !== 'system' || !injection.content.some((block) => block.type !== 'text')) continue;
476
+ const key = `${moduleName}\u0000${injection.namespace}`;
477
+ if (this.notShownWarned.has(key)) continue;
478
+ this.notShownWarned.add(key);
479
+ console.error(
480
+ `[${moduleName}] gatherContext: a system injection in namespace ${logValue(injection.namespace)} holds a block that ` +
481
+ "isn't text, which the system prompt can't carry, so an agent given the injection reads a line in place of each such block; " +
482
+ 'this line prints once per module and namespace while the host runs',
483
+ );
484
+ }
485
+ }
486
+
446
487
  /**
447
488
  * Tell modules an agent's tool batch completed (see
448
489
  * Module.onToolBatchComplete). Hooks run in parallel, each awaited up to
@@ -640,18 +681,12 @@ class ModuleContextImpl implements ModuleContext {
640
681
  name: string,
641
682
  opts?: { deltaSnapshotEvery?: number; fullSnapshotEvery?: number }
642
683
  ): void {
643
- const id = this.logStateId(name);
644
- try {
645
- this.store.registerState({
646
- id,
647
- strategy: 'append_log',
648
- deltaSnapshotEvery: opts?.deltaSnapshotEvery ?? 100,
649
- fullSnapshotEvery: opts?.fullSnapshotEvery ?? 20,
650
- });
651
- } catch (err) {
652
- if (!isStateExistsError(err)) throw err;
653
- // Already registered (previous run) — idempotent path.
654
- }
684
+ ensureStateRegistered(this.store, {
685
+ id: this.logStateId(name),
686
+ strategy: 'append_log',
687
+ deltaSnapshotEvery: opts?.deltaSnapshotEvery ?? 100,
688
+ fullSnapshotEvery: opts?.fullSnapshotEvery ?? 20,
689
+ });
655
690
  this.registeredLogStates.add(name);
656
691
  }
657
692
 
@@ -40,7 +40,7 @@ export class ApiModule implements Module {
40
40
 
41
41
  async handleToolCall(_call: ToolCall): Promise<ToolResult> {
42
42
  // API module has no tools
43
- return { success: false, error: 'Unknown tool' };
43
+ return { success: false, error: 'Unknown tool', isError: true };
44
44
  }
45
45
 
46
46
  async onProcess(event: ProcessEvent, _state: ProcessState): Promise<EventResponse> {
@@ -29,6 +29,17 @@ export interface DiscordJsClientConfig {
29
29
  channelIds?: string[];
30
30
  }
31
31
 
32
+ /** An attachment as both a live message and history carry it. */
33
+ function toAttachment(a: Attachment): DiscordAttachment {
34
+ return {
35
+ id: a.id,
36
+ filename: a.name ?? 'unknown',
37
+ url: a.url,
38
+ contentType: a.contentType ?? undefined,
39
+ size: a.size,
40
+ };
41
+ }
42
+
32
43
  export class DiscordJsClient implements DiscordClientInterface {
33
44
  private client: Client;
34
45
  private token: string;
@@ -68,7 +79,11 @@ export class DiscordJsClient implements DiscordClientInterface {
68
79
  });
69
80
 
70
81
  this.client.on('messageUpdate', (_oldMessage, newMessage) => {
71
- if (!newMessage.content || !this.editHandler) return;
82
+ // content is null for a partial message, one discord.js hadn't cached
83
+ // and whose update carried no text, so there's no text to compare; a
84
+ // cached message keeps the text it had. An edit that leaves no text,
85
+ // beside an attachment, is '' and is still an edit.
86
+ if (typeof newMessage.content !== 'string' || !this.editHandler) return;
72
87
  this.editHandler(newMessage.id, newMessage.content);
73
88
  });
74
89
 
@@ -114,13 +129,7 @@ export class DiscordJsClient implements DiscordClientInterface {
114
129
  }
115
130
 
116
131
  private convertMessage(message: Message): DiscordMessageData {
117
- const attachments: DiscordAttachment[] = message.attachments.map((a: Attachment) => ({
118
- id: a.id,
119
- filename: a.name ?? 'unknown',
120
- url: a.url,
121
- contentType: a.contentType ?? undefined,
122
- size: a.size,
123
- }));
132
+ const attachments = message.attachments.map(toAttachment);
124
133
 
125
134
  // Extract mentioned user IDs
126
135
  const mentionedUserIds = message.mentions.users.map((u: User) => u.id);
@@ -160,7 +169,7 @@ export class DiscordJsClient implements DiscordClientInterface {
160
169
  channelId: string,
161
170
  content: string,
162
171
  options?: { replyTo?: string; createThread?: { name: string } }
163
- ): Promise<{ messageId: string }> {
172
+ ): Promise<{ messageId: string; threadFailure?: string }> {
164
173
  const channel = await this.client.channels.fetch(channelId);
165
174
  if (!channel || !('send' in channel)) {
166
175
  throw new Error(`Channel ${channelId} not found or not a text channel`);
@@ -173,7 +182,13 @@ export class DiscordJsClient implements DiscordClientInterface {
173
182
  });
174
183
 
175
184
  if (options?.createThread && 'threads' in textChannel) {
176
- await message.startThread({ name: options.createThread.name });
185
+ try {
186
+ await message.startThread({ name: options.createThread.name });
187
+ } catch (error) {
188
+ // The message is out, so the caller counts it as sent before it
189
+ // reports why its thread wasn't started.
190
+ return { messageId: message.id, threadFailure: error instanceof Error ? error.message : String(error) };
191
+ }
177
192
  }
178
193
 
179
194
  return { messageId: message.id };
@@ -341,6 +356,7 @@ export class DiscordJsClient implements DiscordClientInterface {
341
356
  authorName: m.author.username,
342
357
  isBot: m.author.bot,
343
358
  content: m.content,
359
+ attachments: m.attachments.map(toAttachment),
344
360
  timestamp: m.createdAt,
345
361
  replyTo: m.reference
346
362
  ? {