@0xmaxma/claude-gateway 1.8.14 → 2.0.1

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 (586) hide show
  1. package/README.md +28 -1613
  2. package/config.template.json +7 -1
  3. package/dist/agent/runner.d.ts +419 -0
  4. package/dist/agent/runner.d.ts.map +1 -1
  5. package/dist/agent/runner.js +736 -24
  6. package/dist/agent/runner.js.map +1 -1
  7. package/dist/agent/skill-learning/index.d.ts +6 -4
  8. package/dist/agent/skill-learning/index.d.ts.map +1 -1
  9. package/dist/agent/skill-learning/index.js +3 -3
  10. package/dist/agent/skill-learning/index.js.map +1 -1
  11. package/dist/agent/skill-learning/notifier.d.ts +3 -4
  12. package/dist/agent/skill-learning/notifier.d.ts.map +1 -1
  13. package/dist/agent/skill-learning/notifier.js +15 -13
  14. package/dist/agent/skill-learning/notifier.js.map +1 -1
  15. package/dist/agent/skill-learning/reviewer.d.ts.map +1 -1
  16. package/dist/agent/skill-learning/reviewer.js +3 -1
  17. package/dist/agent/skill-learning/reviewer.js.map +1 -1
  18. package/dist/api/connectors-router.d.ts.map +1 -1
  19. package/dist/api/connectors-router.js +110 -4
  20. package/dist/api/connectors-router.js.map +1 -1
  21. package/dist/api/gateway-router.d.ts +1 -0
  22. package/dist/api/gateway-router.d.ts.map +1 -1
  23. package/dist/api/gateway-router.js +13 -1
  24. package/dist/api/gateway-router.js.map +1 -1
  25. package/dist/api/line-webhook-router.d.ts +2 -2
  26. package/dist/api/line-webhook-router.d.ts.map +1 -1
  27. package/dist/api/line-webhook-router.js +264 -230
  28. package/dist/api/line-webhook-router.js.map +1 -1
  29. package/dist/api/router.d.ts.map +1 -1
  30. package/dist/api/router.js +162 -10
  31. package/dist/api/router.js.map +1 -1
  32. package/dist/api/share-router.d.ts.map +1 -1
  33. package/dist/api/share-router.js +29 -10
  34. package/dist/api/share-router.js.map +1 -1
  35. package/dist/api/slack-client.d.ts +2 -0
  36. package/dist/api/slack-client.d.ts.map +1 -1
  37. package/dist/api/slack-client.js +6 -2
  38. package/dist/api/slack-client.js.map +1 -1
  39. package/dist/api/slack-webhook-router.d.ts +3 -0
  40. package/dist/api/slack-webhook-router.d.ts.map +1 -1
  41. package/dist/api/slack-webhook-router.js +226 -131
  42. package/dist/api/slack-webhook-router.js.map +1 -1
  43. package/dist/api/voice-router.d.ts +21 -0
  44. package/dist/api/voice-router.d.ts.map +1 -0
  45. package/dist/api/voice-router.js +372 -0
  46. package/dist/api/voice-router.js.map +1 -0
  47. package/dist/api/voice-settings-router.d.ts +5 -0
  48. package/dist/api/voice-settings-router.d.ts.map +1 -0
  49. package/dist/api/voice-settings-router.js +318 -0
  50. package/dist/api/voice-settings-router.js.map +1 -0
  51. package/dist/apps/agent-container-migration.d.ts +11 -0
  52. package/dist/apps/agent-container-migration.d.ts.map +1 -0
  53. package/dist/apps/agent-container-migration.js +85 -0
  54. package/dist/apps/agent-container-migration.js.map +1 -0
  55. package/dist/apps/installer.d.ts +1 -1
  56. package/dist/apps/installer.d.ts.map +1 -1
  57. package/dist/apps/installer.js +2 -1
  58. package/dist/apps/installer.js.map +1 -1
  59. package/dist/cli/commands/tasks.d.ts +5 -0
  60. package/dist/cli/commands/tasks.d.ts.map +1 -0
  61. package/dist/cli/commands/tasks.js +92 -0
  62. package/dist/cli/commands/tasks.js.map +1 -0
  63. package/dist/cli/http-client.d.ts +2 -0
  64. package/dist/cli/http-client.d.ts.map +1 -1
  65. package/dist/cli/http-client.js +8 -3
  66. package/dist/cli/http-client.js.map +1 -1
  67. package/dist/cli/index.d.ts.map +1 -1
  68. package/dist/cli/index.js +5 -1
  69. package/dist/cli/index.js.map +1 -1
  70. package/dist/config/config-write-lock.d.ts +2 -0
  71. package/dist/config/config-write-lock.d.ts.map +1 -1
  72. package/dist/config/config-write-lock.js +5 -0
  73. package/dist/config/config-write-lock.js.map +1 -1
  74. package/dist/config/loader.d.ts.map +1 -1
  75. package/dist/config/loader.js +87 -2
  76. package/dist/config/loader.js.map +1 -1
  77. package/dist/config/migrator.d.ts.map +1 -1
  78. package/dist/config/migrator.js +12 -1
  79. package/dist/config/migrator.js.map +1 -1
  80. package/dist/config/watcher.d.ts.map +1 -1
  81. package/dist/config/watcher.js +6 -0
  82. package/dist/config/watcher.js.map +1 -1
  83. package/dist/connectors/resolve.d.ts.map +1 -1
  84. package/dist/connectors/resolve.js +3 -1
  85. package/dist/connectors/resolve.js.map +1 -1
  86. package/dist/connectors/types.d.ts +8 -0
  87. package/dist/connectors/types.d.ts.map +1 -1
  88. package/dist/cron/manager.d.ts.map +1 -1
  89. package/dist/cron/manager.js +21 -2
  90. package/dist/cron/manager.js.map +1 -1
  91. package/dist/discord/receiver.d.ts +2 -1
  92. package/dist/discord/receiver.d.ts.map +1 -1
  93. package/dist/discord/receiver.js +5 -1
  94. package/dist/discord/receiver.js.map +1 -1
  95. package/dist/history/db.d.ts +3 -0
  96. package/dist/history/db.d.ts.map +1 -1
  97. package/dist/history/db.js +21 -1
  98. package/dist/history/db.js.map +1 -1
  99. package/dist/history/types.d.ts +2 -0
  100. package/dist/history/types.d.ts.map +1 -1
  101. package/dist/index.js +48 -9
  102. package/dist/index.js.map +1 -1
  103. package/dist/orchestration/bounded-queue.d.ts +15 -0
  104. package/dist/orchestration/bounded-queue.d.ts.map +1 -0
  105. package/dist/orchestration/bounded-queue.js +58 -0
  106. package/dist/orchestration/bounded-queue.js.map +1 -0
  107. package/dist/orchestration/bridge.d.ts +55 -0
  108. package/dist/orchestration/bridge.d.ts.map +1 -0
  109. package/dist/orchestration/bridge.js +234 -0
  110. package/dist/orchestration/bridge.js.map +1 -0
  111. package/dist/orchestration/browser-routing.d.ts +7 -0
  112. package/dist/orchestration/browser-routing.d.ts.map +1 -0
  113. package/dist/orchestration/browser-routing.js +22 -0
  114. package/dist/orchestration/browser-routing.js.map +1 -0
  115. package/dist/orchestration/capabilities.d.ts +49 -0
  116. package/dist/orchestration/capabilities.d.ts.map +1 -0
  117. package/dist/orchestration/capabilities.js +417 -0
  118. package/dist/orchestration/capabilities.js.map +1 -0
  119. package/dist/orchestration/capacity.d.ts +14 -0
  120. package/dist/orchestration/capacity.d.ts.map +1 -0
  121. package/dist/orchestration/capacity.js +52 -0
  122. package/dist/orchestration/capacity.js.map +1 -0
  123. package/dist/orchestration/channel-activity.d.ts +21 -0
  124. package/dist/orchestration/channel-activity.d.ts.map +1 -0
  125. package/dist/orchestration/channel-activity.js +72 -0
  126. package/dist/orchestration/channel-activity.js.map +1 -0
  127. package/dist/orchestration/channel-controls.d.ts +32 -0
  128. package/dist/orchestration/channel-controls.d.ts.map +1 -0
  129. package/dist/orchestration/channel-controls.js +105 -0
  130. package/dist/orchestration/channel-controls.js.map +1 -0
  131. package/dist/orchestration/channel-input-media.d.ts +11 -0
  132. package/dist/orchestration/channel-input-media.d.ts.map +1 -0
  133. package/dist/orchestration/channel-input-media.js +54 -0
  134. package/dist/orchestration/channel-input-media.js.map +1 -0
  135. package/dist/orchestration/channel-media.d.ts +4 -0
  136. package/dist/orchestration/channel-media.d.ts.map +1 -0
  137. package/dist/orchestration/channel-media.js +70 -0
  138. package/dist/orchestration/channel-media.js.map +1 -0
  139. package/dist/orchestration/channel-speech.d.ts +7 -0
  140. package/dist/orchestration/channel-speech.d.ts.map +1 -0
  141. package/dist/orchestration/channel-speech.js +65 -0
  142. package/dist/orchestration/channel-speech.js.map +1 -0
  143. package/dist/orchestration/cli-skills.d.ts +12 -0
  144. package/dist/orchestration/cli-skills.d.ts.map +1 -0
  145. package/dist/orchestration/cli-skills.js +132 -0
  146. package/dist/orchestration/cli-skills.js.map +1 -0
  147. package/dist/orchestration/config.d.ts +260 -0
  148. package/dist/orchestration/config.d.ts.map +1 -0
  149. package/dist/orchestration/config.js +110 -0
  150. package/dist/orchestration/config.js.map +1 -0
  151. package/dist/orchestration/container.d.ts +21 -0
  152. package/dist/orchestration/container.d.ts.map +1 -0
  153. package/dist/orchestration/container.js +195 -0
  154. package/dist/orchestration/container.js.map +1 -0
  155. package/dist/orchestration/control-delivery.d.ts +5 -0
  156. package/dist/orchestration/control-delivery.d.ts.map +1 -0
  157. package/dist/orchestration/control-delivery.js +50 -0
  158. package/dist/orchestration/control-delivery.js.map +1 -0
  159. package/dist/orchestration/conversation-intake.d.ts +32 -0
  160. package/dist/orchestration/conversation-intake.d.ts.map +1 -0
  161. package/dist/orchestration/conversation-intake.js +92 -0
  162. package/dist/orchestration/conversation-intake.js.map +1 -0
  163. package/dist/orchestration/decisions.d.ts +27 -0
  164. package/dist/orchestration/decisions.d.ts.map +1 -0
  165. package/dist/orchestration/decisions.js +151 -0
  166. package/dist/orchestration/decisions.js.map +1 -0
  167. package/dist/orchestration/delivery.d.ts +34 -0
  168. package/dist/orchestration/delivery.d.ts.map +1 -0
  169. package/dist/orchestration/delivery.js +235 -0
  170. package/dist/orchestration/delivery.js.map +1 -0
  171. package/dist/orchestration/display-stream.d.ts +4 -0
  172. package/dist/orchestration/display-stream.d.ts.map +1 -0
  173. package/dist/orchestration/display-stream.js +77 -0
  174. package/dist/orchestration/display-stream.js.map +1 -0
  175. package/dist/orchestration/events.d.ts +30 -0
  176. package/dist/orchestration/events.d.ts.map +1 -0
  177. package/dist/orchestration/events.js +65 -0
  178. package/dist/orchestration/events.js.map +1 -0
  179. package/dist/orchestration/execution-observation.d.ts +38 -0
  180. package/dist/orchestration/execution-observation.d.ts.map +1 -0
  181. package/dist/orchestration/execution-observation.js +25 -0
  182. package/dist/orchestration/execution-observation.js.map +1 -0
  183. package/dist/orchestration/file-delivery.d.ts +16 -0
  184. package/dist/orchestration/file-delivery.d.ts.map +1 -0
  185. package/dist/orchestration/file-delivery.js +139 -0
  186. package/dist/orchestration/file-delivery.js.map +1 -0
  187. package/dist/orchestration/gateway-config.d.ts +17 -0
  188. package/dist/orchestration/gateway-config.d.ts.map +1 -0
  189. package/dist/orchestration/gateway-config.js +128 -0
  190. package/dist/orchestration/gateway-config.js.map +1 -0
  191. package/dist/orchestration/history.d.ts +13 -0
  192. package/dist/orchestration/history.d.ts.map +1 -0
  193. package/dist/orchestration/history.js +48 -0
  194. package/dist/orchestration/history.js.map +1 -0
  195. package/dist/orchestration/identity.d.ts +6 -0
  196. package/dist/orchestration/identity.d.ts.map +1 -0
  197. package/dist/orchestration/identity.js +13 -0
  198. package/dist/orchestration/identity.js.map +1 -0
  199. package/dist/orchestration/inference-errors.d.ts +3 -0
  200. package/dist/orchestration/inference-errors.d.ts.map +1 -0
  201. package/dist/orchestration/inference-errors.js +16 -0
  202. package/dist/orchestration/inference-errors.js.map +1 -0
  203. package/dist/orchestration/input-images.d.ts +12 -0
  204. package/dist/orchestration/input-images.d.ts.map +1 -0
  205. package/dist/orchestration/input-images.js +66 -0
  206. package/dist/orchestration/input-images.js.map +1 -0
  207. package/dist/orchestration/instance-lock.d.ts +5 -0
  208. package/dist/orchestration/instance-lock.d.ts.map +1 -0
  209. package/dist/orchestration/instance-lock.js +33 -0
  210. package/dist/orchestration/instance-lock.js.map +1 -0
  211. package/dist/orchestration/line-loading.d.ts +21 -0
  212. package/dist/orchestration/line-loading.d.ts.map +1 -0
  213. package/dist/orchestration/line-loading.js +89 -0
  214. package/dist/orchestration/line-loading.js.map +1 -0
  215. package/dist/orchestration/media.d.ts +3 -0
  216. package/dist/orchestration/media.d.ts.map +1 -0
  217. package/dist/orchestration/media.js +46 -0
  218. package/dist/orchestration/media.js.map +1 -0
  219. package/dist/orchestration/migrations/schema.d.ts +3 -0
  220. package/dist/orchestration/migrations/schema.d.ts.map +1 -0
  221. package/dist/orchestration/migrations/schema.js +80 -0
  222. package/dist/orchestration/migrations/schema.js.map +1 -0
  223. package/dist/orchestration/notification-mailbox.d.ts +5 -0
  224. package/dist/orchestration/notification-mailbox.d.ts.map +1 -0
  225. package/dist/orchestration/notification-mailbox.js +29 -0
  226. package/dist/orchestration/notification-mailbox.js.map +1 -0
  227. package/dist/orchestration/process-activity.d.ts +23 -0
  228. package/dist/orchestration/process-activity.d.ts.map +1 -0
  229. package/dist/orchestration/process-activity.js +95 -0
  230. package/dist/orchestration/process-activity.js.map +1 -0
  231. package/dist/orchestration/process-supervisor.d.ts +15 -0
  232. package/dist/orchestration/process-supervisor.d.ts.map +1 -0
  233. package/dist/orchestration/process-supervisor.js +92 -0
  234. package/dist/orchestration/process-supervisor.js.map +1 -0
  235. package/dist/orchestration/process-turn.d.ts +35 -0
  236. package/dist/orchestration/process-turn.d.ts.map +1 -0
  237. package/dist/orchestration/process-turn.js +246 -0
  238. package/dist/orchestration/process-turn.js.map +1 -0
  239. package/dist/orchestration/progress-review.d.ts +28 -0
  240. package/dist/orchestration/progress-review.d.ts.map +1 -0
  241. package/dist/orchestration/progress-review.js +48 -0
  242. package/dist/orchestration/progress-review.js.map +1 -0
  243. package/dist/orchestration/recovery.d.ts +8 -0
  244. package/dist/orchestration/recovery.d.ts.map +1 -0
  245. package/dist/orchestration/recovery.js +35 -0
  246. package/dist/orchestration/recovery.js.map +1 -0
  247. package/dist/orchestration/reply-context.d.ts +7 -0
  248. package/dist/orchestration/reply-context.d.ts.map +1 -0
  249. package/dist/orchestration/reply-context.js +54 -0
  250. package/dist/orchestration/reply-context.js.map +1 -0
  251. package/dist/orchestration/runtime.d.ts +237 -0
  252. package/dist/orchestration/runtime.d.ts.map +1 -0
  253. package/dist/orchestration/runtime.js +1031 -0
  254. package/dist/orchestration/runtime.js.map +1 -0
  255. package/dist/orchestration/skills.d.ts +17 -0
  256. package/dist/orchestration/skills.d.ts.map +1 -0
  257. package/dist/orchestration/skills.js +32 -0
  258. package/dist/orchestration/skills.js.map +1 -0
  259. package/dist/orchestration/source-policy.d.ts +6 -0
  260. package/dist/orchestration/source-policy.d.ts.map +1 -0
  261. package/dist/orchestration/source-policy.js +16 -0
  262. package/dist/orchestration/source-policy.js.map +1 -0
  263. package/dist/orchestration/speech.d.ts +24 -0
  264. package/dist/orchestration/speech.d.ts.map +1 -0
  265. package/dist/orchestration/speech.js +61 -0
  266. package/dist/orchestration/speech.js.map +1 -0
  267. package/dist/orchestration/stop-controls.d.ts +30 -0
  268. package/dist/orchestration/stop-controls.d.ts.map +1 -0
  269. package/dist/orchestration/stop-controls.js +79 -0
  270. package/dist/orchestration/stop-controls.js.map +1 -0
  271. package/dist/orchestration/store.d.ts +92 -0
  272. package/dist/orchestration/store.d.ts.map +1 -0
  273. package/dist/orchestration/store.js +326 -0
  274. package/dist/orchestration/store.js.map +1 -0
  275. package/dist/orchestration/task-controls.d.ts +172 -0
  276. package/dist/orchestration/task-controls.d.ts.map +1 -0
  277. package/dist/orchestration/task-controls.js +59 -0
  278. package/dist/orchestration/task-controls.js.map +1 -0
  279. package/dist/orchestration/task-files.d.ts +29 -0
  280. package/dist/orchestration/task-files.d.ts.map +1 -0
  281. package/dist/orchestration/task-files.js +200 -0
  282. package/dist/orchestration/task-files.js.map +1 -0
  283. package/dist/orchestration/task-questions.d.ts +26 -0
  284. package/dist/orchestration/task-questions.d.ts.map +1 -0
  285. package/dist/orchestration/task-questions.js +160 -0
  286. package/dist/orchestration/task-questions.js.map +1 -0
  287. package/dist/orchestration/task-report.d.ts +7 -0
  288. package/dist/orchestration/task-report.d.ts.map +1 -0
  289. package/dist/orchestration/task-report.js +33 -0
  290. package/dist/orchestration/task-report.js.map +1 -0
  291. package/dist/orchestration/tasks/checkpoint-hook.d.ts +19 -0
  292. package/dist/orchestration/tasks/checkpoint-hook.d.ts.map +1 -0
  293. package/dist/orchestration/tasks/checkpoint-hook.js +49 -0
  294. package/dist/orchestration/tasks/checkpoint-hook.js.map +1 -0
  295. package/dist/orchestration/tasks/cleanup.d.ts +18 -0
  296. package/dist/orchestration/tasks/cleanup.d.ts.map +1 -0
  297. package/dist/orchestration/tasks/cleanup.js +113 -0
  298. package/dist/orchestration/tasks/cleanup.js.map +1 -0
  299. package/dist/orchestration/tasks/driver.d.ts +23 -0
  300. package/dist/orchestration/tasks/driver.d.ts.map +1 -0
  301. package/dist/orchestration/tasks/driver.js +209 -0
  302. package/dist/orchestration/tasks/driver.js.map +1 -0
  303. package/dist/orchestration/tasks/failure.d.ts +5 -0
  304. package/dist/orchestration/tasks/failure.d.ts.map +1 -0
  305. package/dist/orchestration/tasks/failure.js +17 -0
  306. package/dist/orchestration/tasks/failure.js.map +1 -0
  307. package/dist/orchestration/tasks/pool.d.ts +18 -0
  308. package/dist/orchestration/tasks/pool.d.ts.map +1 -0
  309. package/dist/orchestration/tasks/pool.js +73 -0
  310. package/dist/orchestration/tasks/pool.js.map +1 -0
  311. package/dist/orchestration/tasks/scheduler.d.ts +38 -0
  312. package/dist/orchestration/tasks/scheduler.d.ts.map +1 -0
  313. package/dist/orchestration/tasks/scheduler.js +160 -0
  314. package/dist/orchestration/tasks/scheduler.js.map +1 -0
  315. package/dist/orchestration/tasks/service.d.ts +114 -0
  316. package/dist/orchestration/tasks/service.d.ts.map +1 -0
  317. package/dist/orchestration/tasks/service.js +760 -0
  318. package/dist/orchestration/tasks/service.js.map +1 -0
  319. package/dist/orchestration/tasks/shared-workspace.d.ts +25 -0
  320. package/dist/orchestration/tasks/shared-workspace.d.ts.map +1 -0
  321. package/dist/orchestration/tasks/shared-workspace.js +162 -0
  322. package/dist/orchestration/tasks/shared-workspace.js.map +1 -0
  323. package/dist/orchestration/tasks/task-directive.d.ts +6 -0
  324. package/dist/orchestration/tasks/task-directive.d.ts.map +1 -0
  325. package/dist/orchestration/tasks/task-directive.js +41 -0
  326. package/dist/orchestration/tasks/task-directive.js.map +1 -0
  327. package/dist/orchestration/tasks/timing.d.ts +15 -0
  328. package/dist/orchestration/tasks/timing.d.ts.map +1 -0
  329. package/dist/orchestration/tasks/timing.js +48 -0
  330. package/dist/orchestration/tasks/timing.js.map +1 -0
  331. package/dist/orchestration/tasks/tool-repetition.d.ts +3 -0
  332. package/dist/orchestration/tasks/tool-repetition.d.ts.map +1 -0
  333. package/dist/orchestration/tasks/tool-repetition.js +30 -0
  334. package/dist/orchestration/tasks/tool-repetition.js.map +1 -0
  335. package/dist/orchestration/tasks/workspace.d.ts +24 -0
  336. package/dist/orchestration/tasks/workspace.d.ts.map +1 -0
  337. package/dist/orchestration/tasks/workspace.js +147 -0
  338. package/dist/orchestration/tasks/workspace.js.map +1 -0
  339. package/dist/orchestration/telegram-speech.d.ts +17 -0
  340. package/dist/orchestration/telegram-speech.d.ts.map +1 -0
  341. package/dist/orchestration/telegram-speech.js +55 -0
  342. package/dist/orchestration/telegram-speech.js.map +1 -0
  343. package/dist/orchestration/telegram-tool-status.d.ts +23 -0
  344. package/dist/orchestration/telegram-tool-status.d.ts.map +1 -0
  345. package/dist/orchestration/telegram-tool-status.js +207 -0
  346. package/dist/orchestration/telegram-tool-status.js.map +1 -0
  347. package/dist/orchestration/telegram-voices.d.ts +42 -0
  348. package/dist/orchestration/telegram-voices.d.ts.map +1 -0
  349. package/dist/orchestration/telegram-voices.js +70 -0
  350. package/dist/orchestration/telegram-voices.js.map +1 -0
  351. package/dist/orchestration/tool-activity.d.ts +10 -0
  352. package/dist/orchestration/tool-activity.d.ts.map +1 -0
  353. package/dist/orchestration/tool-activity.js +38 -0
  354. package/dist/orchestration/tool-activity.js.map +1 -0
  355. package/dist/orchestration/types.d.ts +177 -0
  356. package/dist/orchestration/types.d.ts.map +1 -0
  357. package/dist/orchestration/types.js +13 -0
  358. package/dist/orchestration/types.js.map +1 -0
  359. package/dist/orchestration/voice-reply-policy.d.ts +8 -0
  360. package/dist/orchestration/voice-reply-policy.d.ts.map +1 -0
  361. package/dist/orchestration/voice-reply-policy.js +46 -0
  362. package/dist/orchestration/voice-reply-policy.js.map +1 -0
  363. package/dist/orchestration/worker-shares.d.ts +8 -0
  364. package/dist/orchestration/worker-shares.d.ts.map +1 -0
  365. package/dist/orchestration/worker-shares.js +59 -0
  366. package/dist/orchestration/worker-shares.js.map +1 -0
  367. package/dist/orchestration/workflow.d.ts +121 -0
  368. package/dist/orchestration/workflow.d.ts.map +1 -0
  369. package/dist/orchestration/workflow.js +69 -0
  370. package/dist/orchestration/workflow.js.map +1 -0
  371. package/dist/session/input-image.d.ts +10 -0
  372. package/dist/session/input-image.d.ts.map +1 -0
  373. package/dist/session/input-image.js +3 -0
  374. package/dist/session/input-image.js.map +1 -0
  375. package/dist/session/process.d.ts +15 -3
  376. package/dist/session/process.d.ts.map +1 -1
  377. package/dist/session/process.js +143 -35
  378. package/dist/session/process.js.map +1 -1
  379. package/dist/session/runtime-profile.d.ts +36 -0
  380. package/dist/session/runtime-profile.d.ts.map +1 -0
  381. package/dist/session/runtime-profile.js +63 -0
  382. package/dist/session/runtime-profile.js.map +1 -0
  383. package/dist/session/store.d.ts.map +1 -1
  384. package/dist/session/store.js +23 -1
  385. package/dist/session/store.js.map +1 -1
  386. package/dist/share/share-store.d.ts +3 -1
  387. package/dist/share/share-store.d.ts.map +1 -1
  388. package/dist/share/share-store.js +13 -2
  389. package/dist/share/share-store.js.map +1 -1
  390. package/dist/shared/line-request-order.d.ts +2 -0
  391. package/dist/shared/line-request-order.d.ts.map +1 -0
  392. package/dist/shared/line-request-order.js +16 -0
  393. package/dist/shared/line-request-order.js.map +1 -0
  394. package/dist/shared/task-elapsed.d.ts +3 -0
  395. package/dist/shared/task-elapsed.d.ts.map +1 -0
  396. package/dist/shared/task-elapsed.js +12 -0
  397. package/dist/shared/task-elapsed.js.map +1 -0
  398. package/dist/shared/task-updated-time.d.ts +3 -0
  399. package/dist/shared/task-updated-time.d.ts.map +1 -0
  400. package/dist/shared/task-updated-time.js +15 -0
  401. package/dist/shared/task-updated-time.js.map +1 -0
  402. package/dist/skills/loader.d.ts +2 -0
  403. package/dist/skills/loader.d.ts.map +1 -1
  404. package/dist/skills/loader.js.map +1 -1
  405. package/dist/telegram/chunks.d.ts +19 -0
  406. package/dist/telegram/chunks.d.ts.map +1 -0
  407. package/dist/telegram/chunks.js +129 -0
  408. package/dist/telegram/chunks.js.map +1 -0
  409. package/dist/telegram/markdown.d.ts.map +1 -1
  410. package/dist/telegram/markdown.js +18 -3
  411. package/dist/telegram/markdown.js.map +1 -1
  412. package/dist/telegram/receiver.d.ts +2 -1
  413. package/dist/telegram/receiver.d.ts.map +1 -1
  414. package/dist/telegram/receiver.js +6 -1
  415. package/dist/telegram/receiver.js.map +1 -1
  416. package/dist/types.d.ts +14 -0
  417. package/dist/types.d.ts.map +1 -1
  418. package/dist/ui/web-ui.d.ts.map +1 -1
  419. package/dist/ui/web-ui.js +31 -5
  420. package/dist/ui/web-ui.js.map +1 -1
  421. package/dist/voice/diagnostics.d.ts +29 -0
  422. package/dist/voice/diagnostics.d.ts.map +1 -0
  423. package/dist/voice/diagnostics.js +37 -0
  424. package/dist/voice/diagnostics.js.map +1 -0
  425. package/dist/voice/errors.d.ts +19 -0
  426. package/dist/voice/errors.d.ts.map +1 -0
  427. package/dist/voice/errors.js +133 -0
  428. package/dist/voice/errors.js.map +1 -0
  429. package/dist/voice/line-audio.d.ts +4 -0
  430. package/dist/voice/line-audio.d.ts.map +1 -0
  431. package/dist/voice/line-audio.js +27 -0
  432. package/dist/voice/line-audio.js.map +1 -0
  433. package/dist/voice/managed-quota.d.ts +5 -0
  434. package/dist/voice/managed-quota.d.ts.map +1 -0
  435. package/dist/voice/managed-quota.js +35 -0
  436. package/dist/voice/managed-quota.js.map +1 -0
  437. package/dist/voice/mp3.d.ts +3 -0
  438. package/dist/voice/mp3.d.ts.map +1 -0
  439. package/dist/voice/mp3.js +30 -0
  440. package/dist/voice/mp3.js.map +1 -0
  441. package/dist/voice/notes.d.ts +9 -0
  442. package/dist/voice/notes.d.ts.map +1 -0
  443. package/dist/voice/notes.js +68 -0
  444. package/dist/voice/notes.js.map +1 -0
  445. package/dist/voice/playback.d.ts +22 -0
  446. package/dist/voice/playback.d.ts.map +1 -0
  447. package/dist/voice/playback.js +52 -0
  448. package/dist/voice/playback.js.map +1 -0
  449. package/dist/voice/preview.d.ts +6 -0
  450. package/dist/voice/preview.d.ts.map +1 -0
  451. package/dist/voice/preview.js +44 -0
  452. package/dist/voice/preview.js.map +1 -0
  453. package/dist/voice/protocol.d.ts +10 -0
  454. package/dist/voice/protocol.d.ts.map +1 -0
  455. package/dist/voice/protocol.js +30 -0
  456. package/dist/voice/protocol.js.map +1 -0
  457. package/dist/voice/providers/cartesia-tts.d.ts +26 -0
  458. package/dist/voice/providers/cartesia-tts.d.ts.map +1 -0
  459. package/dist/voice/providers/cartesia-tts.js +95 -0
  460. package/dist/voice/providers/cartesia-tts.js.map +1 -0
  461. package/dist/voice/providers/deepgram-stt.d.ts +20 -0
  462. package/dist/voice/providers/deepgram-stt.d.ts.map +1 -0
  463. package/dist/voice/providers/deepgram-stt.js +66 -0
  464. package/dist/voice/providers/deepgram-stt.js.map +1 -0
  465. package/dist/voice/providers/elevenlabs-stt.d.ts +20 -0
  466. package/dist/voice/providers/elevenlabs-stt.d.ts.map +1 -0
  467. package/dist/voice/providers/elevenlabs-stt.js +92 -0
  468. package/dist/voice/providers/elevenlabs-stt.js.map +1 -0
  469. package/dist/voice/providers/elevenlabs-tts.d.ts +26 -0
  470. package/dist/voice/providers/elevenlabs-tts.d.ts.map +1 -0
  471. package/dist/voice/providers/elevenlabs-tts.js +82 -0
  472. package/dist/voice/providers/elevenlabs-tts.js.map +1 -0
  473. package/dist/voice/providers/encoded-audio-tts.d.ts +21 -0
  474. package/dist/voice/providers/encoded-audio-tts.d.ts.map +1 -0
  475. package/dist/voice/providers/encoded-audio-tts.js +175 -0
  476. package/dist/voice/providers/encoded-audio-tts.js.map +1 -0
  477. package/dist/voice/providers/fake.d.ts +39 -0
  478. package/dist/voice/providers/fake.d.ts.map +1 -0
  479. package/dist/voice/providers/fake.js +41 -0
  480. package/dist/voice/providers/fake.js.map +1 -0
  481. package/dist/voice/providers/gemini-live-stt.d.ts +21 -0
  482. package/dist/voice/providers/gemini-live-stt.d.ts.map +1 -0
  483. package/dist/voice/providers/gemini-live-stt.js +158 -0
  484. package/dist/voice/providers/gemini-live-stt.js.map +1 -0
  485. package/dist/voice/providers/gemini.d.ts +60 -0
  486. package/dist/voice/providers/gemini.d.ts.map +1 -0
  487. package/dist/voice/providers/gemini.js +124 -0
  488. package/dist/voice/providers/gemini.js.map +1 -0
  489. package/dist/voice/providers/model-ref.d.ts +9 -0
  490. package/dist/voice/providers/model-ref.d.ts.map +1 -0
  491. package/dist/voice/providers/model-ref.js +31 -0
  492. package/dist/voice/providers/model-ref.js.map +1 -0
  493. package/dist/voice/providers/openrouter.d.ts +39 -0
  494. package/dist/voice/providers/openrouter.d.ts.map +1 -0
  495. package/dist/voice/providers/openrouter.js +154 -0
  496. package/dist/voice/providers/openrouter.js.map +1 -0
  497. package/dist/voice/providers/paxalabs-stt.d.ts +12 -0
  498. package/dist/voice/providers/paxalabs-stt.d.ts.map +1 -0
  499. package/dist/voice/providers/paxalabs-stt.js +41 -0
  500. package/dist/voice/providers/paxalabs-stt.js.map +1 -0
  501. package/dist/voice/providers/paxalabs-tts.d.ts +23 -0
  502. package/dist/voice/providers/paxalabs-tts.d.ts.map +1 -0
  503. package/dist/voice/providers/paxalabs-tts.js +80 -0
  504. package/dist/voice/providers/paxalabs-tts.js.map +1 -0
  505. package/dist/voice/providers/recorded-stt.d.ts +34 -0
  506. package/dist/voice/providers/recorded-stt.d.ts.map +1 -0
  507. package/dist/voice/providers/recorded-stt.js +59 -0
  508. package/dist/voice/providers/recorded-stt.js.map +1 -0
  509. package/dist/voice/providers/registry.d.ts +10 -0
  510. package/dist/voice/providers/registry.d.ts.map +1 -0
  511. package/dist/voice/providers/registry.js +77 -0
  512. package/dist/voice/providers/registry.js.map +1 -0
  513. package/dist/voice/providers/socket.d.ts +10 -0
  514. package/dist/voice/providers/socket.d.ts.map +1 -0
  515. package/dist/voice/providers/socket.js +91 -0
  516. package/dist/voice/providers/socket.js.map +1 -0
  517. package/dist/voice/providers/upstream.d.ts +9 -0
  518. package/dist/voice/providers/upstream.d.ts.map +1 -0
  519. package/dist/voice/providers/upstream.js +51 -0
  520. package/dist/voice/providers/upstream.js.map +1 -0
  521. package/dist/voice/providers/voice-catalog.d.ts +17 -0
  522. package/dist/voice/providers/voice-catalog.d.ts.map +1 -0
  523. package/dist/voice/providers/voice-catalog.js +167 -0
  524. package/dist/voice/providers/voice-catalog.js.map +1 -0
  525. package/dist/voice/queue.d.ts +2 -0
  526. package/dist/voice/queue.d.ts.map +1 -0
  527. package/dist/voice/queue.js +6 -0
  528. package/dist/voice/queue.js.map +1 -0
  529. package/dist/voice/session.d.ts +86 -0
  530. package/dist/voice/session.d.ts.map +1 -0
  531. package/dist/voice/session.js +464 -0
  532. package/dist/voice/session.js.map +1 -0
  533. package/dist/voice/turn-manager.d.ts +27 -0
  534. package/dist/voice/turn-manager.d.ts.map +1 -0
  535. package/dist/voice/turn-manager.js +75 -0
  536. package/dist/voice/turn-manager.js.map +1 -0
  537. package/dist/voice/types.d.ts +78 -0
  538. package/dist/voice/types.d.ts.map +1 -0
  539. package/dist/voice/types.js +18 -0
  540. package/dist/voice/types.js.map +1 -0
  541. package/dist/voice/wav.d.ts +2 -0
  542. package/dist/voice/wav.d.ts.map +1 -0
  543. package/dist/voice/wav.js +21 -0
  544. package/dist/voice/wav.js.map +1 -0
  545. package/dist/wechat/ilink-client.d.ts +13 -0
  546. package/dist/wechat/ilink-client.d.ts.map +1 -1
  547. package/dist/wechat/ilink-client.js +19 -0
  548. package/dist/wechat/ilink-client.js.map +1 -1
  549. package/dist/whatsapp/manager.d.ts.map +1 -1
  550. package/dist/whatsapp/manager.js +51 -1
  551. package/dist/whatsapp/manager.js.map +1 -1
  552. package/mcp/capability-catalog.ts +206 -0
  553. package/mcp/modules.ts +56 -0
  554. package/mcp/server.ts +18 -37
  555. package/mcp/tools/browser/module.ts +1 -1
  556. package/mcp/tools/browser/skills/open-browser/SKILL.md +5 -3
  557. package/mcp/tools/discord/commands.ts +17 -1
  558. package/mcp/tools/discord/inbound.ts +11 -0
  559. package/mcp/tools/discord/module.ts +42 -2
  560. package/mcp/tools/discord/receiver-server.ts +10 -0
  561. package/mcp/tools/discord/types.ts +4 -1
  562. package/mcp/tools/image/module.ts +3 -1
  563. package/mcp/tools/receiver-spool.test.ts +28 -0
  564. package/mcp/tools/receiver-spool.ts +56 -0
  565. package/mcp/tools/share-file/module.ts +9 -1
  566. package/mcp/tools/shared/share-client.ts +19 -0
  567. package/mcp/tools/tasks/module.ts +35 -0
  568. package/mcp/tools/telegram/media-group.ts +21 -0
  569. package/mcp/tools/telegram/receiver-server.ts +246 -11
  570. package/mcp/tools/telegram/selection-confirmation.ts +20 -0
  571. package/mcp/tools/telegram/task-browser.ts +117 -0
  572. package/mcp/tools/telegram/task-detail.ts +36 -0
  573. package/mcp/tools/telegram/task-elapsed.ts +1 -0
  574. package/mcp/tools/telegram/typing.ts +6 -116
  575. package/mcp/tools/video/module.ts +1 -1
  576. package/mcp/types.ts +5 -0
  577. package/package.json +2 -1
  578. package/resource/claude_gateway.jpeg +0 -0
  579. package/scripts/orchestration/bench-store.cjs +30 -0
  580. package/scripts/orchestration/inspect.cjs +16 -0
  581. package/scripts/orchestration/probe-profile.cjs +67 -0
  582. package/scripts/orchestration/reconcile.cjs +21 -0
  583. package/scripts/orchestration/smoke-elevenlabs.cjs +90 -0
  584. package/scripts/orchestration/smoke-media.cjs +70 -0
  585. package/scripts/orchestration/smoke-text.cjs +101 -0
  586. package/scripts/orchestration/smoke-vision.cjs +49 -0
