@theowlops/boombot 0.0.0-stage → 1.1.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 (544) hide show
  1. package/README.md +69 -3
  2. package/dist/LICENSE +21 -0
  3. package/dist/bin/boombot.js +16 -0
  4. package/dist/cli/api-key.js +123 -0
  5. package/dist/cli/bin-bun.js +17 -0
  6. package/dist/cli/bin.js +34 -0
  7. package/dist/cli/cli/cli-error.js +61 -0
  8. package/dist/cli/cli/dispatch.js +138 -0
  9. package/dist/cli/cli/help.js +83 -0
  10. package/dist/cli/cli/parser.js +89 -0
  11. package/dist/cli/cli/registry.js +185 -0
  12. package/dist/cli/cli/spec.js +41 -0
  13. package/dist/cli/cli/suggest.js +125 -0
  14. package/dist/cli/cli/version.js +30 -0
  15. package/dist/cli/cli/vocabulary.js +87 -0
  16. package/dist/cli/commands/doctor.js +365 -0
  17. package/dist/cli/commands/gateway.js +290 -0
  18. package/dist/cli/commands/migrate.js +270 -0
  19. package/dist/cli/commands/plugin.js +97 -0
  20. package/dist/cli/commands/setup.js +244 -0
  21. package/dist/cli/config-file.js +133 -0
  22. package/dist/cli/master-key.js +78 -0
  23. package/dist/cli/open-browser.js +59 -0
  24. package/dist/cli/web-assets.js +58 -0
  25. package/dist/gateway/auth.js +46 -0
  26. package/dist/gateway/config-format.js +202 -0
  27. package/dist/gateway/config.js +427 -0
  28. package/dist/gateway/context.js +1 -0
  29. package/dist/gateway/env-file.js +129 -0
  30. package/dist/gateway/events.js +172 -0
  31. package/dist/gateway/guard/tagging.js +505 -0
  32. package/dist/gateway/handlers/index.js +66 -0
  33. package/dist/gateway/handlers/memory.js +54 -0
  34. package/dist/gateway/handlers/providers.js +73 -0
  35. package/dist/gateway/handlers/registry.js +39 -0
  36. package/dist/gateway/handlers/sessions.js +188 -0
  37. package/dist/gateway/handlers/system.js +12 -0
  38. package/dist/gateway/handlers/tasks.js +191 -0
  39. package/dist/gateway/handlers/turn.js +100 -0
  40. package/dist/gateway/index.js +126 -0
  41. package/dist/gateway/main.js +23 -0
  42. package/dist/gateway/server.js +354 -0
  43. package/dist/gateway/services/context-limits.js +75 -0
  44. package/dist/gateway/services/history-normalizer.js +42 -0
  45. package/dist/gateway/services/image-pipeline.js +56 -0
  46. package/dist/gateway/services/key-roulette-client.js +43 -0
  47. package/dist/gateway/services/llm-client.js +593 -0
  48. package/dist/gateway/services/llm-decoder.js +200 -0
  49. package/dist/gateway/services/local-fallback.js +135 -0
  50. package/dist/gateway/services/memory.js +511 -0
  51. package/dist/gateway/services/persistent-memory.js +196 -0
  52. package/dist/gateway/services/providers.js +44 -0
  53. package/dist/gateway/services/tasks.js +237 -0
  54. package/dist/gateway/services/verification.js +124 -0
  55. package/dist/gateway/services/vision-payload.js +48 -0
  56. package/dist/gateway/services.js +257 -0
  57. package/dist/gateway/session-snapshot.js +19 -0
  58. package/dist/gateway/sessions.js +701 -0
  59. package/dist/gateway/static.js +239 -0
  60. package/dist/gateway/turns/clarify-tool.js +57 -0
  61. package/dist/gateway/turns/cronjob-tool.js +96 -0
  62. package/dist/gateway/turns/deferred-tools.js +154 -0
  63. package/dist/gateway/turns/execute-code-tool.js +84 -0
  64. package/dist/gateway/turns/file-tool-defs.js +178 -0
  65. package/dist/gateway/turns/file-tool-ops.js +178 -0
  66. package/dist/gateway/turns/file-tool-scan.js +182 -0
  67. package/dist/gateway/turns/file-tool.js +302 -0
  68. package/dist/gateway/turns/index.js +416 -0
  69. package/dist/gateway/turns/jev-middleware.js +91 -0
  70. package/dist/gateway/turns/local-reply.js +156 -0
  71. package/dist/gateway/turns/mcp-client.js +643 -0
  72. package/dist/gateway/turns/memory-tool.js +171 -0
  73. package/dist/gateway/turns/middleware.js +96 -0
  74. package/dist/gateway/turns/python-core.js +397 -0
  75. package/dist/gateway/turns/routing/index.js +3 -0
  76. package/dist/gateway/turns/routing/intent-classifier.js +60 -0
  77. package/dist/gateway/turns/routing/planner-adapter.js +91 -0
  78. package/dist/gateway/turns/routing/types.js +1 -0
  79. package/dist/gateway/turns/runtime-deps.js +228 -0
  80. package/dist/gateway/turns/self-config-tool.js +277 -0
  81. package/dist/gateway/turns/service-types.js +11 -0
  82. package/dist/gateway/turns/service.js +820 -0
  83. package/dist/gateway/turns/session-adapter.js +158 -0
  84. package/dist/gateway/turns/session-tool.js +49 -0
  85. package/dist/gateway/turns/shell-tool.js +190 -0
  86. package/dist/gateway/turns/skill-tool.js +239 -0
  87. package/dist/gateway/turns/spillover.js +201 -0
  88. package/dist/gateway/turns/subagent-tool.js +140 -0
  89. package/dist/gateway/turns/system-prompt.js +121 -0
  90. package/dist/gateway/turns/tool-schema.js +90 -0
  91. package/dist/gateway/turns/turn-utils.js +58 -0
  92. package/dist/gateway/turns/vision-tool.js +120 -0
  93. package/dist/gateway/types.js +1 -0
  94. package/dist/native/win32-x64/boombot-native-host.exe +0 -0
  95. package/dist/node_modules/@boombot/channels/handlers.d.ts +9 -0
  96. package/dist/node_modules/@boombot/channels/handlers.js +109 -0
  97. package/dist/node_modules/@boombot/channels/index.d.ts +12 -0
  98. package/dist/node_modules/@boombot/channels/index.js +12 -0
  99. package/dist/node_modules/@boombot/channels/package.json +9 -0
  100. package/dist/node_modules/@boombot/channels/service.d.ts +62 -0
  101. package/dist/node_modules/@boombot/channels/service.js +608 -0
  102. package/dist/node_modules/@boombot/channels/tool.d.ts +10 -0
  103. package/dist/node_modules/@boombot/channels/tool.js +46 -0
  104. package/dist/node_modules/@boombot/channels/transports/common/dedup.d.ts +17 -0
  105. package/dist/node_modules/@boombot/channels/transports/common/dedup.js +42 -0
  106. package/dist/node_modules/@boombot/channels/transports/common/handoff.d.ts +19 -0
  107. package/dist/node_modules/@boombot/channels/transports/common/handoff.js +32 -0
  108. package/dist/node_modules/@boombot/channels/transports/common/index.d.ts +3 -0
  109. package/dist/node_modules/@boombot/channels/transports/common/index.js +3 -0
  110. package/dist/node_modules/@boombot/channels/transports/common/types.d.ts +99 -0
  111. package/dist/node_modules/@boombot/channels/transports/common/types.js +54 -0
  112. package/dist/node_modules/@boombot/channels/transports/common.d.ts +2 -0
  113. package/dist/node_modules/@boombot/channels/transports/common.js +2 -0
  114. package/dist/node_modules/@boombot/channels/transports/dedup/index.d.ts +1 -0
  115. package/dist/node_modules/@boombot/channels/transports/dedup/index.js +1 -0
  116. package/dist/node_modules/@boombot/channels/transports/dedup.d.ts +2 -0
  117. package/dist/node_modules/@boombot/channels/transports/dedup.js +2 -0
  118. package/dist/node_modules/@boombot/channels/transports/discord/index.d.ts +1 -0
  119. package/dist/node_modules/@boombot/channels/transports/discord/index.js +1 -0
  120. package/dist/node_modules/@boombot/channels/transports/discord/transport.d.ts +36 -0
  121. package/dist/node_modules/@boombot/channels/transports/discord/transport.js +199 -0
  122. package/dist/node_modules/@boombot/channels/transports/discord.d.ts +2 -0
  123. package/dist/node_modules/@boombot/channels/transports/discord.js +2 -0
  124. package/dist/node_modules/@boombot/channels/transports/handoff.d.ts +2 -0
  125. package/dist/node_modules/@boombot/channels/transports/handoff.js +2 -0
  126. package/dist/node_modules/@boombot/channels/transports/messenger/index.d.ts +1 -0
  127. package/dist/node_modules/@boombot/channels/transports/messenger/index.js +1 -0
  128. package/dist/node_modules/@boombot/channels/transports/messenger/transport.d.ts +34 -0
  129. package/dist/node_modules/@boombot/channels/transports/messenger/transport.js +180 -0
  130. package/dist/node_modules/@boombot/channels/transports/messenger.d.ts +2 -0
  131. package/dist/node_modules/@boombot/channels/transports/messenger.js +2 -0
  132. package/dist/node_modules/@boombot/channels/transports/slack/index.d.ts +1 -0
  133. package/dist/node_modules/@boombot/channels/transports/slack/index.js +1 -0
  134. package/dist/node_modules/@boombot/channels/transports/slack/transport.d.ts +35 -0
  135. package/dist/node_modules/@boombot/channels/transports/slack/transport.js +183 -0
  136. package/dist/node_modules/@boombot/channels/transports/slack.d.ts +2 -0
  137. package/dist/node_modules/@boombot/channels/transports/slack.js +2 -0
  138. package/dist/node_modules/@boombot/channels/transports/streamer/index.d.ts +1 -0
  139. package/dist/node_modules/@boombot/channels/transports/streamer/index.js +1 -0
  140. package/dist/node_modules/@boombot/channels/transports/streamer/streamer.d.ts +31 -0
  141. package/dist/node_modules/@boombot/channels/transports/streamer/streamer.js +141 -0
  142. package/dist/node_modules/@boombot/channels/transports/streamer.d.ts +2 -0
  143. package/dist/node_modules/@boombot/channels/transports/streamer.js +2 -0
  144. package/dist/node_modules/@boombot/channels/transports/telegram/index.d.ts +1 -0
  145. package/dist/node_modules/@boombot/channels/transports/telegram/index.js +1 -0
  146. package/dist/node_modules/@boombot/channels/transports/telegram/transport.d.ts +75 -0
  147. package/dist/node_modules/@boombot/channels/transports/telegram/transport.js +395 -0
  148. package/dist/node_modules/@boombot/channels/transports/telegram.d.ts +2 -0
  149. package/dist/node_modules/@boombot/channels/transports/telegram.js +2 -0
  150. package/dist/node_modules/@boombot/channels/transports/tiktok/index.d.ts +1 -0
  151. package/dist/node_modules/@boombot/channels/transports/tiktok/index.js +1 -0
  152. package/dist/node_modules/@boombot/channels/transports/tiktok/transport.d.ts +27 -0
  153. package/dist/node_modules/@boombot/channels/transports/tiktok/transport.js +97 -0
  154. package/dist/node_modules/@boombot/channels/transports/tiktok.d.ts +2 -0
  155. package/dist/node_modules/@boombot/channels/transports/tiktok.js +2 -0
  156. package/dist/node_modules/@boombot/channels/transports/whatsapp/index.d.ts +1 -0
  157. package/dist/node_modules/@boombot/channels/transports/whatsapp/index.js +1 -0
  158. package/dist/node_modules/@boombot/channels/transports/whatsapp/transport.d.ts +38 -0
  159. package/dist/node_modules/@boombot/channels/transports/whatsapp/transport.js +189 -0
  160. package/dist/node_modules/@boombot/channels/transports/whatsapp.d.ts +2 -0
  161. package/dist/node_modules/@boombot/channels/transports/whatsapp.js +2 -0
  162. package/dist/node_modules/@boombot/channels/transports/zalo/index.d.ts +2 -0
  163. package/dist/node_modules/@boombot/channels/transports/zalo/index.js +2 -0
  164. package/dist/node_modules/@boombot/channels/transports/zalo/oa.d.ts +28 -0
  165. package/dist/node_modules/@boombot/channels/transports/zalo/oa.js +94 -0
  166. package/dist/node_modules/@boombot/channels/transports/zalo/personal.d.ts +106 -0
  167. package/dist/node_modules/@boombot/channels/transports/zalo/personal.js +171 -0
  168. package/dist/node_modules/@boombot/channels/transports/zalo-personal.d.ts +2 -0
  169. package/dist/node_modules/@boombot/channels/transports/zalo-personal.js +2 -0
  170. package/dist/node_modules/@boombot/channels/transports/zalo.d.ts +2 -0
  171. package/dist/node_modules/@boombot/channels/transports/zalo.js +2 -0
  172. package/dist/node_modules/@boombot/core/agent-core/index.d.ts +12 -0
  173. package/dist/node_modules/@boombot/core/agent-core/index.js +12 -0
  174. package/dist/node_modules/@boombot/core/agent-core/middleware.d.ts +60 -0
  175. package/dist/node_modules/@boombot/core/agent-core/middleware.js +152 -0
  176. package/dist/node_modules/@boombot/core/agent-core/routing.d.ts +128 -0
  177. package/dist/node_modules/@boombot/core/agent-core/routing.js +437 -0
  178. package/dist/node_modules/@boombot/core/agent-core/runtime-deps.d.ts +88 -0
  179. package/dist/node_modules/@boombot/core/agent-core/runtime-deps.js +8 -0
  180. package/dist/node_modules/@boombot/core/agent-core/tool-errors.d.ts +44 -0
  181. package/dist/node_modules/@boombot/core/agent-core/tool-errors.js +60 -0
  182. package/dist/node_modules/@boombot/core/agent-core/turn-loop.d.ts +21 -0
  183. package/dist/node_modules/@boombot/core/agent-core/turn-loop.js +561 -0
  184. package/dist/node_modules/@boombot/core/agent-core/types.d.ts +189 -0
  185. package/dist/node_modules/@boombot/core/agent-core/types.js +7 -0
  186. package/dist/node_modules/@boombot/core/compaction/compactor.d.ts +19 -0
  187. package/dist/node_modules/@boombot/core/compaction/compactor.js +127 -0
  188. package/dist/node_modules/@boombot/core/compaction/estimator.d.ts +10 -0
  189. package/dist/node_modules/@boombot/core/compaction/estimator.js +48 -0
  190. package/dist/node_modules/@boombot/core/compaction/index.d.ts +3 -0
  191. package/dist/node_modules/@boombot/core/compaction/index.js +3 -0
  192. package/dist/node_modules/@boombot/core/compaction/types.d.ts +31 -0
  193. package/dist/node_modules/@boombot/core/compaction/types.js +7 -0
  194. package/dist/node_modules/@boombot/core/index.d.ts +9 -0
  195. package/dist/node_modules/@boombot/core/index.js +9 -0
  196. package/dist/node_modules/@boombot/core/jev/index.d.ts +2 -0
  197. package/dist/node_modules/@boombot/core/jev/index.js +2 -0
  198. package/dist/node_modules/@boombot/core/jev/jev.d.ts +30 -0
  199. package/dist/node_modules/@boombot/core/jev/jev.js +164 -0
  200. package/dist/node_modules/@boombot/core/jev/types.d.ts +22 -0
  201. package/dist/node_modules/@boombot/core/jev/types.js +1 -0
  202. package/dist/node_modules/@boombot/core/memory/consolidation/budget.d.ts +63 -0
  203. package/dist/node_modules/@boombot/core/memory/consolidation/budget.js +94 -0
  204. package/dist/node_modules/@boombot/core/memory/consolidation/consolidator.d.ts +152 -0
  205. package/dist/node_modules/@boombot/core/memory/consolidation/consolidator.js +318 -0
  206. package/dist/node_modules/@boombot/core/memory/consolidation/index.d.ts +12 -0
  207. package/dist/node_modules/@boombot/core/memory/consolidation/index.js +12 -0
  208. package/dist/node_modules/@boombot/core/memory/curation.d.ts +86 -0
  209. package/dist/node_modules/@boombot/core/memory/curation.js +120 -0
  210. package/dist/node_modules/@boombot/core/memory/errors.d.ts +12 -0
  211. package/dist/node_modules/@boombot/core/memory/errors.js +20 -0
  212. package/dist/node_modules/@boombot/core/memory/hybrid-search.d.ts +29 -0
  213. package/dist/node_modules/@boombot/core/memory/hybrid-search.js +52 -0
  214. package/dist/node_modules/@boombot/core/memory/index.d.ts +23 -0
  215. package/dist/node_modules/@boombot/core/memory/index.js +23 -0
  216. package/dist/node_modules/@boombot/core/memory/indexer.d.ts +47 -0
  217. package/dist/node_modules/@boombot/core/memory/indexer.js +138 -0
  218. package/dist/node_modules/@boombot/core/memory/lifecycle.d.ts +12 -0
  219. package/dist/node_modules/@boombot/core/memory/lifecycle.js +66 -0
  220. package/dist/node_modules/@boombot/core/memory/provider.d.ts +84 -0
  221. package/dist/node_modules/@boombot/core/memory/provider.js +117 -0
  222. package/dist/node_modules/@boombot/core/memory/recall.d.ts +7 -0
  223. package/dist/node_modules/@boombot/core/memory/recall.js +111 -0
  224. package/dist/node_modules/@boombot/core/memory/scope-resolver.d.ts +27 -0
  225. package/dist/node_modules/@boombot/core/memory/scope-resolver.js +60 -0
  226. package/dist/node_modules/@boombot/core/memory/search.d.ts +37 -0
  227. package/dist/node_modules/@boombot/core/memory/search.js +158 -0
  228. package/dist/node_modules/@boombot/core/memory/store.d.ts +60 -0
  229. package/dist/node_modules/@boombot/core/memory/store.js +289 -0
  230. package/dist/node_modules/@boombot/core/memory/types.d.ts +121 -0
  231. package/dist/node_modules/@boombot/core/memory/types.js +21 -0
  232. package/dist/node_modules/@boombot/core/memory/vector-index.d.ts +34 -0
  233. package/dist/node_modules/@boombot/core/memory/vector-index.js +65 -0
  234. package/dist/node_modules/@boombot/core/package.json +9 -0
  235. package/dist/node_modules/@boombot/core/reflection/classifier.d.ts +13 -0
  236. package/dist/node_modules/@boombot/core/reflection/classifier.js +77 -0
  237. package/dist/node_modules/@boombot/core/reflection/index.d.ts +2 -0
  238. package/dist/node_modules/@boombot/core/reflection/index.js +2 -0
  239. package/dist/node_modules/@boombot/core/reflection/types.d.ts +13 -0
  240. package/dist/node_modules/@boombot/core/reflection/types.js +4 -0
  241. package/dist/node_modules/@boombot/core/research/config.d.ts +89 -0
  242. package/dist/node_modules/@boombot/core/research/config.js +206 -0
  243. package/dist/node_modules/@boombot/core/research/crawl.d.ts +36 -0
  244. package/dist/node_modules/@boombot/core/research/crawl.js +179 -0
  245. package/dist/node_modules/@boombot/core/research/factory.d.ts +26 -0
  246. package/dist/node_modules/@boombot/core/research/factory.js +46 -0
  247. package/dist/node_modules/@boombot/core/research/http.d.ts +87 -0
  248. package/dist/node_modules/@boombot/core/research/http.js +250 -0
  249. package/dist/node_modules/@boombot/core/research/index.d.ts +17 -0
  250. package/dist/node_modules/@boombot/core/research/index.js +10 -0
  251. package/dist/node_modules/@boombot/core/research/orchestrator.d.ts +113 -0
  252. package/dist/node_modules/@boombot/core/research/orchestrator.js +252 -0
  253. package/dist/node_modules/@boombot/core/research/parse/docx.d.ts +24 -0
  254. package/dist/node_modules/@boombot/core/research/parse/docx.js +183 -0
  255. package/dist/node_modules/@boombot/core/research/parse/guards.d.ts +89 -0
  256. package/dist/node_modules/@boombot/core/research/parse/guards.js +171 -0
  257. package/dist/node_modules/@boombot/core/research/parse/index.d.ts +68 -0
  258. package/dist/node_modules/@boombot/core/research/parse/index.js +219 -0
  259. package/dist/node_modules/@boombot/core/research/parse/pdf.d.ts +38 -0
  260. package/dist/node_modules/@boombot/core/research/parse/pdf.js +567 -0
  261. package/dist/node_modules/@boombot/core/research/providers/arxiv.d.ts +9 -0
  262. package/dist/node_modules/@boombot/core/research/providers/arxiv.js +72 -0
  263. package/dist/node_modules/@boombot/core/research/providers/brave.d.ts +11 -0
  264. package/dist/node_modules/@boombot/core/research/providers/brave.js +36 -0
  265. package/dist/node_modules/@boombot/core/research/providers/duckduckgo.d.ts +9 -0
  266. package/dist/node_modules/@boombot/core/research/providers/duckduckgo.js +78 -0
  267. package/dist/node_modules/@boombot/core/research/providers/exa.d.ts +11 -0
  268. package/dist/node_modules/@boombot/core/research/providers/exa.js +34 -0
  269. package/dist/node_modules/@boombot/core/research/providers/firecrawl.d.ts +16 -0
  270. package/dist/node_modules/@boombot/core/research/providers/firecrawl.js +47 -0
  271. package/dist/node_modules/@boombot/core/research/providers/index.d.ts +17 -0
  272. package/dist/node_modules/@boombot/core/research/providers/index.js +11 -0
  273. package/dist/node_modules/@boombot/core/research/providers/jina.d.ts +13 -0
  274. package/dist/node_modules/@boombot/core/research/providers/jina.js +114 -0
  275. package/dist/node_modules/@boombot/core/research/providers/openalex.d.ts +14 -0
  276. package/dist/node_modules/@boombot/core/research/providers/openalex.js +66 -0
  277. package/dist/node_modules/@boombot/core/research/providers/semantic-scholar.d.ts +9 -0
  278. package/dist/node_modules/@boombot/core/research/providers/semantic-scholar.js +56 -0
  279. package/dist/node_modules/@boombot/core/research/providers/tavily.d.ts +11 -0
  280. package/dist/node_modules/@boombot/core/research/providers/tavily.js +35 -0
  281. package/dist/node_modules/@boombot/core/research/providers/wikipedia.d.ts +12 -0
  282. package/dist/node_modules/@boombot/core/research/providers/wikipedia.js +47 -0
  283. package/dist/node_modules/@boombot/core/research/tools.d.ts +27 -0
  284. package/dist/node_modules/@boombot/core/research/tools.js +251 -0
  285. package/dist/node_modules/@boombot/core/research/types.d.ts +133 -0
  286. package/dist/node_modules/@boombot/core/research/types.js +8 -0
  287. package/dist/node_modules/@boombot/core/research/wiring.d.ts +25 -0
  288. package/dist/node_modules/@boombot/core/research/wiring.js +51 -0
  289. package/dist/node_modules/@boombot/core/scheduler/cron.d.ts +34 -0
  290. package/dist/node_modules/@boombot/core/scheduler/cron.js +147 -0
  291. package/dist/node_modules/@boombot/core/scheduler/evaluator.d.ts +42 -0
  292. package/dist/node_modules/@boombot/core/scheduler/evaluator.js +148 -0
  293. package/dist/node_modules/@boombot/core/scheduler/index.d.ts +15 -0
  294. package/dist/node_modules/@boombot/core/scheduler/index.js +15 -0
  295. package/dist/node_modules/@boombot/core/scheduler/registry.d.ts +81 -0
  296. package/dist/node_modules/@boombot/core/scheduler/registry.js +263 -0
  297. package/dist/node_modules/@boombot/core/scheduler/runner.d.ts +59 -0
  298. package/dist/node_modules/@boombot/core/scheduler/runner.js +257 -0
  299. package/dist/node_modules/@boombot/core/scheduler/store.d.ts +150 -0
  300. package/dist/node_modules/@boombot/core/scheduler/store.js +526 -0
  301. package/dist/node_modules/@boombot/core/scheduler/timezone.d.ts +35 -0
  302. package/dist/node_modules/@boombot/core/scheduler/timezone.js +96 -0
  303. package/dist/node_modules/@boombot/core/scheduler/types.d.ts +157 -0
  304. package/dist/node_modules/@boombot/core/scheduler/types.js +89 -0
  305. package/dist/node_modules/@boombot/core/task-runner/index.d.ts +7 -0
  306. package/dist/node_modules/@boombot/core/task-runner/index.js +5 -0
  307. package/dist/node_modules/@boombot/core/task-runner/planner.d.ts +37 -0
  308. package/dist/node_modules/@boombot/core/task-runner/planner.js +154 -0
  309. package/dist/node_modules/@boombot/core/task-runner/runner.d.ts +8 -0
  310. package/dist/node_modules/@boombot/core/task-runner/runner.js +564 -0
  311. package/dist/node_modules/@boombot/core/task-runner/store.d.ts +28 -0
  312. package/dist/node_modules/@boombot/core/task-runner/store.js +126 -0
  313. package/dist/node_modules/@boombot/core/task-runner/types.d.ts +138 -0
  314. package/dist/node_modules/@boombot/core/task-runner/types.js +11 -0
  315. package/dist/node_modules/@boombot/core/workflow/dag.d.ts +16 -0
  316. package/dist/node_modules/@boombot/core/workflow/dag.js +109 -0
  317. package/dist/node_modules/@boombot/core/workflow/engine.d.ts +34 -0
  318. package/dist/node_modules/@boombot/core/workflow/engine.js +304 -0
  319. package/dist/node_modules/@boombot/core/workflow/index.d.ts +3 -0
  320. package/dist/node_modules/@boombot/core/workflow/index.js +3 -0
  321. package/dist/node_modules/@boombot/core/workflow/types.d.ts +98 -0
  322. package/dist/node_modules/@boombot/core/workflow/types.js +21 -0
  323. package/dist/node_modules/@boombot/cronjobs/handlers.d.ts +11 -0
  324. package/dist/node_modules/@boombot/cronjobs/handlers.js +174 -0
  325. package/dist/node_modules/@boombot/cronjobs/index.d.ts +2 -0
  326. package/dist/node_modules/@boombot/cronjobs/index.js +2 -0
  327. package/dist/node_modules/@boombot/cronjobs/package.json +9 -0
  328. package/dist/node_modules/@boombot/cronjobs/service.d.ts +53 -0
  329. package/dist/node_modules/@boombot/cronjobs/service.js +200 -0
  330. package/dist/node_modules/@boombot/plugins/index.d.ts +2 -0
  331. package/dist/node_modules/@boombot/plugins/index.js +2 -0
  332. package/dist/node_modules/@boombot/plugins/installer.d.ts +45 -0
  333. package/dist/node_modules/@boombot/plugins/installer.js +487 -0
  334. package/dist/node_modules/@boombot/plugins/manager.d.ts +23 -0
  335. package/dist/node_modules/@boombot/plugins/manager.js +243 -0
  336. package/dist/node_modules/@boombot/plugins/package.json +9 -0
  337. package/dist/node_modules/@boombot/protocol/gateway-protocol/commands-channels.d.ts +125 -0
  338. package/dist/node_modules/@boombot/protocol/gateway-protocol/commands-channels.js +76 -0
  339. package/dist/node_modules/@boombot/protocol/gateway-protocol/commands-plugins.d.ts +220 -0
  340. package/dist/node_modules/@boombot/protocol/gateway-protocol/commands-plugins.js +60 -0
  341. package/dist/node_modules/@boombot/protocol/gateway-protocol/commands-scheduler.d.ts +33 -0
  342. package/dist/node_modules/@boombot/protocol/gateway-protocol/commands-scheduler.js +25 -0
  343. package/dist/node_modules/@boombot/protocol/gateway-protocol/commands.d.ts +4349 -0
  344. package/dist/node_modules/@boombot/protocol/gateway-protocol/commands.js +563 -0
  345. package/dist/node_modules/@boombot/protocol/gateway-protocol/envelope.d.ts +32 -0
  346. package/dist/node_modules/@boombot/protocol/gateway-protocol/envelope.js +61 -0
  347. package/dist/node_modules/@boombot/protocol/gateway-protocol/errors.d.ts +13 -0
  348. package/dist/node_modules/@boombot/protocol/gateway-protocol/errors.js +16 -0
  349. package/dist/node_modules/@boombot/protocol/gateway-protocol/events.d.ts +567 -0
  350. package/dist/node_modules/@boombot/protocol/gateway-protocol/events.js +395 -0
  351. package/dist/node_modules/@boombot/protocol/gateway-protocol/index.d.ts +20 -0
  352. package/dist/node_modules/@boombot/protocol/gateway-protocol/index.js +13 -0
  353. package/dist/node_modules/@boombot/protocol/gateway-protocol/types.d.ts +91 -0
  354. package/dist/node_modules/@boombot/protocol/gateway-protocol/types.js +7 -0
  355. package/dist/node_modules/@boombot/protocol/index.d.ts +4 -0
  356. package/dist/node_modules/@boombot/protocol/index.js +3 -0
  357. package/dist/node_modules/@boombot/protocol/package.json +9 -0
  358. package/dist/node_modules/@boombot/protocol/plugin-sdk/channel.d.ts +41 -0
  359. package/dist/node_modules/@boombot/protocol/plugin-sdk/channel.js +17 -0
  360. package/dist/node_modules/@boombot/protocol/plugin-sdk/index.d.ts +10 -0
  361. package/dist/node_modules/@boombot/protocol/plugin-sdk/index.js +10 -0
  362. package/dist/node_modules/@boombot/protocol/plugin-sdk/manifest.d.ts +58 -0
  363. package/dist/node_modules/@boombot/protocol/plugin-sdk/manifest.js +116 -0
  364. package/dist/node_modules/@boombot/protocol/plugin-sdk/plugin.d.ts +25 -0
  365. package/dist/node_modules/@boombot/protocol/plugin-sdk/plugin.js +1 -0
  366. package/dist/node_modules/@boombot/protocol/providers/cipher.d.ts +7 -0
  367. package/dist/node_modules/@boombot/protocol/providers/cipher.js +52 -0
  368. package/dist/node_modules/@boombot/protocol/providers/index.d.ts +19 -0
  369. package/dist/node_modules/@boombot/protocol/providers/index.js +19 -0
  370. package/dist/node_modules/@boombot/protocol/providers/key-roulette.d.ts +79 -0
  371. package/dist/node_modules/@boombot/protocol/providers/key-roulette.js +81 -0
  372. package/dist/node_modules/@boombot/protocol/providers/probe.d.ts +29 -0
  373. package/dist/node_modules/@boombot/protocol/providers/probe.js +96 -0
  374. package/dist/node_modules/@boombot/protocol/providers/profiles/anthropic.d.ts +11 -0
  375. package/dist/node_modules/@boombot/protocol/providers/profiles/anthropic.js +11 -0
  376. package/dist/node_modules/@boombot/protocol/providers/profiles/custom.d.ts +22 -0
  377. package/dist/node_modules/@boombot/protocol/providers/profiles/custom.js +222 -0
  378. package/dist/node_modules/@boombot/protocol/providers/profiles/deepseek.d.ts +7 -0
  379. package/dist/node_modules/@boombot/protocol/providers/profiles/deepseek.js +9 -0
  380. package/dist/node_modules/@boombot/protocol/providers/profiles/google.d.ts +10 -0
  381. package/dist/node_modules/@boombot/protocol/providers/profiles/google.js +10 -0
  382. package/dist/node_modules/@boombot/protocol/providers/profiles/index.d.ts +31 -0
  383. package/dist/node_modules/@boombot/protocol/providers/profiles/index.js +56 -0
  384. package/dist/node_modules/@boombot/protocol/providers/profiles/local.d.ts +10 -0
  385. package/dist/node_modules/@boombot/protocol/providers/profiles/local.js +11 -0
  386. package/dist/node_modules/@boombot/protocol/providers/profiles/mistral.d.ts +7 -0
  387. package/dist/node_modules/@boombot/protocol/providers/profiles/mistral.js +9 -0
  388. package/dist/node_modules/@boombot/protocol/providers/profiles/openai-compatible.d.ts +10 -0
  389. package/dist/node_modules/@boombot/protocol/providers/profiles/openai-compatible.js +10 -0
  390. package/dist/node_modules/@boombot/protocol/providers/profiles/openai.d.ts +7 -0
  391. package/dist/node_modules/@boombot/protocol/providers/profiles/openai.js +11 -0
  392. package/dist/node_modules/@boombot/protocol/providers/profiles/types.d.ts +58 -0
  393. package/dist/node_modules/@boombot/protocol/providers/profiles/types.js +1 -0
  394. package/dist/node_modules/@boombot/protocol/providers/profiles/xai.d.ts +7 -0
  395. package/dist/node_modules/@boombot/protocol/providers/profiles/xai.js +10 -0
  396. package/dist/node_modules/@boombot/protocol/providers/request-profile.d.ts +102 -0
  397. package/dist/node_modules/@boombot/protocol/providers/request-profile.js +118 -0
  398. package/dist/node_modules/@boombot/protocol/providers/service.d.ts +2 -0
  399. package/dist/node_modules/@boombot/protocol/providers/service.js +418 -0
  400. package/dist/node_modules/@boombot/protocol/providers/types.d.ts +141 -0
  401. package/dist/node_modules/@boombot/protocol/providers/types.js +16 -0
  402. package/dist/node_modules/@boombot/sandbox/fs-path.d.ts +13 -0
  403. package/dist/node_modules/@boombot/sandbox/fs-path.js +79 -0
  404. package/dist/node_modules/@boombot/sandbox/index.d.ts +13 -0
  405. package/dist/node_modules/@boombot/sandbox/index.js +13 -0
  406. package/dist/node_modules/@boombot/sandbox/native.d.ts +39 -0
  407. package/dist/node_modules/@boombot/sandbox/native.js +224 -0
  408. package/dist/node_modules/@boombot/sandbox/package.json +9 -0
  409. package/dist/node_modules/@boombot/sandbox/sandbox.d.ts +92 -0
  410. package/dist/node_modules/@boombot/sandbox/sandbox.js +229 -0
  411. package/dist/node_modules/@boombot/security/harness-guard/boundary.d.ts +22 -0
  412. package/dist/node_modules/@boombot/security/harness-guard/boundary.js +105 -0
  413. package/dist/node_modules/@boombot/security/harness-guard/gates.d.ts +90 -0
  414. package/dist/node_modules/@boombot/security/harness-guard/gates.js +791 -0
  415. package/dist/node_modules/@boombot/security/harness-guard/index.d.ts +23 -0
  416. package/dist/node_modules/@boombot/security/harness-guard/index.js +23 -0
  417. package/dist/node_modules/@boombot/security/harness-guard/policy.d.ts +20 -0
  418. package/dist/node_modules/@boombot/security/harness-guard/policy.js +70 -0
  419. package/dist/node_modules/@boombot/security/harness-guard/sanitizer.d.ts +53 -0
  420. package/dist/node_modules/@boombot/security/harness-guard/sanitizer.js +145 -0
  421. package/dist/node_modules/@boombot/security/harness-guard/types.d.ts +71 -0
  422. package/dist/node_modules/@boombot/security/harness-guard/types.js +10 -0
  423. package/dist/node_modules/@boombot/security/harness-guard/verifier.d.ts +59 -0
  424. package/dist/node_modules/@boombot/security/harness-guard/verifier.js +169 -0
  425. package/dist/node_modules/@boombot/security/index.d.ts +5 -0
  426. package/dist/node_modules/@boombot/security/index.js +9 -0
  427. package/dist/node_modules/@boombot/security/package.json +9 -0
  428. package/dist/node_modules/@boombot/security/policy/approval.d.ts +117 -0
  429. package/dist/node_modules/@boombot/security/policy/approval.js +223 -0
  430. package/dist/node_modules/@boombot/security/reasoning-guard/claim-extractor.d.ts +10 -0
  431. package/dist/node_modules/@boombot/security/reasoning-guard/claim-extractor.js +124 -0
  432. package/dist/node_modules/@boombot/security/reasoning-guard/evidence-ledger.d.ts +25 -0
  433. package/dist/node_modules/@boombot/security/reasoning-guard/evidence-ledger.js +70 -0
  434. package/dist/node_modules/@boombot/security/reasoning-guard/gate.d.ts +38 -0
  435. package/dist/node_modules/@boombot/security/reasoning-guard/gate.js +61 -0
  436. package/dist/node_modules/@boombot/security/reasoning-guard/grounding-check.d.ts +12 -0
  437. package/dist/node_modules/@boombot/security/reasoning-guard/grounding-check.js +234 -0
  438. package/dist/node_modules/@boombot/security/reasoning-guard/index.d.ts +17 -0
  439. package/dist/node_modules/@boombot/security/reasoning-guard/index.js +13 -0
  440. package/dist/node_modules/@boombot/security/reasoning-guard/policy.d.ts +15 -0
  441. package/dist/node_modules/@boombot/security/reasoning-guard/policy.js +39 -0
  442. package/dist/node_modules/@boombot/security/reasoning-guard/types.d.ts +46 -0
  443. package/dist/node_modules/@boombot/security/reasoning-guard/types.js +7 -0
  444. package/dist/node_modules/@boombot/security/security/approval.d.ts +63 -0
  445. package/dist/node_modules/@boombot/security/security/approval.js +140 -0
  446. package/dist/node_modules/@boombot/security/security/audit.d.ts +39 -0
  447. package/dist/node_modules/@boombot/security/security/audit.js +70 -0
  448. package/dist/node_modules/@boombot/security/security/index.d.ts +12 -0
  449. package/dist/node_modules/@boombot/security/security/index.js +12 -0
  450. package/dist/node_modules/@boombot/security/security/trust.d.ts +79 -0
  451. package/dist/node_modules/@boombot/security/security/trust.js +87 -0
  452. package/dist/package.json +5 -0
  453. package/dist/proto/agent_core.proto +56 -0
  454. package/dist/python/agent-core-python/pyproject.toml +40 -0
  455. package/dist/python/agent-core-python/src/boombot_agent/__init__.py +5 -0
  456. package/dist/python/agent-core-python/src/boombot_agent/generated/__init__.py +0 -0
  457. package/dist/python/agent-core-python/src/boombot_agent/generated/agent_core_pb2.py +54 -0
  458. package/dist/python/agent-core-python/src/boombot_agent/generated/agent_core_pb2_grpc.py +140 -0
  459. package/dist/python/agent-core-python/src/boombot_agent/rpc.py +265 -0
  460. package/dist/python/agent-core-python/src/boombot_agent/turn.py +577 -0
  461. package/dist/python/agent-core-python/src/boombot_ml/__init__.py +12 -0
  462. package/dist/python/agent-core-python/src/boombot_ml/embeddings.py +58 -0
  463. package/dist/python/agent-core-python/src/boombot_ml/training.py +156 -0
  464. package/dist/python/agent-core-python/uv.lock +2856 -0
  465. package/dist/web/assets/ChatView-BZrSD-64.js +262 -0
  466. package/dist/web/assets/ChatView-Cahbjez6.css +1 -0
  467. package/dist/web/assets/KaTeX_AMS-Regular-BQhdFMY1.woff2 +0 -0
  468. package/dist/web/assets/KaTeX_AMS-Regular-DMm9YOAa.woff +0 -0
  469. package/dist/web/assets/KaTeX_AMS-Regular-DRggAlZN.ttf +0 -0
  470. package/dist/web/assets/KaTeX_Caligraphic-Bold-ATXxdsX0.ttf +0 -0
  471. package/dist/web/assets/KaTeX_Caligraphic-Bold-BEiXGLvX.woff +0 -0
  472. package/dist/web/assets/KaTeX_Caligraphic-Bold-Dq_IR9rO.woff2 +0 -0
  473. package/dist/web/assets/KaTeX_Caligraphic-Regular-CTRA-rTL.woff +0 -0
  474. package/dist/web/assets/KaTeX_Caligraphic-Regular-Di6jR-x-.woff2 +0 -0
  475. package/dist/web/assets/KaTeX_Caligraphic-Regular-wX97UBjC.ttf +0 -0
  476. package/dist/web/assets/KaTeX_Fraktur-Bold-BdnERNNW.ttf +0 -0
  477. package/dist/web/assets/KaTeX_Fraktur-Bold-BsDP51OF.woff +0 -0
  478. package/dist/web/assets/KaTeX_Fraktur-Bold-CL6g_b3V.woff2 +0 -0
  479. package/dist/web/assets/KaTeX_Fraktur-Regular-CB_wures.ttf +0 -0
  480. package/dist/web/assets/KaTeX_Fraktur-Regular-CTYiF6lA.woff2 +0 -0
  481. package/dist/web/assets/KaTeX_Fraktur-Regular-Dxdc4cR9.woff +0 -0
  482. package/dist/web/assets/KaTeX_Main-Bold-Cx986IdX.woff2 +0 -0
  483. package/dist/web/assets/KaTeX_Main-Bold-Jm3AIy58.woff +0 -0
  484. package/dist/web/assets/KaTeX_Main-Bold-waoOVXN0.ttf +0 -0
  485. package/dist/web/assets/KaTeX_Main-BoldItalic-DxDJ3AOS.woff2 +0 -0
  486. package/dist/web/assets/KaTeX_Main-BoldItalic-DzxPMmG6.ttf +0 -0
  487. package/dist/web/assets/KaTeX_Main-BoldItalic-SpSLRI95.woff +0 -0
  488. package/dist/web/assets/KaTeX_Main-Italic-3WenGoN9.ttf +0 -0
  489. package/dist/web/assets/KaTeX_Main-Italic-BMLOBm91.woff +0 -0
  490. package/dist/web/assets/KaTeX_Main-Italic-NWA7e6Wa.woff2 +0 -0
  491. package/dist/web/assets/KaTeX_Main-Regular-B22Nviop.woff2 +0 -0
  492. package/dist/web/assets/KaTeX_Main-Regular-Dr94JaBh.woff +0 -0
  493. package/dist/web/assets/KaTeX_Main-Regular-ypZvNtVU.ttf +0 -0
  494. package/dist/web/assets/KaTeX_Math-BoldItalic-B3XSjfu4.ttf +0 -0
  495. package/dist/web/assets/KaTeX_Math-BoldItalic-CZnvNsCZ.woff2 +0 -0
  496. package/dist/web/assets/KaTeX_Math-BoldItalic-iY-2wyZ7.woff +0 -0
  497. package/dist/web/assets/KaTeX_Math-Italic-DA0__PXp.woff +0 -0
  498. package/dist/web/assets/KaTeX_Math-Italic-flOr_0UB.ttf +0 -0
  499. package/dist/web/assets/KaTeX_Math-Italic-t53AETM-.woff2 +0 -0
  500. package/dist/web/assets/KaTeX_SansSerif-Bold-CFMepnvq.ttf +0 -0
  501. package/dist/web/assets/KaTeX_SansSerif-Bold-D1sUS0GD.woff2 +0 -0
  502. package/dist/web/assets/KaTeX_SansSerif-Bold-DbIhKOiC.woff +0 -0
  503. package/dist/web/assets/KaTeX_SansSerif-Italic-C3H0VqGB.woff2 +0 -0
  504. package/dist/web/assets/KaTeX_SansSerif-Italic-DN2j7dab.woff +0 -0
  505. package/dist/web/assets/KaTeX_SansSerif-Italic-YYjJ1zSn.ttf +0 -0
  506. package/dist/web/assets/KaTeX_SansSerif-Regular-BNo7hRIc.ttf +0 -0
  507. package/dist/web/assets/KaTeX_SansSerif-Regular-CS6fqUqJ.woff +0 -0
  508. package/dist/web/assets/KaTeX_SansSerif-Regular-DDBCnlJ7.woff2 +0 -0
  509. package/dist/web/assets/KaTeX_Script-Regular-C5JkGWo-.ttf +0 -0
  510. package/dist/web/assets/KaTeX_Script-Regular-D3wIWfF6.woff2 +0 -0
  511. package/dist/web/assets/KaTeX_Script-Regular-D5yQViql.woff +0 -0
  512. package/dist/web/assets/KaTeX_Size1-Regular-C195tn64.woff +0 -0
  513. package/dist/web/assets/KaTeX_Size1-Regular-Dbsnue_I.ttf +0 -0
  514. package/dist/web/assets/KaTeX_Size1-Regular-mCD8mA8B.woff2 +0 -0
  515. package/dist/web/assets/KaTeX_Size2-Regular-B7gKUWhC.ttf +0 -0
  516. package/dist/web/assets/KaTeX_Size2-Regular-Dy4dx90m.woff2 +0 -0
  517. package/dist/web/assets/KaTeX_Size2-Regular-oD1tc_U0.woff +0 -0
  518. package/dist/web/assets/KaTeX_Size3-Regular-CTq5MqoE.woff +0 -0
  519. package/dist/web/assets/KaTeX_Size3-Regular-DgpXs0kz.ttf +0 -0
  520. package/dist/web/assets/KaTeX_Size4-Regular-BF-4gkZK.woff +0 -0
  521. package/dist/web/assets/KaTeX_Size4-Regular-DWFBv043.ttf +0 -0
  522. package/dist/web/assets/KaTeX_Size4-Regular-Dl5lxZxV.woff2 +0 -0
  523. package/dist/web/assets/KaTeX_Typewriter-Regular-C0xS9mPB.woff +0 -0
  524. package/dist/web/assets/KaTeX_Typewriter-Regular-CO6r4hn1.woff2 +0 -0
  525. package/dist/web/assets/KaTeX_Typewriter-Regular-D3Ib7_Hf.ttf +0 -0
  526. package/dist/web/assets/MemoryView-BJbXqqs7.css +1 -0
  527. package/dist/web/assets/MemoryView-BfMq_6CD.js +1 -0
  528. package/dist/web/assets/SchedulesView-B22QmPR-.js +1 -0
  529. package/dist/web/assets/SchedulesView-C6XK7A8a.css +1 -0
  530. package/dist/web/assets/SessionsView-C1dqdhxI.css +1 -0
  531. package/dist/web/assets/SessionsView-DS0-aH2a.js +1 -0
  532. package/dist/web/assets/TasksView-Dtasg4hd.css +1 -0
  533. package/dist/web/assets/TasksView-ey0FLsW8.js +2 -0
  534. package/dist/web/assets/Textarea-DN3Zybl1.js +1 -0
  535. package/dist/web/assets/Tooltip-Bn2cqFPz.css +1 -0
  536. package/dist/web/assets/Tooltip-MzV2Gqnc.js +1 -0
  537. package/dist/web/assets/browser-Bnt73-Ub.js +8 -0
  538. package/dist/web/assets/index-BL8bi7Yt.css +1 -0
  539. package/dist/web/assets/index-CuPR73Tn.js +73 -0
  540. package/dist/web/favicon.svg +4 -0
  541. package/dist/web/index.html +26 -0
  542. package/dist/web/logo.jpg +0 -0
  543. package/dist/web/logo.png +0 -0
  544. package/package.json +51 -4