@@ -0,0 +1,206 @@
1
+ /** Metadata only. Never initialize channel receivers or call an MCP tool. */
2
+ import { Client } from '@modelcontextprotocol/sdk/client/index.js';
3
+ import { StdioClientTransport } from '@modelcontextprotocol/sdk/client/stdio.js';
4
+ import { StreamableHTTPClientTransport } from '@modelcontextprotocol/sdk/client/streamableHttp.js';
5
+ import { SSEClientTransport } from '@modelcontextprotocol/sdk/client/sse.js';
6
+ import { gatewayModules } from './modules';
7
+ import { AGENT_TASK_TOOLS, WORKER_REPORT_TOOLS } from './tools/tasks/module';
8
+
9
+ type Entry = {
10
+ name: string;
11
+ description: string;
12
+ server: string;
13
+ status: string;
14
+ via: 'agent' | 'worker' | 'unavailable';
15
+ };
16
+ const entries: Entry[] = [];
17
+ const servers: Array<{ name: string; status: string }> = [];
18
+ const chunks: Buffer[] = [];
19
+ let bytes = 0;
20
+ for await (const chunk of process.stdin) {
21
+ bytes += chunk.length;
22
+ if (bytes > 4 * 1024 * 1024) throw Error('CATALOG_INPUT_TOO_LARGE');
23
+ chunks.push(Buffer.from(chunk));
24
+ }
25
+ const input = JSON.parse(Buffer.concat(chunks).toString());
26
+ // Mirror the worker module gates for metadata, without issuing a usable ticket.
27
+ const profileKeys = [
28
+ 'GATEWAY_ORCHESTRATION_ROLE',
29
+ 'GATEWAY_ORCHESTRATION_MEDIA',
30
+ 'GATEWAY_ORCHESTRATION_TICKET_FILE',
31
+ ];
32
+ const original = profileKeys.map((key) => process.env[key]);
33
+ Object.assign(process.env, {
34
+ GATEWAY_ORCHESTRATION_ROLE: 'worker',
35
+ GATEWAY_ORCHESTRATION_MEDIA: 'true',
36
+ GATEWAY_ORCHESTRATION_TICKET_FILE: '/capability-discovery-no-execution',
37
+ });
38
+ const worker = new Set(
39
+ gatewayModules('worker', true).flatMap((m) =>
40
+ m.isEnabled() ? m.getTools().map((t) => t.name) : []
41
+ )
42
+ );
43
+ for (const module of gatewayModules()) {
44
+ let enabled = false;
45
+ try {
46
+ enabled = module.isEnabled();
47
+ } catch {
48
+ /* Unavailable, not absent. */
49
+ }
50
+ for (const tool of module.getTools())
51
+ entries.push({
52
+ name: `mcp__gateway__${tool.name}`,
53
+ description: tool.description,
54
+ server: 'gateway',
55
+ status: !enabled
56
+ ? 'not_configured'
57
+ : worker.has(tool.name)
58
+ ? tool.name.startsWith('memory_shared_')
59
+ ? 'requires_memory_permission'
60
+ : 'available'
61
+ : 'not_exposed_to_workers',
62
+ via:
63
+ enabled && ['memory_search', 'memory_get'].includes(tool.name)
64
+ ? 'agent'
65
+ : enabled && worker.has(tool.name)
66
+ ? 'worker'
67
+ : 'unavailable',
68
+ });
69
+ }
70
+ for (const tool of AGENT_TASK_TOOLS)
71
+ entries.push({
72
+ name: `mcp__gateway__${tool.name}`,
73
+ description: tool.description,
74
+ server: 'gateway',
75
+ status:
76
+ tool.name === 'conversation_intake'
77
+ ? 'requires_semantic_intake'
78
+ : 'available',
79
+ via: 'agent',
80
+ });
81
+ for (const tool of WORKER_REPORT_TOOLS)
82
+ entries.push({
83
+ name: `mcp__gateway__${tool.name}`,
84
+ description: tool.description,
85
+ server: 'gateway',
86
+ status:
87
+ tool.name === 'task_memory_append'
88
+ ? 'requires_memory_permission'
89
+ : 'available',
90
+ via: 'worker',
91
+ });
92
+ profileKeys.forEach((key, i) => {
93
+ if (original[i] === undefined) delete process.env[key];
94
+ else process.env[key] = original[i];
95
+ });
96
+ servers.push({ name: 'gateway', status: 'available' });
97
+ for (const [name, value] of Object.entries(input.servers ?? {})) {
98
+ const config = value as {
99
+ type?: string;
100
+ command?: string;
101
+ args?: string[];
102
+ env?: Record<string, string>;
103
+ url?: string;
104
+ headers?: Record<string, string>;
105
+ };
106
+ const client = new Client({
107
+ name: 'gateway-capability-discovery',
108
+ version: '1',
109
+ });
110
+ let transport:
111
+ | StdioClientTransport
112
+ | StreamableHTTPClientTransport
113
+ | SSEClientTransport
114
+ | undefined;
115
+ const timeout = setTimeout(() => {
116
+ void client.close();
117
+ }, 5000);
118
+ try {
119
+ if (config.command)
120
+ transport = new StdioClientTransport({
121
+ command: config.command,
122
+ args: config.args,
123
+ env: {
124
+ ...Object.fromEntries(
125
+ Object.entries(process.env).filter(
126
+ (e): e is [string, string] => typeof e[1] === 'string'
127
+ )
128
+ ),
129
+ ...config.env,
130
+ },
131
+ stderr: 'ignore',
132
+ });
133
+ else if (config.url)
134
+ transport =
135
+ config.type === 'sse'
136
+ ? new SSEClientTransport(new URL(config.url), {
137
+ requestInit: { headers: config.headers },
138
+ })
139
+ : new StreamableHTTPClientTransport(new URL(config.url), {
140
+ requestInit: { headers: config.headers },
141
+ });
142
+ else throw Error('INVALID_MCP_CONFIG');
143
+ await client.connect(transport, { timeout: 5000 });
144
+ let cursor: string | undefined;
145
+ const seen = new Set<string>();
146
+ do {
147
+ const result = await client.listTools(cursor ? { cursor } : {}, {
148
+ timeout: 5000,
149
+ });
150
+ for (const tool of result.tools)
151
+ entries.push({
152
+ name: `mcp__${name.replace(/[^a-zA-Z0-9_-]/g, '_')}__${tool.name.replace(/[^a-zA-Z0-9_-]/g, '_')}`,
153
+ description: tool.description ?? '',
154
+ server: name,
155
+ status: 'available',
156
+ via: 'worker',
157
+ });
158
+ cursor = result.nextCursor;
159
+ if (cursor && seen.has(cursor)) throw Error('CATALOG_CURSOR_LOOP');
160
+ if (cursor) seen.add(cursor);
161
+ if (Buffer.byteLength(JSON.stringify(entries)) > 3 * 1024 * 1024)
162
+ throw Error('CATALOG_TOO_LARGE');
163
+ } while (cursor);
164
+ servers.push({ name, status: 'available' });
165
+ } catch {
166
+ // Do not publish connection errors: URLs/headers may include secrets.
167
+ for (const entry of entries)
168
+ if (entry.server === name) {
169
+ entry.status = 'discovery_incomplete';
170
+ entry.via = 'unavailable';
171
+ }
172
+ const observed = input.observed?.find(
173
+ (s: { name: string; status: string }) =>
174
+ s.name === name && s.status === 'connected'
175
+ );
176
+ if (observed) {
177
+ for (const tool of observed.tools ?? []) {
178
+ const fullName = `mcp__${name.replace(/[^a-zA-Z0-9_-]/g, '_')}__${String(tool.name).replace(/[^a-zA-Z0-9_-]/g, '_')}`;
179
+ if (!entries.some((e) => e.name === fullName))
180
+ entries.push({
181
+ name: fullName,
182
+ description:
183
+ tool.description ||
184
+ 'Tool reported by the Claude Code MCP runtime; detailed metadata unavailable.',
185
+ server: name,
186
+ status: 'available',
187
+ via: 'worker',
188
+ });
189
+ else
190
+ for (const entry of entries)
191
+ if (entry.name === fullName) {
192
+ entry.status = 'available';
193
+ entry.via = 'worker';
194
+ }
195
+ }
196
+ servers.push({ name, status: 'available_names_only' });
197
+ } else servers.push({ name, status: 'discovery_unavailable' });
198
+ } finally {
199
+ clearTimeout(timeout);
200
+ await client.close().catch(() => {});
201
+ await transport?.close().catch(() => {});
202
+ }
203
+ }
204
+ process.stdout.write(
205
+ JSON.stringify({ entries, servers, observedAt: new Date().toISOString() })
206
+ );
package/mcp/modules.ts ADDED
@@ -0,0 +1,56 @@
1
+ import { TelegramModule } from './tools/telegram/module';
2
+ import { DiscordModule } from './tools/discord/module';
3
+ import { LineModule } from './tools/line/module';
4
+ import { SlackModule } from './tools/slack/module';
5
+ import { WhatsAppModule } from './tools/whatsapp/module';
6
+ import { WhatsAppCloudModule } from './tools/whatsapp-cloud/module';
7
+ import { WeChatModule } from './tools/wechat/module';
8
+ import { CronModule } from './tools/cron/module';
9
+ import { SkillsModule } from './tools/skills/module';
10
+ import { AgentModule } from './tools/agent/module';
11
+ import { BrowserModule } from './tools/browser/module';
12
+ import { ImageModule } from './tools/image/module';
13
+ import { VideoModule } from './tools/video/module';
14
+ import { ShareFileModule } from './tools/share-file/module';
15
+ import { AppsModule } from './tools/apps/module';
16
+ import { ApiModule } from './tools/api/module';
17
+ import { MemoryModule } from './tools/memory/module';
18
+ import type { ChannelModule, ToolModule } from './types';
19
+
20
+ /** Shared registration for execution and read-only capability discovery. */
21
+ export function gatewayModules(
22
+ role?: string,
23
+ media = false
24
+ ): Array<ChannelModule | ToolModule> {
25
+ return role
26
+ ? [
27
+ new MemoryModule(),
28
+ ...(role === 'worker' && media
29
+ ? [
30
+ new ImageModule(),
31
+ new VideoModule(),
32
+ new ShareFileModule(),
33
+ new BrowserModule(),
34
+ ]
35
+ : []),
36
+ ]
37
+ : [
38
+ new TelegramModule(),
39
+ new DiscordModule(),
40
+ new LineModule(),
41
+ new SlackModule(),
42
+ new WhatsAppModule(),
43
+ new WhatsAppCloudModule(),
44
+ new WeChatModule(),
45
+ new CronModule(),
46
+ new SkillsModule(),
47
+ new AgentModule(),
48
+ new BrowserModule(),
49
+ new ImageModule(),
50
+ new VideoModule(),
51
+ new ShareFileModule(),
52
+ new AppsModule(),
53
+ new ApiModule(),
54
+ new MemoryModule(),
55
+ ];
56
+ }
package/mcp/server.ts CHANGED
@@ -12,27 +12,14 @@ import {
12
12
  ListToolsRequestSchema,
13
13
  CallToolRequestSchema,
14
14
  } from '@modelcontextprotocol/sdk/types.js';
15
- import { TelegramModule } from './tools/telegram/module';
16
- import { DiscordModule } from './tools/discord/module';
17
- import { LineModule } from './tools/line/module';
18
- import { SlackModule } from './tools/slack/module';
19
- import { WhatsAppModule } from './tools/whatsapp/module';
20
- import { WhatsAppCloudModule } from './tools/whatsapp-cloud/module';
21
- import { WeChatModule } from './tools/wechat/module';
22
- import { CronModule } from './tools/cron/module';
23
- import { SkillsModule } from './tools/skills/module';
24
- import { AgentModule } from './tools/agent/module';
25
- import { BrowserModule } from './tools/browser/module';
26
- import { ImageModule } from './tools/image/module';
27
- import { VideoModule } from './tools/video/module';
28
- import { ShareFileModule } from './tools/share-file/module';
29
- import { AppsModule } from './tools/apps/module';
30
- import { ApiModule } from './tools/api/module';
31
- import { MemoryModule } from './tools/memory/module';
15
+ import { gatewayModules } from './modules';
16
+ import { AGENT_TASK_TOOLS, WORKER_REPORT_TOOLS, callTaskBridge } from './tools/tasks/module';
32
17
  import { buildChannelInstructions } from './instructions';
33
18
  import type { ChannelModule, ToolModule, McpToolDefinition } from './types';