@@ -0,0 +1,608 @@
1
+ /**
2
+ * Channel service for the gateway runtime (phase 2).
3
+ *
4
+ * Owns every channel transport (`channels/src/transports/*`):
5
+ * starts the configured ones at boot, stops them cleanly on shutdown, and
6
+ * exposes the operations the command handlers need:
7
+ *
8
+ * - `list()` → `ChannelInfo[]` for the `channel.list` command (real status:
9
+ * `connected` when creds are present and the transport is running,
10
+ * `error` when creds exist but the platform rejected them,
11
+ * `disconnected` when creds are missing — the NOT_CONFIGURED case).
12
+ * - `send(channel, target, text)` → outbound message via the transport.
13
+ * - `pair(channel)` / `unpair(channel, target)` → Telegram chat pairing
14
+ * (`BOOM-######` codes) for Telegram and Zalo Personal.
15
+ *
16
+ * Integration contract (for executor A, who owns `context.ts`):
17
+ * the real `ServiceContext` must structurally satisfy
18
+ * {@link ChannelServiceContext} below (`config`, `dataDir`, `log`,
19
+ * `events`, optional `turnService`). `startChannelService` attaches the
20
+ * service at `ctx.channelService`; `getChannelService()` exposes the
21
+ * started instance to `handlers/channels.ts`.
22
+ *
23
+ * Secrets: channel configs carry tokens; they are passed to transports and
24
+ * never logged (SECURITY.md §5).
25
+ */
26
+ import { createHash, randomBytes } from 'node:crypto';
27
+ import { chmodSync, existsSync, mkdirSync, readFileSync, renameSync, writeFileSync, } from 'node:fs';
28
+ import { dirname, join } from 'node:path';
29
+ import { decryptSecret, encryptSecret, } from '@boombot/protocol';
30
+ import { isTurnDonePayload, } from './transports/common.js';
31
+ import { DiscordTransport, } from './transports/discord.js';
32
+ import { MessengerTransport, } from './transports/messenger.js';
33
+ import { SlackTransport, } from './transports/slack.js';
34
+ import { TelegramTransport, TURN_DONE_EVENT, } from './transports/telegram.js';
35
+ import { TikTokTransport, } from './transports/tiktok.js';
36
+ import { WhatsAppTransport, } from './transports/whatsapp.js';
37
+ import { createZaloPersonalClient, ZALO_QR_EVENT, ZaloPersonalTransport, } from './transports/zalo-personal.js';
38
+ import { ZaloTransport, } from './transports/zalo.js';
39
+ const DISPLAY_ORDER = [
40
+ 'telegram',
41
+ 'whatsapp',
42
+ 'discord',
43
+ 'slack',
44
+ 'zalo',
45
+ 'messenger',
46
+ 'tiktok',
47
+ ];
48
+ let activeService;
49
+ const ZALO_PERMISSION_URL = 'https://oauth.zaloapp.com/v4/oa/permission';
50
+ const ZALO_TOKEN_URL = 'https://oauth.zaloapp.com/v4/oa/access_token';
51
+ const ZALO_CALLBACK_PATH = '/v1/channels/zalo/oauth/callback';
52
+ const OAUTH_TTL_MS = 10 * 60 * 1000;
53
+ const REFRESH_EARLY_MS = 5 * 60 * 1000;
54
+ function parseZaloPersonalCredentials(raw) {
55
+ const value = JSON.parse(raw);
56
+ if (typeof value !== 'object' ||
57
+ value === null ||
58
+ typeof value.imei !== 'string' ||
59
+ typeof value.userAgent !== 'string' ||
60
+ !('cookie' in value)) {
61
+ throw new Error('invalid Zalo personal credentials');
62
+ }
63
+ return value;
64
+ }
65
+ function readCredentials(path, masterKey, log) {
66
+ if (!existsSync(path))
67
+ return {};
68
+ if (!masterKey) {
69
+ log.warn('channel credentials ignored: BOOMBOT_MASTER_KEY is missing');
70
+ return {};
71
+ }
72
+ try {
73
+ const stored = JSON.parse(readFileSync(path, 'utf8'));
74
+ if (stored.version !== 1)
75
+ throw new Error('unsupported store version');
76
+ return {
77
+ ...(stored.zaloMode ? { zaloMode: stored.zaloMode } : {}),
78
+ ...(stored.telegram
79
+ ? { telegramBotToken: decryptSecret(masterKey, stored.telegram.botTokenCipher) }
80
+ : {}),
81
+ ...(stored.zalo
82
+ ? {
83
+ zalo: {
84
+ appId: stored.zalo.appId,
85
+ appSecret: decryptSecret(masterKey, stored.zalo.appSecretCipher),
86
+ accessToken: decryptSecret(masterKey, stored.zalo.accessTokenCipher),
87
+ refreshToken: decryptSecret(masterKey, stored.zalo.refreshTokenCipher),
88
+ expiresAt: stored.zalo.expiresAt,
89
+ ...(stored.zalo.oaId ? { oaId: stored.zalo.oaId } : {}),
90
+ },
91
+ }
92
+ : {}),
93
+ ...(stored.zaloPersonal
94
+ ? {
95
+ zaloPersonal: parseZaloPersonalCredentials(decryptSecret(masterKey, stored.zaloPersonal.credentialsCipher)),
96
+ }
97
+ : {}),
98
+ };
99
+ }
100
+ catch (error) {
101
+ log.error('channel credentials could not be read', {
102
+ error: error instanceof Error ? error.message : String(error),
103
+ });
104
+ return {};
105
+ }
106
+ }
107
+ function writeCredentials(path, masterKey, credentials) {
108
+ const stored = {
109
+ version: 1,
110
+ ...(credentials.zaloMode ? { zaloMode: credentials.zaloMode } : {}),
111
+ ...(credentials.telegramBotToken
112
+ ? {
113
+ telegram: {
114
+ botTokenCipher: encryptSecret(masterKey, credentials.telegramBotToken),
115
+ },
116
+ }
117
+ : {}),
118
+ ...(credentials.zalo
119
+ ? {
120
+ zalo: {
121
+ appId: credentials.zalo.appId,
122
+ appSecretCipher: encryptSecret(masterKey, credentials.zalo.appSecret),
123
+ accessTokenCipher: encryptSecret(masterKey, credentials.zalo.accessToken),
124
+ refreshTokenCipher: encryptSecret(masterKey, credentials.zalo.refreshToken),
125
+ expiresAt: credentials.zalo.expiresAt,
126
+ ...(credentials.zalo.oaId ? { oaId: credentials.zalo.oaId } : {}),
127
+ },
128
+ }
129
+ : {}),
130
+ ...(credentials.zaloPersonal
131
+ ? {
132
+ zaloPersonal: {
133
+ credentialsCipher: encryptSecret(masterKey, JSON.stringify(credentials.zaloPersonal)),
134
+ },
135
+ }
136
+ : {}),
137
+ };
138
+ mkdirSync(dirname(path), { recursive: true });
139
+ const temporary = `${path}.tmp`;
140
+ writeFileSync(temporary, JSON.stringify(stored, null, 2), {
141
+ encoding: 'utf8',
142
+ mode: 0o600,
143
+ });
144
+ try {
145
+ chmodSync(temporary, 0o600);
146
+ }
147
+ catch {
148
+ // Windows ACLs do not follow POSIX chmod; encryption remains mandatory.
149
+ }
150
+ renameSync(temporary, path);
151
+ }
152
+ function parseZaloTokens(raw) {
153
+ const accessToken = typeof raw.access_token === 'string' ? raw.access_token : '';
154
+ const refreshToken = typeof raw.refresh_token === 'string' ? raw.refresh_token : '';
155
+ const expiresIn = Number(raw.expires_in);
156
+ if (accessToken === '' || refreshToken === '' || !Number.isFinite(expiresIn) || expiresIn <= 0) {
157
+ throw new Error('ZALO_TOKEN_EXCHANGE_FAILED: invalid token response');
158
+ }
159
+ return {
160
+ accessToken,
161
+ refreshToken,
162
+ expiresAt: Date.now() + expiresIn * 1000,
163
+ };
164
+ }
165
+ /** The service started by `startChannelService`, if any. */
166
+ export function getChannelService() {
167
+ return activeService;
168
+ }
169
+ class DefaultChannelService {
170
+ credentialPath;
171
+ credentials;
172
+ ctx;
173
+ log;
174
+ masterKey;
175
+ oauthSessions = new Map();
176
+ transports;
177
+ zaloQrAbort;
178
+ constructor(transports, ctx, credentials) {
179
+ this.transports = transports;
180
+ this.ctx = ctx;
181
+ this.credentials = credentials;
182
+ this.log = ctx.log;
183
+ this.credentialPath = join(ctx.dataDir, 'channels', 'credentials.json');
184
+ this.masterKey = process.env['BOOMBOT_MASTER_KEY']?.trim() || undefined;
185
+ }
186
+ async list() {
187
+ return this.transports.map((transport) => {
188
+ const { status } = transport.getStatus();
189
+ return {
190
+ id: transport.kind,
191
+ kind: transport.kind,
192
+ status,
193
+ displayName: transport.displayName,
194
+ };
195
+ });
196
+ }
197
+ stopPendingConnections() {
198
+ this.zaloQrAbort?.();
199
+ this.zaloQrAbort = undefined;
200
+ }
201
+ async send(channel, target, text) {
202
+ if (channel === 'zalo' && this.credentials.zaloMode !== 'personal') {
203
+ await this.refreshZaloIfNeeded();
204
+ }
205
+ await this.findTransport(channel).send(target, text);
206
+ }
207
+ async handleWebhook(channel, request) {
208
+ const transport = this.findTransportByKind(channel);
209
+ const handler = transport.handleWebhook;
210
+ if (handler === undefined)
211
+ return { status: 404 };
212
+ return handler.call(transport, request);
213
+ }
214
+ async connect(input) {
215
+ if (input.channel === 'telegram')
216
+ return this.connectTelegram(input.botToken);
217
+ return input.mode === 'personal'
218
+ ? this.startZaloPersonalQr()
219
+ : this.startZaloOAuth(input);
220
+ }
221
+ async completeZaloOAuth(params) {
222
+ const state = params.get('state') ?? '';
223
+ const session = this.oauthSessions.get(state);
224
+ this.oauthSessions.delete(state);
225
+ if (session === undefined || session.expiresAt <= Date.now()) {
226
+ throw new Error('ZALO_OAUTH_INVALID_STATE');
227
+ }
228
+ if (params.has('error'))
229
+ throw new Error('ZALO_OAUTH_DENIED');
230
+ const code = params.get('code')?.trim() ?? '';
231
+ if (code === '')
232
+ throw new Error('ZALO_OAUTH_MISSING_CODE');
233
+ const response = await fetch(ZALO_TOKEN_URL, {
234
+ method: 'POST',
235
+ headers: {
236
+ 'content-type': 'application/x-www-form-urlencoded',
237
+ secret_key: session.appSecret,
238
+ },
239
+ body: new URLSearchParams({
240
+ app_id: session.appId,
241
+ code,
242
+ grant_type: 'authorization_code',
243
+ code_verifier: session.codeVerifier,
244
+ }),
245
+ signal: AbortSignal.timeout(15_000),
246
+ });
247
+ if (!response.ok)
248
+ throw new Error(`ZALO_TOKEN_EXCHANGE_FAILED: HTTP ${response.status}`);
249
+ const tokens = parseZaloTokens((await response.json()));
250
+ const oaId = params.get('oa_id')?.trim() || undefined;
251
+ const zalo = {
252
+ appId: session.appId,
253
+ appSecret: session.appSecret,
254
+ ...tokens,
255
+ ...(oaId ? { oaId } : {}),
256
+ };
257
+ const transport = new ZaloTransport({ oaToken: zalo.accessToken }, this.log);
258
+ await transport.start();
259
+ if (transport.getStatus().status !== 'connected') {
260
+ throw new Error('ZALO_CREDENTIAL_CHECK_FAILED');
261
+ }
262
+ this.credentials.zalo = zalo;
263
+ this.credentials.zaloMode = 'oa';
264
+ try {
265
+ this.persistCredentials();
266
+ }
267
+ catch (error) {
268
+ await transport.stop();
269
+ throw error;
270
+ }
271
+ await this.replaceTransport('zalo', transport);
272
+ this.log.info('zalo: OAuth connection completed', { oaId });
273
+ }
274
+ async pair(channel) {
275
+ const transport = this.findTransport(channel);
276
+ if (!(transport instanceof TelegramTransport) &&
277
+ !(transport instanceof ZaloPersonalTransport)) {
278
+ throw new Error(`PAIRING_UNSUPPORTED: pairing requires Telegram or Zalo Personal (requested: ${channel}).`);
279
+ }
280
+ const code = transport.createPairingCode();
281
+ this.log.info('channel.pair: pairing code created', { channel });
282
+ return code;
283
+ }
284
+ async unpair(channel, target) {
285
+ const transport = this.findTransport(channel);
286
+ if (transport instanceof ZaloPersonalTransport) {
287
+ transport.unpairThread(target);
288
+ }
289
+ else if (transport instanceof TelegramTransport) {
290
+ transport.unpairChat(target);
291
+ }
292
+ else {
293
+ throw new Error(`PAIRING_UNSUPPORTED: unpair requires Telegram or Zalo Personal (requested: ${channel}).`);
294
+ }
295
+ this.log.info('channel.unpair: chat removed from allowlist', { channel, target });
296
+ }
297
+ async connectTelegram(rawToken) {
298
+ const botToken = rawToken.trim();
299
+ if (!/^\d+:[A-Za-z0-9_-]{20,}$/.test(botToken)) {
300
+ throw new Error('INVALID_ARGUMENT: Telegram bot token format is invalid');
301
+ }
302
+ const current = this.findTransportByKind('telegram');
303
+ if (current.getStatus().status === 'connected') {
304
+ return { status: 'connected', displayName: current.displayName };
305
+ }
306
+ const transport = new TelegramTransport({
307
+ config: { ...(this.ctx.config.channels?.telegram ?? {}), botToken },
308
+ dataDir: this.ctx.dataDir,
309
+ log: this.log,
310
+ turnService: this.ctx.turnService,
311
+ subscribeTurnDone: makeTurnDoneSubscription(this.ctx.events),
312
+ });
313
+ await transport.start();
314
+ const status = transport.getStatus().status;
315
+ if (status !== 'connected' && status !== 'pending') {
316
+ await transport.stop();
317
+ throw new Error('INVALID_ARGUMENT: Telegram rejected the bot token');
318
+ }
319
+ this.credentials.telegramBotToken = botToken;
320
+ try {
321
+ this.persistCredentials();
322
+ }
323
+ catch (error) {
324
+ await transport.stop();
325
+ throw error;
326
+ }
327
+ await this.replaceTransport('telegram', transport);
328
+ return { status: 'connected', displayName: transport.displayName };
329
+ }
330
+ async startZaloPersonalQr() {
331
+ this.zaloQrAbort?.();
332
+ const zalo = createZaloPersonalClient();
333
+ let settled = false;
334
+ let resolveQr = () => { };
335
+ let rejectQr = () => { };
336
+ const qr = new Promise((resolve, reject) => {
337
+ resolveQr = resolve;
338
+ rejectQr = reject;
339
+ });
340
+ const login = zalo.loginQR({}, (event) => {
341
+ if (event.actions)
342
+ this.zaloQrAbort = event.actions.abort;
343
+ if (event.type === ZALO_QR_EVENT.QRCodeGenerated && event.data) {
344
+ settled = true;
345
+ resolveQr({
346
+ status: 'qr_required',
347
+ qrDataUrl: `data:image/png;base64,${event.data.image}`,
348
+ expiresAt: new Date(Date.now() + 2 * 60 * 1000).toISOString(),
349
+ });
350
+ }
351
+ else if (!settled &&
352
+ (event.type === ZALO_QR_EVENT.QRCodeExpired ||
353
+ event.type === ZALO_QR_EVENT.QRCodeDeclined)) {
354
+ rejectQr(new Error('ZALO_QR_EXPIRED'));
355
+ }
356
+ });
357
+ void login
358
+ .then((api) => this.completeZaloPersonalLogin(api))
359
+ .catch((error) => {
360
+ if (!settled)
361
+ rejectQr(error instanceof Error ? error : new Error(String(error)));
362
+ this.log.error('zalo personal: QR login failed', {
363
+ detail: error instanceof Error ? error.message : String(error),
364
+ });
365
+ })
366
+ .finally(() => {
367
+ this.zaloQrAbort = undefined;
368
+ });
369
+ return qr;
370
+ }
371
+ async completeZaloPersonalLogin(api) {
372
+ const transport = new ZaloPersonalTransport({
373
+ api,
374
+ dataDir: this.ctx.dataDir,
375
+ log: this.log,
376
+ turnService: this.ctx.turnService,
377
+ subscribeTurnDone: makeTurnDoneSubscription(this.ctx.events),
378
+ });
379
+ await transport.start();
380
+ const status = transport.getStatus().status;
381
+ if (status !== 'connected' && status !== 'pending') {
382
+ await transport.stop();
383
+ throw new Error('ZALO_PERSONAL_LOGIN_FAILED');
384
+ }
385
+ const context = api.getContext();
386
+ this.credentials.zaloPersonal = {
387
+ imei: context.imei,
388
+ userAgent: context.userAgent,
389
+ language: context.language,
390
+ cookie: api.getCookie().serializeSync()?.cookies ?? [],
391
+ };
392
+ this.credentials.zaloMode = 'personal';
393
+ try {
394
+ this.persistCredentials();
395
+ }
396
+ catch (error) {
397
+ await transport.stop();
398
+ throw error;
399
+ }
400
+ await this.replaceTransport('zalo', transport);
401
+ this.log.info('zalo personal: QR connection completed');
402
+ }
403
+ startZaloOAuth(input) {
404
+ const configured = this.ctx.config.channels?.zalo;
405
+ const appId = input.appId?.trim() || configured?.appId?.trim() || this.credentials.zalo?.appId;
406
+ const appSecret = input.appSecret?.trim() || configured?.appSecret?.trim() || this.credentials.zalo?.appSecret;
407
+ if (!appId || !appSecret) {
408
+ throw new Error('NOT_CONFIGURED: Zalo OAuth requires appId and appSecret');
409
+ }
410
+ const redirect = new URL(input.redirectUri);
411
+ const local = ['localhost', '127.0.0.1', '::1'].includes(redirect.hostname);
412
+ if (redirect.pathname !== ZALO_CALLBACK_PATH ||
413
+ (redirect.protocol !== 'https:' && !(local && redirect.protocol === 'http:')) ||
414
+ redirect.username !== '' ||
415
+ redirect.password !== '' ||
416
+ redirect.hash !== '') {
417
+ throw new Error(`INVALID_ARGUMENT: redirectUri must be HTTPS and end with ${ZALO_CALLBACK_PATH}`);
418
+ }
419
+ const state = randomBytes(32).toString('base64url');
420
+ const codeVerifier = randomBytes(48).toString('base64url');
421
+ const codeChallenge = createHash('sha256').update(codeVerifier).digest('base64url');
422
+ const expiresAt = Date.now() + OAUTH_TTL_MS;
423
+ for (const [key, value] of this.oauthSessions) {
424
+ if (value.expiresAt <= Date.now())
425
+ this.oauthSessions.delete(key);
426
+ }
427
+ this.oauthSessions.set(state, {
428
+ appId,
429
+ appSecret,
430
+ codeVerifier,
431
+ redirectUri: redirect.toString(),
432
+ expiresAt,
433
+ });
434
+ const authorizationUrl = new URL(ZALO_PERMISSION_URL);
435
+ authorizationUrl.search = new URLSearchParams({
436
+ app_id: appId,
437
+ redirect_uri: redirect.toString(),
438
+ code_challenge: codeChallenge,
439
+ state,
440
+ }).toString();
441
+ return {
442
+ status: 'authorization_required',
443
+ authorizationUrl: authorizationUrl.toString(),
444
+ expiresAt: new Date(expiresAt).toISOString(),
445
+ };
446
+ }
447
+ async refreshZaloIfNeeded() {
448
+ const current = this.credentials.zalo;
449
+ if (current === undefined || current.expiresAt > Date.now() + REFRESH_EARLY_MS)
450
+ return;
451
+ const response = await fetch(ZALO_TOKEN_URL, {
452
+ method: 'POST',
453
+ headers: {
454
+ 'content-type': 'application/x-www-form-urlencoded',
455
+ secret_key: current.appSecret,
456
+ },
457
+ body: new URLSearchParams({
458
+ app_id: current.appId,
459
+ refresh_token: current.refreshToken,
460
+ grant_type: 'refresh_token',
461
+ }),
462
+ signal: AbortSignal.timeout(15_000),
463
+ });
464
+ if (!response.ok)
465
+ throw new Error(`ZALO_TOKEN_REFRESH_FAILED: HTTP ${response.status}`);
466
+ const tokens = parseZaloTokens((await response.json()));
467
+ const zalo = { ...current, ...tokens };
468
+ const transport = new ZaloTransport({ oaToken: zalo.accessToken }, this.log);
469
+ await transport.start();
470
+ if (transport.getStatus().status !== 'connected') {
471
+ throw new Error('ZALO_TOKEN_REFRESH_FAILED: credential check failed');
472
+ }
473
+ this.credentials.zalo = zalo;
474
+ this.persistCredentials();
475
+ await this.replaceTransport('zalo', transport);
476
+ }
477
+ persistCredentials() {
478
+ if (!this.masterKey) {
479
+ throw new Error('NOT_CONFIGURED: BOOMBOT_MASTER_KEY is required to store channel credentials');
480
+ }
481
+ writeCredentials(this.credentialPath, this.masterKey, this.credentials);
482
+ }
483
+ async replaceTransport(kind, replacement) {
484
+ const index = this.transports.findIndex((transport) => transport.kind === kind);
485
+ if (index === -1)
486
+ throw new Error(`UNKNOWN_CHANNEL: ${kind}`);
487
+ const previous = this.transports[index];
488
+ if (previous === undefined)
489
+ throw new Error(`UNKNOWN_CHANNEL: ${kind}`);
490
+ if (previous !== replacement)
491
+ await previous.stop();
492
+ this.transports[index] = replacement;
493
+ }
494
+ findTransportByKind(channel) {
495
+ const transport = this.transports.find((candidate) => candidate.kind === channel);
496
+ if (transport === undefined)
497
+ throw new Error(`UNKNOWN_CHANNEL: no channel "${channel}".`);
498
+ return transport;
499
+ }
500
+ findTransport(channel) {
501
+ const transport = this.findTransportByKind(channel);
502
+ if (transport.getStatus().status === 'disconnected') {
503
+ throw new Error(`NOT_CONFIGURED: channel "${channel}" is not configured.`);
504
+ }
505
+ return transport;
506
+ }
507
+ }
508
+ /**
509
+ * Wire the internal event bus to the Telegram transport's turn-reply hook.
510
+ * When the gateway publishes `agent.turn.done` (executor B, see
511
+ * `TURN_DONE_EVENT` in channels/common.ts), the payload is validated and
512
+ * forwarded; anything else is ignored.
513
+ */
514
+ function makeTurnDoneSubscription(events) {
515
+ const subscribe = events.subscribe;
516
+ if (subscribe === undefined) {
517
+ return undefined;
518
+ }
519
+ return (handler) => subscribe(TURN_DONE_EVENT, (raw) => {
520
+ if (isTurnDonePayload(raw)) {
521
+ handler(raw);
522
+ }
523
+ });
524
+ }
525
+ /**
526
+ * Start every configured channel transport.
527
+ *
528
+ * Telegram runs its long-polling loop in the background (with backoff);
529
+ * WhatsApp/Discord/Slack expose signed HTTP webhooks. A transport that fails to
530
+ * start is left in `error` status and never blocks the others.
531
+ *
532
+ * @returns a stop function that shuts every transport down cleanly.
533
+ */
534
+ export async function startChannelService(ctx) {
535
+ const channelConfigs = ctx.config.channels ?? {};
536
+ const credentials = readCredentials(join(ctx.dataDir, 'channels', 'credentials.json'), process.env['BOOMBOT_MASTER_KEY']?.trim() || undefined, ctx.log);
537
+ if (channelConfigs.zalo?.oaToken) {
538
+ credentials.zalo = undefined;
539
+ credentials.zaloMode = 'oa';
540
+ }
541
+ const transports = [];
542
+ const telegram = new TelegramTransport({
543
+ config: {
544
+ ...(channelConfigs.telegram ?? {}),
545
+ botToken: channelConfigs.telegram?.botToken ?? credentials.telegramBotToken,
546
+ },
547
+ dataDir: ctx.dataDir,
548
+ log: ctx.log,
549
+ turnService: ctx.turnService,
550
+ subscribeTurnDone: makeTurnDoneSubscription(ctx.events),
551
+ });
552
+ transports.push(telegram);
553
+ const inbound = {
554
+ turnService: ctx.turnService,
555
+ subscribeTurnDone: makeTurnDoneSubscription(ctx.events),
556
+ };
557
+ transports.push(new WhatsAppTransport(channelConfigs.whatsapp ?? {}, ctx.log, inbound));
558
+ transports.push(new DiscordTransport(channelConfigs.discord ?? {}, ctx.log, inbound));
559
+ transports.push(new SlackTransport(channelConfigs.slack ?? {}, ctx.log, inbound));
560
+ transports.push(credentials.zaloMode === 'personal' && credentials.zaloPersonal
561
+ ? new ZaloPersonalTransport({
562
+ credentials: credentials.zaloPersonal,
563
+ dataDir: ctx.dataDir,
564
+ log: ctx.log,
565
+ turnService: ctx.turnService,
566
+ subscribeTurnDone: makeTurnDoneSubscription(ctx.events),
567
+ })
568
+ : new ZaloTransport({
569
+ ...(channelConfigs.zalo ?? {}),
570
+ oaToken: channelConfigs.zalo?.oaToken ?? credentials.zalo?.accessToken,
571
+ }, ctx.log));
572
+ const messengerTransport = new MessengerTransport({
573
+ ...(channelConfigs.messenger ?? {}),
574
+ turnService: ctx.turnService,
575
+ subscribeTurnDone: makeTurnDoneSubscription(ctx.events),
576
+ }, ctx.log);
577
+ transports.push(messengerTransport);
578
+ transports.push(new TikTokTransport(channelConfigs.tiktok ?? {}, ctx.log));
579
+ for (const transport of transports) {
580
+ try {
581
+ await transport.start();
582
+ }
583
+ catch (err) {
584
+ // Never let one channel break gateway boot; it stays in error status.
585
+ ctx.log.error(`channel ${transport.kind}: start failed`, {
586
+ error: err instanceof Error ? err.message : String(err),
587
+ });
588
+ }
589
+ }
590
+ // Keep a stable, documented order for channel.list.
591
+ transports.sort((a, b) => DISPLAY_ORDER.indexOf(a.kind) - DISPLAY_ORDER.indexOf(b.kind));
592
+ const service = new DefaultChannelService(transports, ctx, credentials);
593
+ ctx.channelService = service;
594
+ activeService = service;
595
+ return async () => {
596
+ service.stopPendingConnections();
597
+ for (const transport of transports) {
598
+ try {
599
+ await transport.stop();
600
+ }
601
+ catch (err) {
602
+ ctx.log.error(`channel ${transport.kind}: stop failed`, {
603
+ error: err instanceof Error ? err.message : String(err),
604
+ });
605
+ }
606
+ }
607
+ };
608
+ }
@@ -0,0 +1,10 @@
1
+ import type { ToolCall, ToolDefinition, ToolResult } from '@boombot/core';
2
+ export declare const CHANNEL_SEND_TOOL_NAME = "channel.send";
3
+ export declare const channelSendDefinition: ToolDefinition;
4
+ export interface ChannelSendService {
5
+ send(channel: string, target: string, text: string): Promise<void>;
6
+ }
7
+ export interface ChannelToolRegistry {
8
+ registerTool(definition: ToolDefinition, handler: (call: ToolCall, signal?: AbortSignal) => Promise<ToolResult> | ToolResult): void;
9
+ }
10
+ export declare function registerChannelTool(registry: ChannelToolRegistry, service: ChannelSendService): void;
@@ -0,0 +1,46 @@
1
+ export const CHANNEL_SEND_TOOL_NAME = 'channel.send';
2
+ export const channelSendDefinition = {
3
+ name: CHANNEL_SEND_TOOL_NAME,
4
+ description: 'Send a text message through a configured messaging channel after operator approval.',
5
+ parameters: {
6
+ type: 'object',
7
+ properties: {
8
+ channel: { type: 'string', description: 'Configured channel kind, for example telegram.' },
9
+ target: { type: 'string', description: 'Channel-specific recipient or chat id.' },
10
+ text: { type: 'string', description: 'Message text to send.' },
11
+ },
12
+ required: ['channel', 'target', 'text'],
13
+ additionalProperties: false,
14
+ },
15
+ };
16
+ function requiredString(call, key) {
17
+ const value = call.arguments[key];
18
+ if (typeof value !== 'string' || value.trim() === '') {
19
+ throw new Error(`'${key}' must be a non-empty string`);
20
+ }
21
+ return value.trim();
22
+ }
23
+ export function registerChannelTool(registry, service) {
24
+ registry.registerTool(channelSendDefinition, async (call) => {
25
+ try {
26
+ const channel = requiredString(call, 'channel');
27
+ const target = requiredString(call, 'target');
28
+ const text = requiredString(call, 'text');
29
+ await service.send(channel, target, text);
30
+ return {
31
+ callId: call.id,
32
+ name: call.name,
33
+ output: `Message sent through ${channel}.`,
34
+ error: false,
35
+ };
36
+ }
37
+ catch (error) {
38
+ return {
39
+ callId: call.id,
40
+ name: call.name,
41
+ output: `channel.send: ${error instanceof Error ? error.message : 'unknown error'}`,
42
+ error: true,
43
+ };
44
+ }
45
+ });
46
+ }
@@ -0,0 +1,17 @@
1
+ /**
2
+ * MessageDeduplicator — sliding TTL cache preventing duplicate message processing.
3
+ * Direct concept from ChannelHub core.
4
+ */
5
+ export declare class MessageDeduplicator {
6
+ private readonly ttlMs;
7
+ private readonly maxSize;
8
+ private readonly seen;
9
+ constructor(ttlMs?: number, // 10 minutes
10
+ maxSize?: number);
11
+ /**
12
+ * Returns true if the messageId is seen for the first time.
13
+ * Returns false if it has already been processed within the TTL window.
14
+ */
15
+ checkAndRecord(messageId: string): boolean;
16
+ private prune;
17
+ }