34
19
 
35
20
  const ORIGIN_CHANNEL = process.env.GATEWAY_ORIGIN_CHANNEL ?? '';
21
+ const ORCHESTRATION_ROLE = process.env.GATEWAY_ORCHESTRATION_ROLE;
22
+ if (ORCHESTRATION_ROLE && !['agent', 'worker'].includes(ORCHESTRATION_ROLE)) throw new Error('Invalid orchestration MCP role');
36
23
 
37
24
  type AnyModule = ChannelModule | ToolModule;
38
25
 
@@ -40,25 +27,7 @@ function isChannelModule(mod: AnyModule): mod is ChannelModule {
40
27
  return 'start' in mod && typeof (mod as ChannelModule).start === 'function';
41
28
  }
42
29
 
43
- const modules: AnyModule[] = [
44
- new TelegramModule(),
45
- new DiscordModule(),
46
- new LineModule(),
47
- new SlackModule(),
48
- new WhatsAppModule(),
49
- new WhatsAppCloudModule(),
50
- new WeChatModule(),
51
- new CronModule(),
52
- new SkillsModule(),
53
- new AgentModule(),
54
- new BrowserModule(),
55
- new ImageModule(),
56
- new VideoModule(),
57
- new ShareFileModule(),
58
- new AppsModule(),
59
- new ApiModule(),
60
- new MemoryModule(),
61
- ];
30
+ const modules = gatewayModules(ORCHESTRATION_ROLE, process.env.GATEWAY_ORCHESTRATION_MEDIA === 'true');
62
31
 
63
32
  // Build tool-to-module mapping for enabled modules
64
33
  const toolMap = new Map<string, AnyModule>();
@@ -76,11 +45,16 @@ for (const mod of modules) {
76
45
  if (!visible) continue;
77
46
 
78
47
  for (const tool of mod.getTools()) {
48
+ if (ORCHESTRATION_ROLE && !['memory_search', 'memory_get'].includes(tool.name) && !(ORCHESTRATION_ROLE === 'worker' &&
49
+ ((mod.id === 'image' || mod.id === 'video' || mod.id === 'share-file' || mod.id === 'browser') || (mod.id === 'memory' && process.env.GATEWAY_ORCHESTRATION_WRITE_MEMORY === 'true')))) continue;
79
50
  toolMap.set(tool.name, mod);
80
51
  visibleTools.push(tool);
81
52
  }
82
53
  }
83
54
 
55
+ const taskTools = ORCHESTRATION_ROLE === 'agent' ? AGENT_TASK_TOOLS.filter(tool => (tool.name !== 'conversation_intake' || process.env.GATEWAY_SEMANTIC_INTAKE === 'true') && (tool.name !== 'capabilities_list' || process.env.GATEWAY_CAPABILITY_CATALOG === 'true')) : ORCHESTRATION_ROLE === 'worker' ? WORKER_REPORT_TOOLS.filter(tool => tool.name !== 'task_memory_append' || process.env.GATEWAY_ORCHESTRATION_WRITE_MEMORY === 'true') : [];
56
+ if (ORCHESTRATION_ROLE && process.env.GATEWAY_ORCHESTRATION_TICKET_FILE) visibleTools.push(...taskTools);
57
+
84
58
  // Initialize channel modules so their bot API clients are ready for tool calls.
85
59
  // initBot() returns immediately after creating the client — no blocking.
86
60
  for (const mod of modules) {
@@ -105,7 +79,7 @@ const mcp = new Server(
105
79
  'claude/channel/permission': {},
106
80
  },
107
81
  },
108
- instructions: buildChannelInstructions(imageEnabled, videoEnabled),
82
+ instructions: ORCHESTRATION_ROLE ? 'Use scoped capability discovery, task tools and memory retrieval. The agent writes user-facing responses; workers return task results and orchestration handles delivery.' : buildChannelInstructions(imageEnabled, videoEnabled),
109
83
  },
110
84
  );
111
85
 
@@ -116,6 +90,9 @@ mcp.setRequestHandler(ListToolsRequestSchema, async () => ({
116
90
  mcp.setRequestHandler(CallToolRequestSchema, async (req, extra) => {
117
91
  const toolName = req.params.name;
118
92
  const args = (req.params.arguments ?? {}) as Record<string, unknown>;
93
+ if (ORCHESTRATION_ROLE && process.env.GATEWAY_ORCHESTRATION_TICKET_FILE && taskTools.some(tool => tool.name === toolName)) {
94
+ return callTaskBridge(toolName, args, String(extra.requestId), AbortSignal.any([extra.signal, shutdownController.signal]));
95
+ }
119
96
 
120
97
  const mod = toolMap.get(toolName);
121
98
  if (!mod) {
@@ -124,6 +101,10 @@ mcp.setRequestHandler(CallToolRequestSchema, async (req, extra) => {
124
101
  isError: true,
125
102
  };
126
103
  }
104
+ if (ORCHESTRATION_ROLE === 'worker' && process.env.GATEWAY_ORCHESTRATION_MEDIA === 'true') {
105
+ const validation = await callTaskBridge('task_validate', {}, String(extra.requestId), AbortSignal.any([extra.signal, shutdownController.signal]));
106
+ if (validation.isError) return validation;
107
+ }
127
108
 
128
109
  // extra.signal fires on notifications/cancelled for THIS call (the SDK matches
129
110
  // it by requestId) — the CLI sends that when a user Stop/Ctrl-C interrupts an
@@ -159,7 +159,7 @@ async function callGetpodBrowser(
159
159
  const browserToolDefs: McpToolDefinition[] = [
160
160
  {
161
161
  name: 'browser_create_session',
162
- description: 'Create or resume a browser session. Returns session status.',
162
+ description: 'Create or resume GetPod Cloud Browser, NOT the user Chrome or Remote Browser connector. Use only when Cloud Browser is selected, or no Remote Browser is connected for a generic browser request. Returns session status.',
163
163
  inputSchema: {
164
164
  type: 'object',
165
165
  properties: {
@@ -1,16 +1,18 @@
1
1
  ---
2
2
  name: open-browser
3
- description: "ALWAYS invoke this skill when user says 'browser [site]', 'open [site]', or asks to navigate to a website. Never call MCP browser tools directly."
3
+ description: "Open a website in GetPod Cloud Browser after that environment is selected. Does not control the user Chrome or Remote Browser connector."
4
4
  user-invocable: true
5
5
  ---
6
6
 
7
7
  # open-browser
8
8
 
9
- When user says "open X in browser", "navigate to X", "open chrome", "browser to X", "switch to tab X", etc.
9
+ Use this skill only for GetPod Cloud Browser. Remote Browser is a separate connector controlling the user's approved device tabs.
10
+
11
+ If a Remote Browser connector is enabled and the user has not selected an environment, ask whether to use Remote Browser (recommended) or GetPod Cloud Browser before taking browser actions. An explicit remote/device request must use that connector instead of this skill. Reuse the selection for related follow-ups. With no Remote Browser connector, ordinary browser requests may use Cloud Browser. Never fall back from Remote Browser to Cloud Browser without user approval.
10
12
 
11
13
  ## Rules
12
14
 
13
- - Use ONLY `mcp__gateway__browser_*` tools — never Python, never CDP direct, never filesystem
15
+ - For the selected Cloud Browser workflow, use ONLY `mcp__gateway__browser_*` tools — never Python, never CDP direct, never filesystem
14
16
  - NEVER use `wait: "networkidle"` — it hangs on SPAs. Omit `wait` entirely (fire-and-forget)
15
17
  - Always check tab state before navigating — tab IDs change between sessions
16
18
  - Do NOT pass `session_id` — it is injected automatically from agent context
@@ -24,15 +24,31 @@ export const SLASH_COMMANDS: SlashCommandDef[] = [
24
24
  },
25
25
  ];
26
26
 
27
+ export function commandDefinitions(orchestration:boolean,interactive:boolean):SlashCommandDef[]{
28
+ return [...SLASH_COMMANDS,
29
+ ...(orchestration ? [
30
+ {name:'voice',description:'Turn automatic voice replies on or off',options:[{name:'mode',description:'on or off (omit to show buttons)',required:false,type:'STRING' as const}]},
31
+ {name:'voices',description:'Choose the agent voice'},
32
+ {name:'tasks',description:'View pending tasks in this conversation'},
33
+ {name:'help',description:'Show available orchestration controls'},
34
+ ] : []),
35
+ {name:'stop',description:orchestration?'Stop a response or choose a task to stop':'Stop the agent response'},
36
+ ...(interactive && !orchestration ? [{name:'cli',description:'Open the live terminal viewer'}] : []),
37
+ ];
38
+ }
39
+
27
40
  export async function registerCommands(
28
41
  client: any,
29
42
  token: string,
43
+ orchestration = false,
44
+ interactive = false,
30
45
  ): Promise<void> {
31
46
  // @ts-ignore — discord.js in mcp/node_modules
32
47
  const { REST, Routes, SlashCommandBuilder } = await import('discord.js');
33
48
  const rest = new REST().setToken(token);
34
49
 
35
- const bodies = SLASH_COMMANDS.map(cmd => {
50
+ const commands=commandDefinitions(orchestration,interactive);
51
+ const bodies = commands.map(cmd => {
36
52
  const builder = new SlashCommandBuilder()
37
53
  .setName(cmd.name)
38
54
  .setDescription(cmd.description);
@@ -45,9 +45,20 @@ export function createMessageHandler(
45
45
  messageId: message.id,
46
46
  threadId: isThread ? message.channelId : undefined,
47
47
  attachmentFileId: message.attachments.first()?.url,
48
+ attachmentKind: (message.attachments.first()?.contentType?.startsWith('audio/') || (typeof message.flags==='number' ? !!(message.flags&8192) : message.flags?.has(8192))) ? 'voice' : 'file',
48
49
  ts: message.createdTimestamp,
49
50
  };
50
51
 
52
+ const attachments = (msg: DiscordMessage, quoted=false) => (msg.attachments.values ? [...msg.attachments.values()] : [msg.attachments.first()].filter(Boolean)).slice(0,10).map(a=>({url:a!.url,name:a!.name,kind:a!.contentType?.startsWith('image/')?'image':a!.contentType?.startsWith('audio/')?'audio':'file',quoted}));
53
+ inbound.attachments = attachments(message);
54
+ if (message.reference?.messageId && (!message.reference.channelId || message.reference.channelId === message.channelId)) {
55
+ inbound.replyToMessageId = message.reference.messageId;
56
+ let timer: ReturnType<typeof setTimeout> | undefined;
57
+ try {
58
+ const replied = await Promise.race([message.fetchReference?.(), new Promise<undefined>(resolve=>{timer=setTimeout(()=>resolve(undefined),3000);})]);
59
+ if (replied && replied.channelId === message.channelId) { inbound.repliedText=replied.content; inbound.repliedSender=replied.author.username; inbound.attachments.push(...attachments(replied,true)); }
60
+ } catch { /* ID still resolves from scoped local history when available. */ } finally { if(timer)clearTimeout(timer); }
61
+ }
51
62
  await handler(inbound);
52
63
  };
53
64
  }
@@ -190,6 +190,10 @@ export class DiscordModule implements ChannelModule {
190
190
  const { createDiscordClient } = await import('./client');
191
191
  this.client = await createDiscordClient(token);
192
192
  this.running = true;
193
+ if(process.env.CLAUDE_CHANNEL_CALLBACK){
194
+ const {registerCommands}=await import('./commands');
195
+ await registerCommands(this.client,token,process.env.GATEWAY_ORCHESTRATION_ENABLED==='true',process.env.GATEWAY_INTERACTIVE_CLI_ENABLED==='true').catch(err=>process.stderr.write(`discord: command registration failed: ${err}\n`));
196
+ }
193
197
  }
194
198
 
195
199
  async start(handler: InboundMessageHandler, signal: AbortSignal): Promise<void> {
@@ -296,7 +300,12 @@ export class DiscordModule implements ChannelModule {
296
300
  // button) instead of forwarding the text to the agent. Only reached after
297
301
  // gate() authorized this user, so it inherits the channel's access control.
298
302
  const cliText = (msg.content ?? '').replace(/<@!?\d+>/g, '').trim().toLowerCase();
303
+ if(/^\/(voice|voices|tasks|stop|help|orch)(?:\s|$)/.test(cliText)){
304
+ await handler({channel:'discord',accountId:this.client.user?.id??'discord',senderId:context.userId,chatId:context.channelId,chatType:isDM?'direct':'group',text:(msg.content??'').replace(/<@!?\d+>/g,'').trim(),messageId:msg.id,ts:Date.now()});
305
+ return;
306
+ }
299
307
  if (cliText === '/cli') {
308
+ if(process.env.GATEWAY_INTERACTIVE_CLI_ENABLED!=='true'){await msg.channel.send('The terminal viewer requires interactive mode.');return;}
300
309
  const base = cliCallbackBase();
301
310
  try {
302
311
  const res = await fetch(base + '/command', {
@@ -336,7 +345,7 @@ export class DiscordModule implements ChannelModule {
336
345
  const typingFileDir = path.join(this.stateDir, 'typing');
337
346
  try {
338
347
  fs.mkdirSync(typingFileDir, { recursive: true });
339
- fs.writeFileSync(path.join(typingFileDir, channelId), '');
348
+ if (process.env.GATEWAY_ORCHESTRATION_ENABLED !== 'true') fs.writeFileSync(path.join(typingFileDir, channelId), '');
340
349
  await fetch(`https://discord.com/api/v10/channels/${channelId}/typing`, {
341
350
  method: 'POST',
342
351
  headers: { Authorization: `Bot ${this.getToken()!}`, 'Content-Length': '0' },
@@ -388,7 +397,14 @@ export class DiscordModule implements ChannelModule {
388
397
  // Security mirrors the message path: the access gate must return 'deliver'.
389
398
  // discord.js client is typed as `any` (dynamic import) so we narrow locally.
390
399
  interface ButtonInteraction {
400
+ id?: string;
391
401
  isButton?: () => boolean;
402
+ isChatInputCommand?: () => boolean;
403
+ commandName?: string;
404
+ options?: {getString(name:string):string|null};
405
+ deferUpdate?: () => Promise<unknown>;
406
+ deferReply?: (options: {ephemeral:boolean}) => Promise<unknown>;
407
+ deleteReply?: () => Promise<unknown>;
392
408
  customId?: string;
393
409
  guildId?: string | null;
394
410
  channelId: string;
@@ -401,6 +417,28 @@ export class DiscordModule implements ChannelModule {
401
417
  }
402
418
  this.client.on('interactionCreate', async (interaction: ButtonInteraction) => {
403
419
  try {
420
+ const orchButton=interaction.isButton?.()&&/^orch:(?:[a-f0-9-]{36}|q:[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}:(?:snooze|mute))$/.test(interaction.customId??'');
421
+ const slash=interaction.isChatInputCommand?.();
422
+ if(orchButton||slash){
423
+ const isDM=!interaction.guildId,isThread=interaction.channel?.isThread?.()??false;
424
+ const context:DiscordMessageContext={guildId:interaction.guildId??null,channelId:interaction.channelId,threadId:isThread?interaction.channelId:null,userId:interaction.user.id,username:interaction.user.username,messageId:interaction.message?.id??'',isDM,isThread,mentionsBot:true};
425
+ const access=gate(loadAccessFn(),context,saveAccessFn,()=>randomBytes(3).toString('hex'));
426
+ if(access.action!=='deliver'){await interaction.reply({content:'Not authorized.',ephemeral:true});return;}
427
+ if(orchButton)await interaction.deferUpdate?.();else await interaction.deferReply?.({ephemeral:true});
428
+ let text=orchButton?`/orch ${interaction.customId!.slice(5)}`:`/${interaction.commandName}`;
429
+ if(slash){
430
+ const name=interaction.commandName;
431
+ const arg=interaction.options?.getString(name==='voice'?'mode':name==='ask'?'question':'name');
432
+ if(name==='ask')text=arg??'';else if(arg)text+=' '+arg;
433
+ if(name==='cli'){
434
+ const channel=await this.client.channels.fetch(interaction.channelId);
435
+ await handleDiscordMessage({id:randomBytes(12).toString('hex'),content:'/cli',author:{id:interaction.user.id,username:interaction.user.username,bot:false},guild:interaction.guildId?{id:interaction.guildId}:null,guildId:interaction.guildId,channelId:interaction.channelId,channel,mentions:{has:()=>true}} as any);
436
+ await interaction.deleteReply?.();return;
437
+ }
438
+ }
439
+ await handler({channel:'discord',accountId:interaction.client.user?.id??'discord',senderId:interaction.user.id,chatId:interaction.channelId,chatType:isDM?'direct':'group',text,messageId:interaction.id??randomBytes(12).toString('hex'),controlMessageId:orchButton?interaction.message?.id:undefined,ts:Date.now()});
440
+ if(slash)await interaction.deleteReply?.();return;
441
+ }
404
442
  if (!interaction.isButton?.()) return;
405
443
 
406
444
  // `/cli` approve/deny — unlock (or reject) a pending terminal-viewer
@@ -518,7 +556,7 @@ export class DiscordModule implements ChannelModule {
518
556
  const typingFileDir = path.join(this.stateDir, 'typing');
519
557
  try {
520
558
  fs.mkdirSync(typingFileDir, { recursive: true });
521
- fs.writeFileSync(path.join(typingFileDir, channelId), '');
559
+ if (process.env.GATEWAY_ORCHESTRATION_ENABLED !== 'true') fs.writeFileSync(path.join(typingFileDir, channelId), '');
522
560
  } catch {}
523
561
 
524
562
  const inbound: InboundMessage = {
@@ -621,6 +659,8 @@ export class DiscordModule implements ChannelModule {
621
659
  }
622
660
 
623
661
  private async processTypingSignals(typingDir: string, token: string): Promise<void> {
662
+ // Managed activity is derived from durable Agent/Worker state; stale legacy files are not work.
663
+ if (process.env.GATEWAY_ORCHESTRATION_ENABLED === 'true') return;
624
664
  let files: string[];
625
665
  try { files = fs.readdirSync(typingDir); } catch { return; }
626
666
 
@@ -7,8 +7,10 @@
7
7
 
8
8
  import { DiscordModule } from './module';
9
9
  import type { InboundMessage } from '../../types';
10
+ import { ReceiverSpool } from '../receiver-spool';
10
11
 
11
12
  const CALLBACK_URL = process.env.CLAUDE_CHANNEL_CALLBACK;
13
+ const spool = process.env.GATEWAY_ORCHESTRATION_INGRESS_DIR && CALLBACK_URL ? new ReceiverSpool(process.env.GATEWAY_ORCHESTRATION_INGRESS_DIR, CALLBACK_URL) : undefined;
12
14
  if (!CALLBACK_URL) {
13
15
  process.stderr.write('discord receiver: CLAUDE_CHANNEL_CALLBACK required\n');
14
16
  process.exit(1);
@@ -30,6 +32,14 @@ async function postCallback(inbound: InboundMessage): Promise<void> {
30
32
  if (inbound.attachmentFileId) {
31
33
  meta['attachment_file_id'] = inbound.attachmentFileId;
32
34
  }
35
+ if(inbound.attachments?.length)meta.attachments_json=JSON.stringify(inbound.attachments.map(a=>({ref:a.url,name:a.name,kind:a.kind,quoted:a.quoted})));
36
+ if(inbound.replyToMessageId)meta.replied_message_id=inbound.replyToMessageId;
37
+ if(inbound.repliedText)meta.replied_text=inbound.repliedText;
38
+ if(inbound.repliedSender)meta.replied_user=inbound.repliedSender;
39
+ if(inbound.threadId)meta.thread_ts=inbound.threadId;
40
+ if(inbound.attachmentKind)meta.attachment_kind=inbound.attachmentKind;
41
+ if(inbound.controlMessageId)meta.control_message_id=inbound.controlMessageId;
42
+ if (spool && !/^\/(voice|voices|tasks|stop|orch)(?:\s|$)/.test(inbound.text??'')) { spool.enqueue({ content: inbound.text ?? '', meta }); return; }
33
43
 
34
44
  try {
35
45
  await fetch(CALLBACK_URL!, {
@@ -108,7 +108,10 @@ export interface DiscordMessage {
108
108
  parentId?: string | null;
109
109
  };
110
110
  createdTimestamp: number;
111
- attachments: { first(): { url: string } | undefined };
111
+ reference?: {messageId?:string;channelId?:string};
112
+ fetchReference?(): Promise<DiscordMessage>;
113
+ flags?: number | {has(bit:number):boolean};
114
+ attachments: { first(): { url: string; contentType?: string | null; name?: string } | undefined; values?(): IterableIterator<{url:string;contentType?:string|null;name?:string}> };
112
115
  client: { user: { id: string } | null };
113
116
  startThread(options: { name: string; autoArchiveDuration: number }): Promise<{ id: string }>;
114
117
  }
@@ -735,7 +735,9 @@ export class ImageModule implements ToolModule {
735
735
  files,
736
736
  ...(artifacts ? { artifacts } : {}),
737
737
  ...(droppedImages > 0 ? { dropped_images: droppedImages } : {}),
738
- note: 'Image saved. Deliver it to the user with your channel delivery tool — api_reply/reply (files: [...]), or line_image on LINE. Do NOT open/Read the file to inspect it first; attach it and answer briefly.'
738
+ note: (process.env.GATEWAY_ORCHESTRATION_ROLE === 'worker'
739
+ ? 'Image saved. Call task_stage_file for each output path, then finish this task. The agent orchestration engine owns user-facing delivery.'
740
+ : 'Image saved. Deliver it to the user with your channel delivery tool — api_reply/reply (files: [...]), or line_image on LINE. Do NOT open/Read the file to inspect it first; attach it and answer briefly.')
739
741
  + (model ? ` Mention which model made it (${model}).` : '')
740
742
  + (artifacts ? ' To edit this image later, reference it via its artifact_ref (e.g. image: "artifact:...").' : '')
741
743
  + (droppedImages > 0 ? ` (${droppedImages} extra image(s) beyond the cap were not saved)` : ''),
@@ -0,0 +1,28 @@
1
+ import { test, expect } from 'bun:test';
2
+ import { mkdtempSync, readdirSync, rmSync, readFileSync } from 'node:fs';
3
+ import { tmpdir } from 'node:os';
4
+ import { join } from 'node:path';
5
+ import { ReceiverSpool } from './receiver-spool';
6
+
7
+ test('receiver restart retains unacknowledged input and removes it only after gateway acceptance', async () => {
8
+ const root = mkdtempSync(join(tmpdir(), 'receiver-spool-'));
9
+ let fail = true;
10
+ const delivered: unknown[] = [];
11
+ const request = (async (_url: string | URL | Request, options?: RequestInit) => {
12
+ delivered.push(JSON.parse(String(options?.body)));
13
+ return new Response('', { status: fail ? 503 : 200 });
14
+ }) as typeof fetch;
15
+ let spool = new ReceiverSpool(root, 'http://fixture.invalid/channel', request);
16
+ try {
17
+ const input = { content: 'hello', meta: { chat_id: 'original', message_id: '1' } };
18
+ spool.enqueue(input);
19
+ await new Promise(resolve => setTimeout(resolve, 10));
20
+ const file = readdirSync(root).find(file => file.endsWith('.json'))!;
21
+ expect(JSON.parse(readFileSync(join(root, file), 'utf8'))).toEqual(input);
22
+ spool.close(); fail = false;
23
+ spool = new ReceiverSpool(root, 'http://fixture.invalid/channel', request);
24
+ await new Promise(resolve => setTimeout(resolve, 10));
25
+ expect(readdirSync(root)).toEqual([]);
26
+ expect(delivered.at(-1)).toEqual(input);
27
+ } finally { spool.close(); rmSync(root, { recursive: true, force: true }); }
28
+ });