@johpaz/hive-agents 0.0.35 → 0.0.36

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 (440) hide show
  1. package/README.md +64 -39
  2. package/dist/hive.js +3127 -3104
  3. package/dist/ui/assets/{AgentCreateForm-B4eK7efF.js → AgentCreateForm-tJZv9FZC.js} +1 -1
  4. package/dist/ui/assets/{AgentDetailPage-BD2uoJWk.js → AgentDetailPage-Du-mRcAX.js} +1 -1
  5. package/dist/ui/assets/AgentNewPage-DIFYd_Ys.js +1 -0
  6. package/dist/ui/assets/{AgentsPage-4JUZXvkA.js → AgentsPage-YvSgWRiw.js} +6 -6
  7. package/dist/ui/assets/CanvasPage-DtMwGvxf.js +33 -0
  8. package/dist/ui/assets/{ChannelsPage-BUn7-nhV.js → ChannelsPage-BdBXWHjj.js} +1 -1
  9. package/dist/ui/assets/DashboardPage-ghl1ZguH.js +6 -0
  10. package/dist/ui/assets/{LoginPage-C8j_urUD.js → LoginPage-CAmSI9Vy.js} +1 -1
  11. package/dist/ui/assets/LogsPage-DAPBHkwK.js +1 -0
  12. package/dist/ui/assets/MeetingPage-WjjGOqqU.js +1 -0
  13. package/dist/ui/assets/{NotFound-Drh-sJPN.js → NotFound-BMeQSGcG.js} +1 -1
  14. package/dist/ui/assets/ProvidersPage-Ct6HsAi1.js +1 -0
  15. package/dist/ui/assets/{RecoverPage-DNb1Pr8h.js → RecoverPage-DpW3l-yv.js} +1 -1
  16. package/dist/ui/assets/SettingsPage-DBJ7_E6C.js +9 -0
  17. package/dist/ui/assets/SetupPage-DKmLVUaj.js +1 -0
  18. package/dist/ui/assets/{WebChatPage-R-YOwA4F.js → WebChatPage-CVRcKept.js} +2 -2
  19. package/dist/ui/assets/accordion-C5d5Rm5z.js +1 -0
  20. package/dist/ui/assets/{alert-U8FsgWi7.js → alert-C-NE-P3s.js} +1 -1
  21. package/dist/ui/assets/{alert-dialog-CRdMkkmk.js → alert-dialog-C5mzbHdP.js} +1 -1
  22. package/dist/ui/assets/{badge-Cli1jnH5.js → badge-ChpACfWO.js} +1 -1
  23. package/dist/ui/assets/chevron-up-BYhk0K2J.js +1 -0
  24. package/dist/ui/assets/{dialog-DQ3s-LuO.js → dialog-QnZ0ad8O.js} +1 -1
  25. package/dist/ui/assets/dropdown-menu-BK-CO3Od.js +1 -0
  26. package/dist/ui/assets/{es-DcMjrpbA.js → es-NQNoaWDx.js} +1 -1
  27. package/dist/ui/assets/index-B2fCYtTS.css +2 -0
  28. package/dist/ui/assets/index-DMCjjdqf.js +116 -0
  29. package/dist/ui/assets/{label-0BvGVXvZ.js → label-D2H1IR_J.js} +1 -1
  30. package/dist/ui/assets/progress-BherYzY6.js +1 -0
  31. package/dist/ui/assets/scroll-area-DkeyX32e.js +1 -0
  32. package/dist/ui/assets/{slider-D47dOrRa.js → slider-CsiUDxc3.js} +1 -1
  33. package/dist/ui/assets/switch-BDwN8RYV.js +1 -0
  34. package/dist/ui/assets/{table-DhowbNxQ.js → table-CSc8ubon.js} +1 -1
  35. package/dist/ui/assets/terminal-DN38Q456.js +1 -0
  36. package/dist/ui/assets/useProviders-C6_QHsEi.js +1 -0
  37. package/dist/ui/assets/{vendor-radix-JY4ncZrD.js → vendor-radix-cw1bQaVC.js} +4 -4
  38. package/dist/ui/assets/{vendor-react-CscwQerf.js → vendor-react-D4s9E-zj.js} +1 -1
  39. package/dist/ui/dist/assets/AgentCreateForm-tJZv9FZC.js +1 -0
  40. package/dist/ui/dist/assets/AgentDetailPage-Du-mRcAX.js +1 -0
  41. package/dist/ui/dist/assets/AgentNewPage-DIFYd_Ys.js +1 -0
  42. package/dist/ui/dist/assets/AgentsPage-YvSgWRiw.js +10 -0
  43. package/dist/ui/dist/assets/CanvasPage-DtMwGvxf.js +33 -0
  44. package/dist/ui/dist/assets/ChannelsPage-BdBXWHjj.js +8 -0
  45. package/dist/ui/dist/assets/DashboardPage-ghl1ZguH.js +6 -0
  46. package/dist/ui/dist/assets/LoginPage-CAmSI9Vy.js +1 -0
  47. package/dist/ui/dist/assets/LogsPage-DAPBHkwK.js +1 -0
  48. package/dist/ui/dist/assets/MeetingPage-WjjGOqqU.js +1 -0
  49. package/dist/ui/dist/assets/NotFound-BMeQSGcG.js +1 -0
  50. package/dist/ui/dist/assets/ProvidersPage-Ct6HsAi1.js +1 -0
  51. package/dist/ui/dist/assets/RecoverPage-DpW3l-yv.js +1 -0
  52. package/dist/ui/dist/assets/SettingsPage-DBJ7_E6C.js +9 -0
  53. package/dist/ui/dist/assets/SetupPage-DKmLVUaj.js +1 -0
  54. package/dist/ui/dist/assets/WebChatPage-CVRcKept.js +16 -0
  55. package/dist/ui/dist/assets/accordion-C5d5Rm5z.js +1 -0
  56. package/dist/ui/dist/assets/activity-c3pNngT_.js +1 -0
  57. package/dist/ui/dist/assets/alert-C-NE-P3s.js +1 -0
  58. package/dist/ui/dist/assets/alert-dialog-C5mzbHdP.js +1 -0
  59. package/dist/ui/dist/assets/arrow-left-CBcbX5EZ.js +1 -0
  60. package/dist/ui/dist/assets/badge-ChpACfWO.js +1 -0
  61. package/dist/ui/dist/assets/calendar-B-KZ9RQO.js +1 -0
  62. package/dist/ui/dist/assets/card-CNf6BS2e.js +1 -0
  63. package/dist/ui/dist/assets/chevron-left-D4U-5A27.js +1 -0
  64. package/dist/ui/dist/assets/chevron-right-CR4Skrf3.js +1 -0
  65. package/dist/ui/dist/assets/chevron-up-BYhk0K2J.js +1 -0
  66. package/dist/ui/dist/assets/circle-alert-CyHDwUj8.js +1 -0
  67. package/dist/ui/dist/assets/circle-check-Bb54Ebmu.js +1 -0
  68. package/dist/ui/dist/assets/cpu-Cdgc_B1K.js +1 -0
  69. package/dist/ui/dist/assets/dialog-QnZ0ad8O.js +1 -0
  70. package/dist/ui/dist/assets/download-C3ifGMjJ.js +1 -0
  71. package/dist/ui/dist/assets/dropdown-menu-BK-CO3Od.js +1 -0
  72. package/dist/ui/dist/assets/es-NQNoaWDx.js +1 -0
  73. package/dist/ui/dist/assets/external-link-BvxYeTP1.js +1 -0
  74. package/dist/ui/dist/assets/eye-DqNTU_GD.js +1 -0
  75. package/dist/ui/dist/assets/file-text-BT_9S9SM.js +1 -0
  76. package/dist/ui/dist/assets/folder-open-BhH8y9ac.js +1 -0
  77. package/dist/ui/dist/assets/format-GVHeOyWI.js +1 -0
  78. package/dist/ui/dist/assets/gateway-url-COCbW0IR.js +1 -0
  79. package/dist/ui/dist/assets/gauge-D_TMa4i9.js +1 -0
  80. package/dist/ui/dist/assets/globe-DeCQTCDJ.js +1 -0
  81. package/dist/ui/dist/assets/hexagon-DsGOUl-H.js +1 -0
  82. package/dist/ui/dist/assets/history-BSG-Ypqf.js +1 -0
  83. package/dist/ui/dist/assets/index-B2fCYtTS.css +2 -0
  84. package/dist/ui/dist/assets/index-DMCjjdqf.js +116 -0
  85. package/dist/ui/dist/assets/info-NwLoa2Mj.js +1 -0
  86. package/dist/ui/dist/assets/key-3EP0dhkT.js +1 -0
  87. package/dist/ui/dist/assets/label-D2H1IR_J.js +1 -0
  88. package/dist/ui/dist/assets/loader-circle-CZNax6kS.js +1 -0
  89. package/dist/ui/dist/assets/lock-Ei1_J-Nq.js +1 -0
  90. package/dist/ui/dist/assets/pause-BUqah9Bi.js +1 -0
  91. package/dist/ui/dist/assets/play-NcZ4swwL.js +1 -0
  92. package/dist/ui/dist/assets/plus-CX1xyhp5.js +1 -0
  93. package/dist/ui/dist/assets/progress-BherYzY6.js +1 -0
  94. package/dist/ui/dist/assets/refresh-cw-DaYdjQFk.js +1 -0
  95. package/dist/ui/dist/assets/rolldown-runtime-S-ySWqyJ.js +1 -0
  96. package/dist/ui/dist/assets/save-CUdYyHNy.js +1 -0
  97. package/dist/ui/dist/assets/scroll-area-DkeyX32e.js +1 -0
  98. package/dist/ui/dist/assets/send-B0H5SEIE.js +1 -0
  99. package/dist/ui/dist/assets/settings-Ds4SqD8s.js +1 -0
  100. package/dist/ui/dist/assets/slider-CsiUDxc3.js +14 -0
  101. package/dist/ui/dist/assets/sparkles-yUEb-7oH.js +1 -0
  102. package/dist/ui/dist/assets/square-BD81nFtN.js +1 -0
  103. package/dist/ui/dist/assets/switch-BDwN8RYV.js +1 -0
  104. package/dist/ui/dist/assets/table-CSc8ubon.js +1 -0
  105. package/dist/ui/dist/assets/terminal-DN38Q456.js +1 -0
  106. package/dist/ui/dist/assets/textarea-CXgXWKrT.js +1 -0
  107. package/dist/ui/dist/assets/trash-2-CNjMkoq6.js +1 -0
  108. package/dist/ui/dist/assets/triangle-alert-C9Y8Ub4X.js +1 -0
  109. package/dist/ui/dist/assets/useProviders-C6_QHsEi.js +1 -0
  110. package/dist/ui/dist/assets/utils-3pnRFmFe.js +1 -0
  111. package/dist/ui/dist/assets/vendor-charts-Bu2lyBKP.js +65 -0
  112. package/dist/ui/dist/assets/vendor-query-DsWPbQdG.js +1 -0
  113. package/dist/ui/dist/assets/vendor-radix-cw1bQaVC.js +63 -0
  114. package/dist/ui/dist/assets/vendor-react-D4s9E-zj.js +1 -0
  115. package/dist/ui/dist/assets/vendor-router-C9pIYwbJ.js +3 -0
  116. package/dist/ui/dist/assets/volume-2-CeSXNDv4.js +1 -0
  117. package/dist/ui/dist/assets/zap-hlXjpSeA.js +1 -0
  118. package/dist/ui/dist/favicon.ico +0 -0
  119. package/dist/ui/dist/index.html +40 -0
  120. package/dist/ui/dist/placeholder.svg +1 -0
  121. package/dist/ui/index.html +6 -6
  122. package/package.json +137 -13
  123. package/packages/cli/src/adapters/binary.ts +461 -0
  124. package/packages/cli/src/adapters/bun-global.ts +378 -0
  125. package/packages/cli/src/adapters/config.ts +314 -0
  126. package/packages/cli/src/adapters/docker.ts +308 -0
  127. package/packages/cli/src/adapters/factory.ts +168 -0
  128. package/packages/cli/src/adapters/index.ts +80 -0
  129. package/packages/cli/src/adapters/types.ts +218 -0
  130. package/packages/cli/src/commands/agent-run.ts +168 -0
  131. package/packages/cli/src/commands/agents.ts +398 -0
  132. package/packages/cli/src/commands/chat.ts +142 -0
  133. package/packages/cli/src/commands/config.ts +49 -0
  134. package/packages/cli/src/commands/cron.ts +487 -0
  135. package/packages/cli/src/commands/dev.ts +58 -0
  136. package/packages/cli/src/commands/doctor.ts +320 -0
  137. package/packages/cli/src/commands/gateway.ts +719 -0
  138. package/packages/cli/src/commands/logs.ts +57 -0
  139. package/packages/cli/src/commands/mcp.ts +175 -0
  140. package/packages/cli/src/commands/message.ts +77 -0
  141. package/packages/cli/src/commands/migrate.ts +90 -0
  142. package/packages/cli/src/commands/onboard.ts +1656 -0
  143. package/packages/cli/src/commands/security.ts +144 -0
  144. package/packages/cli/src/commands/service.ts +50 -0
  145. package/packages/cli/src/commands/sessions.ts +116 -0
  146. package/packages/cli/src/commands/skills.ts +215 -0
  147. package/packages/cli/src/commands/update.ts +203 -0
  148. package/packages/cli/src/index.ts +210 -0
  149. package/packages/cli/src/ui-bundle.generated.ts +3 -0
  150. package/packages/cli/src/utils/token.ts +6 -0
  151. package/packages/core/src/agent/agent-loop.ts +691 -0
  152. package/packages/core/src/agent/compaction.ts +240 -0
  153. package/packages/core/src/agent/context-compiler.ts +467 -0
  154. package/packages/core/src/agent/context-guard.ts +91 -0
  155. package/packages/core/src/agent/conversation-store.ts +244 -0
  156. package/packages/core/src/agent/curator.ts +158 -0
  157. package/packages/core/src/agent/hooks.ts +166 -0
  158. package/packages/core/src/agent/llm-client.ts +167 -0
  159. package/packages/core/src/agent/llm-providers/anthropic.ts +212 -0
  160. package/packages/core/src/agent/llm-providers/deepseek.ts +8 -0
  161. package/packages/core/src/agent/llm-providers/gemini.ts +215 -0
  162. package/packages/core/src/agent/llm-providers/groq.ts +5 -0
  163. package/packages/core/src/agent/llm-providers/interface.ts +195 -0
  164. package/packages/core/src/agent/llm-providers/kimi.ts +8 -0
  165. package/packages/core/src/agent/llm-providers/local-llama.ts +37 -0
  166. package/packages/core/src/agent/llm-providers/mistral.ts +5 -0
  167. package/packages/core/src/agent/llm-providers/nvidia.ts +5 -0
  168. package/packages/core/src/agent/llm-providers/ollama.ts +175 -0
  169. package/packages/core/src/agent/llm-providers/openai-compat-base.ts +379 -0
  170. package/packages/core/src/agent/llm-providers/openai.ts +5 -0
  171. package/packages/core/src/agent/llm-providers/openrouter.ts +5 -0
  172. package/packages/core/src/agent/llm-providers/qwen.ts +5 -0
  173. package/packages/core/src/agent/native-tools.ts +31 -0
  174. package/packages/core/src/agent/playbook-selector.ts +147 -0
  175. package/packages/core/src/agent/prompt-builder.ts +169 -0
  176. package/packages/core/src/agent/providers/index.ts +204 -0
  177. package/packages/core/src/agent/providers.ts +1 -0
  178. package/packages/core/src/agent/reflector.ts +200 -0
  179. package/packages/core/src/agent/service.ts +267 -0
  180. package/packages/core/src/agent/skill-selector.ts +479 -0
  181. package/packages/core/src/agent/stuck-loop.ts +133 -0
  182. package/packages/core/src/agent/tool-selector.ts +569 -0
  183. package/packages/core/src/agent/tracer.ts +100 -0
  184. package/packages/core/src/auth/auth.ts +108 -0
  185. package/packages/core/src/auth/index.ts +1 -0
  186. package/packages/core/src/canvas/a2ui-tools.ts +255 -0
  187. package/packages/core/src/canvas/canvas-manager.ts +390 -0
  188. package/packages/core/src/canvas/canvas-tools.ts +448 -0
  189. package/packages/core/src/canvas/emitter.ts +149 -0
  190. package/packages/core/src/canvas/index.ts +3 -0
  191. package/packages/core/src/channels/base.ts +154 -0
  192. package/packages/core/src/channels/discord.ts +273 -0
  193. package/packages/core/src/channels/index.ts +7 -0
  194. package/packages/core/src/channels/manager.ts +450 -0
  195. package/packages/core/src/channels/slack.ts +323 -0
  196. package/packages/core/src/channels/telegram.ts +612 -0
  197. package/packages/core/src/channels/webchat.ts +139 -0
  198. package/packages/core/src/channels/whatsapp.ts +548 -0
  199. package/packages/core/src/config/index.ts +12 -0
  200. package/packages/core/src/config/loader.ts +569 -0
  201. package/packages/core/src/events/agent-bus.ts +460 -0
  202. package/packages/core/src/events/event-bus.ts +169 -0
  203. package/packages/core/src/gateway/channel-notify.ts +64 -0
  204. package/packages/core/src/gateway/helpers/cors.ts +32 -0
  205. package/packages/core/src/gateway/helpers/index.ts +4 -0
  206. package/packages/core/src/gateway/helpers/narration.ts +57 -0
  207. package/packages/core/src/gateway/helpers/path.ts +13 -0
  208. package/packages/core/src/gateway/helpers/redact.ts +61 -0
  209. package/packages/core/src/gateway/index.ts +5 -0
  210. package/packages/core/src/gateway/initializer.ts +363 -0
  211. package/packages/core/src/gateway/lane-queue.ts +169 -0
  212. package/packages/core/src/gateway/llm-local/client.ts +94 -0
  213. package/packages/core/src/gateway/llm-local/detector.ts +321 -0
  214. package/packages/core/src/gateway/llm-local/downloader.ts +216 -0
  215. package/packages/core/src/gateway/llm-local/index.ts +34 -0
  216. package/packages/core/src/gateway/llm-local/manager.ts +186 -0
  217. package/packages/core/src/gateway/llm-local/models.ts +149 -0
  218. package/packages/core/src/gateway/llm-local/server.ts +179 -0
  219. package/packages/core/src/gateway/resolver.ts +108 -0
  220. package/packages/core/src/gateway/router.ts +124 -0
  221. package/packages/core/src/gateway/routes/agents.ts +210 -0
  222. package/packages/core/src/gateway/routes/auth.ts +244 -0
  223. package/packages/core/src/gateway/routes/channels.ts +484 -0
  224. package/packages/core/src/gateway/routes/chat.ts +241 -0
  225. package/packages/core/src/gateway/routes/config.ts +12 -0
  226. package/packages/core/src/gateway/routes/cron-api.ts +544 -0
  227. package/packages/core/src/gateway/routes/ethics.ts +46 -0
  228. package/packages/core/src/gateway/routes/llm-local.ts +271 -0
  229. package/packages/core/src/gateway/routes/mcp.ts +319 -0
  230. package/packages/core/src/gateway/routes/meeting.ts +232 -0
  231. package/packages/core/src/gateway/routes/models.ts +163 -0
  232. package/packages/core/src/gateway/routes/multimodal.ts +93 -0
  233. package/packages/core/src/gateway/routes/providers.ts +220 -0
  234. package/packages/core/src/gateway/routes/setup.ts +441 -0
  235. package/packages/core/src/gateway/routes/skills.ts +115 -0
  236. package/packages/core/src/gateway/routes/system.ts +469 -0
  237. package/packages/core/src/gateway/routes/tasks.ts +44 -0
  238. package/packages/core/src/gateway/routes/tools.ts +59 -0
  239. package/packages/core/src/gateway/routes/tts-local.ts +388 -0
  240. package/packages/core/src/gateway/routes/users.ts +122 -0
  241. package/packages/core/src/gateway/routes/voice.ts +189 -0
  242. package/packages/core/src/gateway/routes/workspace.ts +281 -0
  243. package/packages/core/src/gateway/server.ts +2744 -0
  244. package/packages/core/src/gateway/session.ts +95 -0
  245. package/packages/core/src/gateway/slash-commands.ts +207 -0
  246. package/packages/core/src/gateway/tts/README.md +94 -0
  247. package/packages/core/src/gateway/tts/package.json +25 -0
  248. package/packages/core/src/gateway/tts/src/client.ts +59 -0
  249. package/packages/core/src/gateway/tts/src/detect.ts +42 -0
  250. package/packages/core/src/gateway/tts/src/index.ts +15 -0
  251. package/packages/core/src/gateway/tts/src/install.ts +129 -0
  252. package/packages/core/src/gateway/tts/src/models.ts +50 -0
  253. package/packages/core/src/gateway/tts/src/server.ts +252 -0
  254. package/packages/core/src/gateway/tts/voices/.gitkeep +0 -0
  255. package/packages/core/src/heartbeat/index.ts +157 -0
  256. package/packages/core/src/index.ts +56 -0
  257. package/packages/core/src/mcp/hot-reload.ts +148 -0
  258. package/packages/core/src/mcp/singleton.ts +21 -0
  259. package/packages/core/src/mcp/tool-sync.ts +176 -0
  260. package/packages/core/src/multimodal/index.ts +2 -0
  261. package/packages/core/src/multimodal/types.ts +28 -0
  262. package/packages/core/src/multimodal/vision-service.ts +283 -0
  263. package/packages/core/src/plugins/api.ts +128 -0
  264. package/packages/core/src/plugins/index.ts +2 -0
  265. package/packages/core/src/plugins/loader.ts +365 -0
  266. package/packages/core/src/resilience/circuit-breaker.ts +225 -0
  267. package/packages/core/src/scheduler/CronScheduler.ts +699 -0
  268. package/packages/core/src/scheduler/dag/AgentExecutor.ts +53 -0
  269. package/packages/core/src/scheduler/dag/DAGScheduler.ts +250 -0
  270. package/packages/core/src/scheduler/dag/EventBridge.ts +122 -0
  271. package/packages/core/src/scheduler/dag/TaskGraph.ts +192 -0
  272. package/packages/core/src/scheduler/dag/TaskNode.ts +97 -0
  273. package/packages/core/src/scheduler/dag/TaskResult.ts +22 -0
  274. package/packages/core/src/scheduler/dag/errors.ts +37 -0
  275. package/packages/core/src/scheduler/dag/index.ts +26 -0
  276. package/packages/core/src/scheduler/dag/presets/ResearchPreset.ts +97 -0
  277. package/packages/core/src/scheduler/dag/strategies/ParallelStrategy.ts +21 -0
  278. package/packages/core/src/scheduler/dag/strategies/PriorityStrategy.ts +46 -0
  279. package/packages/core/src/scheduler/index.ts +22 -0
  280. package/packages/core/src/scheduler/integration.ts +237 -0
  281. package/packages/core/src/scheduler/types.ts +164 -0
  282. package/packages/core/src/security/google-chat.ts +269 -0
  283. package/packages/core/src/security/index.ts +192 -0
  284. package/packages/core/src/security/pairing.ts +250 -0
  285. package/packages/core/src/security/rate-limit.ts +270 -0
  286. package/packages/core/src/security/signal.ts +321 -0
  287. package/packages/core/src/state/store.ts +312 -0
  288. package/packages/core/src/storage/crypto.ts +197 -0
  289. package/packages/core/src/storage/migrate.ts +147 -0
  290. package/packages/core/src/storage/onboarding.ts +1506 -0
  291. package/packages/core/src/storage/schema.ts +666 -0
  292. package/packages/core/src/storage/seed.ts +628 -0
  293. package/packages/core/src/storage/sqlite.ts +407 -0
  294. package/packages/core/src/storage/usage.ts +374 -0
  295. package/packages/core/src/tool-runtime/index.ts +476 -0
  296. package/packages/core/src/tool-runtime/tool-worker.ts +125 -0
  297. package/packages/core/src/tools/agents/get-available-models.ts +118 -0
  298. package/packages/core/src/tools/agents/index.ts +610 -0
  299. package/packages/core/src/tools/canvas/index.ts +420 -0
  300. package/packages/core/src/tools/cli/index.ts +142 -0
  301. package/packages/core/src/tools/core/index.ts +478 -0
  302. package/packages/core/src/tools/cron/index.ts +635 -0
  303. package/packages/core/src/tools/filesystem/fs-delete.ts +78 -0
  304. package/packages/core/src/tools/filesystem/fs-edit.ts +106 -0
  305. package/packages/core/src/tools/filesystem/fs-exists.ts +63 -0
  306. package/packages/core/src/tools/filesystem/fs-glob.ts +108 -0
  307. package/packages/core/src/tools/filesystem/fs-list.ts +129 -0
  308. package/packages/core/src/tools/filesystem/fs-read.ts +72 -0
  309. package/packages/core/src/tools/filesystem/fs-write.ts +67 -0
  310. package/packages/core/src/tools/filesystem/index.ts +34 -0
  311. package/packages/core/src/tools/filesystem/workspace-guard.ts +62 -0
  312. package/packages/core/src/tools/index.ts +197 -0
  313. package/packages/core/src/tools/meeting/index.ts +363 -0
  314. package/packages/core/src/tools/office/index.ts +47 -0
  315. package/packages/core/src/tools/office/office-escribir-docx.ts +192 -0
  316. package/packages/core/src/tools/office/office-escribir-pdf.ts +172 -0
  317. package/packages/core/src/tools/office/office-escribir-pptx.ts +174 -0
  318. package/packages/core/src/tools/office/office-escribir-xlsx.ts +116 -0
  319. package/packages/core/src/tools/office/office-leer-docx.ts +93 -0
  320. package/packages/core/src/tools/office/office-leer-pdf.ts +114 -0
  321. package/packages/core/src/tools/office/office-leer-pptx.ts +136 -0
  322. package/packages/core/src/tools/office/office-leer-xlsx.ts +124 -0
  323. package/packages/core/src/tools/types.ts +39 -0
  324. package/packages/core/src/tools/voice/index.ts +104 -0
  325. package/packages/core/src/tools/web/browser-click.ts +78 -0
  326. package/packages/core/src/tools/web/browser-extract.ts +139 -0
  327. package/packages/core/src/tools/web/browser-navigate.ts +106 -0
  328. package/packages/core/src/tools/web/browser-screenshot.ts +87 -0
  329. package/packages/core/src/tools/web/browser-script.ts +88 -0
  330. package/packages/core/src/tools/web/browser-service.ts +554 -0
  331. package/packages/core/src/tools/web/browser-type.ts +101 -0
  332. package/packages/core/src/tools/web/browser-wait.ts +136 -0
  333. package/packages/core/src/tools/web/index.ts +41 -0
  334. package/packages/core/src/tools/web/web-fetch.ts +78 -0
  335. package/packages/core/src/tools/web/web-search.ts +123 -0
  336. package/packages/core/src/utils/benchmark.ts +80 -0
  337. package/packages/core/src/utils/crypto.ts +73 -0
  338. package/packages/core/src/utils/date.ts +42 -0
  339. package/packages/core/src/utils/index.ts +5 -0
  340. package/packages/core/src/utils/logger.ts +389 -0
  341. package/packages/core/src/utils/retry.ts +70 -0
  342. package/packages/core/src/utils/toon.ts +253 -0
  343. package/packages/core/src/voice/index.ts +643 -0
  344. package/packages/mcp/src/config.ts +13 -0
  345. package/packages/mcp/src/index.ts +1 -0
  346. package/packages/mcp/src/logger.ts +47 -0
  347. package/packages/mcp/src/manager.ts +439 -0
  348. package/packages/mcp/src/transports/index.ts +67 -0
  349. package/packages/mcp/src/transports/sse.ts +238 -0
  350. package/packages/mcp/src/transports/websocket.ts +159 -0
  351. package/packages/skills/src/bundled/agents/agent_spawner/SKILL.md +167 -0
  352. package/packages/skills/src/bundled/agents/code_delegator/SKILL.md +156 -0
  353. package/packages/skills/src/bundled/agents/memory_manager/SKILL.md +143 -0
  354. package/packages/skills/src/bundled/agents/research_and_remember/SKILL.md +139 -0
  355. package/packages/skills/src/bundled/agents/task_orchestrator/SKILL.md +198 -0
  356. package/packages/skills/src/bundled/canvas/a2ui_dashboard/SKILL.md +176 -0
  357. package/packages/skills/src/bundled/canvas/a2ui_form/SKILL.md +202 -0
  358. package/packages/skills/src/bundled/canvas/a2ui_interactive/SKILL.md +206 -0
  359. package/packages/skills/src/bundled/canvas/canvas_dashboard/SKILL.md +146 -0
  360. package/packages/skills/src/bundled/canvas/canvas_interact/SKILL.md +148 -0
  361. package/packages/skills/src/bundled/canvas/canvas_report/SKILL.md +146 -0
  362. package/packages/skills/src/bundled/cli/cli_pipeline/SKILL.md +136 -0
  363. package/packages/skills/src/bundled/cli/cli_safe_exec/SKILL.md +125 -0
  364. package/packages/skills/src/bundled/cron_manager/SKILL.md +188 -0
  365. package/packages/skills/src/bundled/cron_reminder/SKILL.md +112 -0
  366. package/packages/skills/src/bundled/filesystem/file_manager/SKILL.md +118 -0
  367. package/packages/skills/src/bundled/filesystem/file_read_and_summarize/SKILL.md +108 -0
  368. package/packages/skills/src/bundled/filesystem/file_writer/SKILL.md +135 -0
  369. package/packages/skills/src/bundled/meeting/meeting_transcription/SKILL.md +213 -0
  370. package/packages/skills/src/bundled/office/office_document_manager/SKILL.md +262 -0
  371. package/packages/skills/src/bundled/search_knowledge/busqueda_fts5/SKILL.md +74 -0
  372. package/packages/skills/src/bundled/voice/voice_assistant/SKILL.md +174 -0
  373. package/packages/skills/src/bundled/voice/voice_input/SKILL.md +146 -0
  374. package/packages/skills/src/bundled/voice/voice_output/SKILL.md +151 -0
  375. package/packages/skills/src/bundled/web/browser_automate/SKILL.md +120 -0
  376. package/packages/skills/src/bundled/web/browser_scrape/SKILL.md +109 -0
  377. package/packages/skills/src/bundled/web/web_monitor/SKILL.md +127 -0
  378. package/packages/skills/src/bundled/web/web_research/SKILL.md +119 -0
  379. package/packages/skills/src/bundled-data.generated.ts +1964 -0
  380. package/packages/skills/src/index.ts +1 -0
  381. package/packages/skills/src/loader.ts +388 -0
  382. package/dist/ui/assets/AgentNewPage-GB-tVN50.js +0 -1
  383. package/dist/ui/assets/BridgePage-DDcDILKu.js +0 -1
  384. package/dist/ui/assets/CanvasPage-oOk2sGOD.js +0 -33
  385. package/dist/ui/assets/DashboardPage-DV_2qWYJ.js +0 -6
  386. package/dist/ui/assets/LogsPage-DayYjh01.js +0 -1
  387. package/dist/ui/assets/MeetingPage-C01uPuqj.js +0 -1
  388. package/dist/ui/assets/ProjectsPage-B8_am_Ib.js +0 -1
  389. package/dist/ui/assets/ProvidersPage-DBzi66e4.js +0 -1
  390. package/dist/ui/assets/SettingsPage-CFA_Tknl.js +0 -9
  391. package/dist/ui/assets/SetupPage-BrUWbhvT.js +0 -1
  392. package/dist/ui/assets/accordion-DdAEfIXR.js +0 -1
  393. package/dist/ui/assets/chevron-down-DIosfU_U.js +0 -1
  394. package/dist/ui/assets/chevron-up-CI-W21Fy.js +0 -1
  395. package/dist/ui/assets/circle-S0-ouLz-.js +0 -1
  396. package/dist/ui/assets/circle-minus-CE0iJrl8.js +0 -1
  397. package/dist/ui/assets/circle-x-jUJ5zZvQ.js +0 -1
  398. package/dist/ui/assets/dropdown-menu-C2CXM1VE.js +0 -1
  399. package/dist/ui/assets/index-BN0875JH.css +0 -2
  400. package/dist/ui/assets/index-CH6sBa3Q.js +0 -116
  401. package/dist/ui/assets/pencil-5VdSj-h5.js +0 -1
  402. package/dist/ui/assets/progress-JN30I5fF.js +0 -1
  403. package/dist/ui/assets/scroll-area-BQQPitM8.js +0 -1
  404. package/dist/ui/assets/search-ChPgnVKj.js +0 -1
  405. package/dist/ui/assets/switch-C7W2-KEx.js +0 -1
  406. package/dist/ui/assets/terminal-C-R5Fckz.js +0 -1
  407. package/dist/ui/assets/useProviders-TBnWn-Hq.js +0 -1
  408. /package/dist/ui/assets/{card-DFKnZ6ky.js → card-CNf6BS2e.js} +0 -0
  409. /package/dist/ui/assets/{circle-alert-KuAm2FWh.js → circle-alert-CyHDwUj8.js} +0 -0
  410. /package/dist/ui/assets/{circle-check-6Ard1-2z.js → circle-check-Bb54Ebmu.js} +0 -0
  411. /package/dist/ui/assets/{cpu-KDy6-FAI.js → cpu-Cdgc_B1K.js} +0 -0
  412. /package/dist/ui/assets/{download-Cjbk4Rek.js → download-C3ifGMjJ.js} +0 -0
  413. /package/dist/ui/assets/{external-link-HtrFM63g.js → external-link-BvxYeTP1.js} +0 -0
  414. /package/dist/ui/assets/{eye-D1dB40_o.js → eye-DqNTU_GD.js} +0 -0
  415. /package/dist/ui/assets/{file-text-CE58EfH0.js → file-text-BT_9S9SM.js} +0 -0
  416. /package/dist/ui/assets/{folder-open-DIPKeiI_.js → folder-open-BhH8y9ac.js} +0 -0
  417. /package/dist/ui/assets/{format-BwdV8bB5.js → format-GVHeOyWI.js} +0 -0
  418. /package/dist/ui/assets/{gateway-url-D5uj6Nxg.js → gateway-url-COCbW0IR.js} +0 -0
  419. /package/dist/ui/assets/{gauge-DmQmJHEg.js → gauge-D_TMa4i9.js} +0 -0
  420. /package/dist/ui/assets/{globe-_hUGxQF4.js → globe-DeCQTCDJ.js} +0 -0
  421. /package/dist/ui/assets/{hexagon-BaNGQlQj.js → hexagon-DsGOUl-H.js} +0 -0
  422. /package/dist/ui/assets/{history-BfZVGlZa.js → history-BSG-Ypqf.js} +0 -0
  423. /package/dist/ui/assets/{info-CBZ5-AlC.js → info-NwLoa2Mj.js} +0 -0
  424. /package/dist/ui/assets/{key-Bv5DdTPh.js → key-3EP0dhkT.js} +0 -0
  425. /package/dist/ui/assets/{loader-circle-C4hhXLgp.js → loader-circle-CZNax6kS.js} +0 -0
  426. /package/dist/ui/assets/{lock-CkZYexqw.js → lock-Ei1_J-Nq.js} +0 -0
  427. /package/dist/ui/assets/{pause-Bpy1_s7y.js → pause-BUqah9Bi.js} +0 -0
  428. /package/dist/ui/assets/{play-Cj4osqJZ.js → play-NcZ4swwL.js} +0 -0
  429. /package/dist/ui/assets/{plus-BQhgZN3A.js → plus-CX1xyhp5.js} +0 -0
  430. /package/dist/ui/assets/{refresh-cw-BfREHVQM.js → refresh-cw-DaYdjQFk.js} +0 -0
  431. /package/dist/ui/assets/{save-FFTD4dMp.js → save-CUdYyHNy.js} +0 -0
  432. /package/dist/ui/assets/{settings-BdHKUL92.js → settings-Ds4SqD8s.js} +0 -0
  433. /package/dist/ui/assets/{sparkles-r4uJbJAl.js → sparkles-yUEb-7oH.js} +0 -0
  434. /package/dist/ui/assets/{square-G7Hyufqm.js → square-BD81nFtN.js} +0 -0
  435. /package/dist/ui/assets/{textarea-5kyuD04X.js → textarea-CXgXWKrT.js} +0 -0
  436. /package/dist/ui/assets/{trash-2-DXVBRWfh.js → trash-2-CNjMkoq6.js} +0 -0
  437. /package/dist/ui/assets/{triangle-alert-Bu5seg9O.js → triangle-alert-C9Y8Ub4X.js} +0 -0
  438. /package/dist/ui/assets/{vendor-router-CCECILJ0.js → vendor-router-C9pIYwbJ.js} +0 -0
  439. /package/dist/ui/assets/{volume-2-s9DuS696.js → volume-2-CeSXNDv4.js} +0 -0
  440. /package/dist/ui/assets/{zap-BPHZzXKV.js → zap-hlXjpSeA.js} +0 -0
@@ -0,0 +1,612 @@
1
+ import { Bot, GrammyError, InputFile, type Context } from "grammy";
2
+ import { BaseChannel, type ChannelConfig, type IncomingMessage, type OutboundMessage } from "./base.ts";
3
+ import { logger } from "../utils/logger.ts";
4
+ import { getDb } from "../storage/sqlite.ts";
5
+
6
+ export interface TelegramConfig extends ChannelConfig {
7
+ botToken: string;
8
+ groups?: boolean;
9
+ }
10
+
11
+ export class TelegramChannel extends BaseChannel {
12
+ name = "telegram";
13
+ accountId: string;
14
+ config: TelegramConfig;
15
+
16
+ private bot?: Bot;
17
+ private log = logger.child("telegram");
18
+ private chatIdCache: Map<string, number> = new Map();
19
+ private messageIdCache: Map<string, number> = new Map();
20
+ // Deduplication: records recently processed message_ids to avoid double sends
21
+ private recentlyProcessed: Map<number, number> = new Map();
22
+
23
+ constructor(accountId: string, config: TelegramConfig) {
24
+ super();
25
+ this.accountId = accountId;
26
+ this.config = {
27
+ ...config,
28
+ dmPolicy: config.dmPolicy ?? "open",
29
+ allowFrom: config.allowFrom ?? [],
30
+ enabled: config.enabled ?? true,
31
+ };
32
+ }
33
+
34
+ async start(): Promise<void> {
35
+ if (this.running) {
36
+ this.log.warn("Telegram bot is already running, skipping start");
37
+ return;
38
+ }
39
+
40
+ if (!this.config.botToken) {
41
+ throw new Error("Telegram bot token not configured");
42
+ }
43
+
44
+ this.bot = new Bot(this.config.botToken);
45
+
46
+ this.bot.on("message", async (ctx: Context) => {
47
+ await this.handleTelegramMessage(ctx);
48
+ });
49
+
50
+ // Note: edited_message intentionally NOT handled — editing a message
51
+ // should not trigger a new agent response (was causing double sends).
52
+
53
+ this.bot.catch((err: Error) => {
54
+ this.log.error(`Telegram error: ${err.message}`);
55
+ });
56
+
57
+ this.bot.start({
58
+ onStart: () => {
59
+ this.running = true;
60
+ this.log.info(`Telegram bot started: @${this.bot?.botInfo?.username ?? "unknown"}`);
61
+ try {
62
+ getDb().query(`UPDATE channels SET status = 'connected' WHERE id = ?`).run(this.accountId);
63
+ } catch { /* ignore DB errors */ }
64
+ },
65
+ }).catch((error: Error) => {
66
+ this.log.error(`Telegram bot error: ${error.message}`);
67
+ this.running = false;
68
+ try {
69
+ getDb().query(`UPDATE channels SET status = 'error' WHERE id = ?`).run(this.accountId);
70
+ } catch { /* ignore DB errors */ }
71
+ });
72
+ }
73
+
74
+ private async handleTelegramMessage(ctx: Context): Promise<void> {
75
+ const message = ctx.message;
76
+ if (!message) return;
77
+
78
+ const chatId = message.chat.id.toString();
79
+ const userId = message.from?.id?.toString() ?? "unknown";
80
+ const isGroup = message.chat.type === "group" || message.chat.type === "supergroup";
81
+ const kind = isGroup ? "group" : "direct";
82
+ const peerId = isGroup
83
+ ? `${message.chat.id}:${message.from?.id ?? "unknown"}`
84
+ : chatId;
85
+ const messageId = message.message_id;
86
+
87
+ if (message.from?.is_bot) {
88
+ return;
89
+ }
90
+
91
+ // Deduplication: ignore message_ids already processed in the last 60 seconds
92
+ const now = Date.now();
93
+ if (this.recentlyProcessed.has(messageId)) {
94
+ this.log.debug(`Duplicate message_id ${messageId} ignored`);
95
+ return;
96
+ }
97
+ this.recentlyProcessed.set(messageId, now);
98
+ // Clean up old entries (> 60s) to prevent unbounded growth
99
+ for (const [id, ts] of this.recentlyProcessed) {
100
+ if (now - ts > 60_000) this.recentlyProcessed.delete(id);
101
+ }
102
+
103
+ const text = message.text;
104
+ const isCommand = text?.startsWith("/") ?? false;
105
+
106
+ if (text === "/myid" || text?.startsWith("/myid@")) {
107
+ await ctx.reply(
108
+ `🆔 Tu Telegram ID es: <code>${userId}</code>\n\n` +
109
+ `Para autorizarte, ejecuta:\n` +
110
+ `<code>hive config set channels.telegram.accounts.default.allowFrom.+ "tg:${userId}"</code>`,
111
+ { parse_mode: "HTML" }
112
+ );
113
+ return;
114
+ }
115
+
116
+ if (text === "/start" || text?.startsWith("/start@")) {
117
+ const agentName = "Bee";
118
+ await ctx.reply(
119
+ `¡Hola! Soy ${agentName}, tu asistente personal.\n\n` +
120
+ `Tu Telegram ID: <code>${userId}</code>\n\n` +
121
+ `Para empezar a usar el bot, asegúrate de estar autorizado.`,
122
+ { parse_mode: "HTML" }
123
+ );
124
+ return;
125
+ }
126
+
127
+ if (text === "/help" || text?.startsWith("/help@")) {
128
+ await ctx.reply(this.getHelpMessage(userId), { parse_mode: "HTML" });
129
+ return;
130
+ }
131
+
132
+ if (text === "/stop" || text?.startsWith("/stop@")) {
133
+ await ctx.reply("⏹ Detención actual cancelada.", { parse_mode: "HTML" });
134
+ return;
135
+ }
136
+
137
+ if (text === "/new" || text?.startsWith("/new@")) {
138
+ await ctx.reply("🔄 Sesión reiniciada.", { parse_mode: "HTML" });
139
+ return;
140
+ }
141
+
142
+ if (!isGroup && !this.isUserAllowed(chatId)) {
143
+ this.log.debug(`Message from unauthorized user: ${chatId}`);
144
+ const rejectMsg = this.config.dmPolicy === "allowlist"
145
+ ? `⛔ No estás autorizado.\n\n` +
146
+ `Tu Telegram ID: <code>${userId}</code>\n\n` +
147
+ `Para autorizarte:\n` +
148
+ `1. Ejecuta en el servidor: <code>hive config edit</code>\n` +
149
+ `2. Añade bajo channels.telegram.accounts.default.allowFrom:\n` +
150
+ `<pre> - "tg:${userId}"</pre>\n` +
151
+ `3. Ejecuta: <code>hive reload</code>`
152
+ : `⛔ No estás autorizado para usar este bot.\n\n` +
153
+ `Tu Telegram ID: <code>${userId}</code>`;
154
+ await ctx.reply(rejectMsg, { parse_mode: "HTML" });
155
+ return;
156
+ }
157
+
158
+ if (isGroup && !(this.config.groups ?? false)) {
159
+ return;
160
+ }
161
+
162
+ let content = text;
163
+ let contentType = "text";
164
+ let image: IncomingMessage["image"];
165
+ let document_: IncomingMessage["document"];
166
+
167
+ if (message.photo && !text) {
168
+ const caption = message.caption ?? "";
169
+ contentType = "photo";
170
+ try {
171
+ const photos = message.photo;
172
+ const largest = photos[photos.length - 1];
173
+ if (largest && this.bot) {
174
+ const file = await this.bot.api.getFile(largest.file_id);
175
+ if (file.file_path) {
176
+ image = {
177
+ url: `https://api.telegram.org/file/bot${this.config.botToken}/${file.file_path}`,
178
+ mimeType: "image/jpeg",
179
+ caption: caption || undefined,
180
+ };
181
+ }
182
+ }
183
+ } catch (err) {
184
+ this.log.warn(`Failed to download photo: ${(err as Error).message}`);
185
+ }
186
+ content = caption || "";
187
+ }
188
+
189
+ if (message.voice) {
190
+ const voice = message.voice;
191
+ const fileId = voice.file_id;
192
+
193
+ let audioBuffer: Buffer | undefined;
194
+ let audioUrl: string | undefined;
195
+
196
+ try {
197
+ const file = await this.bot!.api.getFile(fileId);
198
+ const filePath = file.file_path;
199
+ if (filePath) {
200
+ audioUrl = `https://api.telegram.org/file/bot${this.config.botToken}/${filePath}`;
201
+ }
202
+ } catch (error) {
203
+ this.log.error(`Failed to get voice file: ${(error as Error).message}`);
204
+ }
205
+
206
+ const msgSessionId = this.formatSessionId(peerId, kind);
207
+
208
+ const incomingMessage: IncomingMessage = {
209
+ sessionId: msgSessionId,
210
+ channel: "telegram",
211
+ accountId: this.accountId,
212
+ peerId,
213
+ peerKind: kind,
214
+ content: "",
215
+ audio: audioBuffer ? { buffer: audioBuffer } : audioUrl ? { url: audioUrl, mimeType: "audio/ogg" } : undefined,
216
+ metadata: {
217
+ telegram: {
218
+ chatId: message.chat.id,
219
+ userId: message.from?.id,
220
+ username: message.from?.username,
221
+ messageId,
222
+ chatType: message.chat.type,
223
+ contentType: "voice",
224
+ },
225
+ },
226
+ replyToId: message.reply_to_message
227
+ ? `tg:${message.reply_to_message.message_id}`
228
+ : undefined,
229
+ };
230
+
231
+ await this.handleMessage(incomingMessage);
232
+ return;
233
+ }
234
+
235
+ if (message.sticker) {
236
+ return;
237
+ }
238
+
239
+ if (message.document && !text) {
240
+ const docName = (message.document as any).file_name ?? "documento";
241
+ const caption = message.caption ?? "";
242
+ contentType = "document";
243
+ try {
244
+ if (this.bot) {
245
+ const file = await this.bot.api.getFile(message.document.file_id);
246
+ if (file.file_path) {
247
+ document_ = {
248
+ url: `https://api.telegram.org/file/bot${this.config.botToken}/${file.file_path}`,
249
+ mimeType: message.document.mime_type || "application/octet-stream",
250
+ fileName: docName,
251
+ };
252
+ }
253
+ }
254
+ } catch (err) {
255
+ this.log.warn(`Failed to download document: ${(err as Error).message}`);
256
+ }
257
+ content = caption || "";
258
+ }
259
+
260
+ const sessionId = this.formatSessionId(peerId, kind);
261
+ this.chatIdCache.set(sessionId, message.chat.id);
262
+ this.messageIdCache.set(sessionId, messageId);
263
+
264
+ const incomingMessage: IncomingMessage = {
265
+ sessionId,
266
+ channel: "telegram",
267
+ accountId: this.accountId,
268
+ peerId,
269
+ peerKind: kind,
270
+ content: content ?? "",
271
+ image,
272
+ document: document_,
273
+ metadata: {
274
+ telegram: {
275
+ chatId: message.chat.id,
276
+ userId: message.from?.id,
277
+ username: message.from?.username,
278
+ messageId,
279
+ chatType: message.chat.type,
280
+ contentType,
281
+ },
282
+ },
283
+ replyToId: message.reply_to_message
284
+ ? `tg:${message.reply_to_message.message_id}`
285
+ : undefined,
286
+ };
287
+
288
+ await this.handleMessage(incomingMessage);
289
+ }
290
+
291
+ private getHelpMessage(_userId: string): string {
292
+ return `📚 <b>Comandos disponibles:</b>
293
+
294
+ <code>/myid</code> - Muestra tu Telegram ID
295
+ <code>/start</code> - Iniciar conversación
296
+ <code>/help</code> - Mostrar esta ayuda
297
+ <code>/stop</code> - Detener tarea actual
298
+ <code>/new</code> - Reiniciar sesión
299
+
300
+ 💡 <i>Envía un mensaje para comenzar.</i>`;
301
+ }
302
+
303
+ async stop(): Promise<void> {
304
+ if (this.bot) {
305
+ await this.bot.stop();
306
+ this.running = false;
307
+ this.log.info("Telegram bot stopped");
308
+ try {
309
+ getDb().query(`UPDATE channels SET status = 'disconnected' WHERE id = ?`).run(this.accountId);
310
+ } catch { /* ignore DB errors */ }
311
+ }
312
+ }
313
+
314
+ private getChatIdFromSession(sessionId: string): number {
315
+ const cached = this.chatIdCache.get(sessionId);
316
+ if (cached) return cached;
317
+
318
+ // Group format: "chatId:userId" (e.g. "-1001234567890:123456789")
319
+ // The chat ID is the first segment before the colon.
320
+ const colonIdx = sessionId.indexOf(":");
321
+ if (colonIdx > 0) {
322
+ const parsed = Number(sessionId.slice(0, colonIdx));
323
+ if (!isNaN(parsed) && parsed !== 0) return parsed;
324
+ }
325
+
326
+ // Direct format: sessionId is the raw chatId (e.g. stored in user_identities)
327
+ const direct = Number(sessionId);
328
+ if (!isNaN(direct) && direct !== 0) return direct;
329
+
330
+ return 0;
331
+ }
332
+
333
+ private getMessageIdFromSession(sessionId: string): number | undefined {
334
+ return this.messageIdCache.get(sessionId);
335
+ }
336
+
337
+ async startTyping(sessionId: string): Promise<void> {
338
+ if (!this.bot) return;
339
+
340
+ const chatId = this.getChatIdFromSession(sessionId);
341
+ if (isNaN(chatId)) return;
342
+
343
+ await this.bot.api.sendChatAction(chatId, "typing");
344
+
345
+ const interval = setInterval(async () => {
346
+ try {
347
+ await this.bot!.api.sendChatAction(chatId, "typing");
348
+ } catch {
349
+ this.stopTyping(sessionId);
350
+ }
351
+ }, 4000);
352
+
353
+ this.typingIntervals.set(sessionId, interval);
354
+ }
355
+
356
+ async stopTyping(sessionId: string): Promise<void> {
357
+ const interval = this.typingIntervals.get(sessionId);
358
+ if (interval) {
359
+ clearInterval(interval);
360
+ this.typingIntervals.delete(sessionId);
361
+ }
362
+ }
363
+
364
+ async send(sessionId: string, message: OutboundMessage): Promise<void> {
365
+ if (!this.bot) {
366
+ throw new Error("Telegram bot not started");
367
+ }
368
+
369
+ await this.stopTyping(sessionId);
370
+
371
+ const chatId = this.getChatIdFromSession(sessionId);
372
+
373
+ if (isNaN(chatId)) {
374
+ throw new Error(`Invalid chat ID from session: ${sessionId}`);
375
+ }
376
+
377
+ const content = message.content ?? "";
378
+
379
+ if (!content || content.trim().length === 0) {
380
+ this.log.warn(`Empty response from agent, skipping send`, { sessionId, chatId });
381
+ return;
382
+ }
383
+
384
+ const replyToId = this.getMessageIdFromSession(sessionId);
385
+ const maxLength = 4096;
386
+
387
+ try {
388
+ if (content.length <= maxLength) {
389
+ await this.sendWithRetry(chatId, content, replyToId);
390
+ } else {
391
+ const chunks = this.chunkMessage(content, maxLength);
392
+ for (let i = 0; i < chunks.length; i++) {
393
+ await this.sendWithRetry(chatId, chunks[i]!, i === 0 ? replyToId : undefined);
394
+ if (i < chunks.length - 1) {
395
+ await new Promise((resolve) => setTimeout(resolve, 300));
396
+ }
397
+ }
398
+ }
399
+ } catch (error: unknown) {
400
+ if (error instanceof GrammyError) {
401
+ this.log.error(`Telegram API error: ${error.description}`);
402
+
403
+ if (error.error_code === 403) {
404
+ this.log.warn(`Bot was blocked by user: ${chatId}`);
405
+ return;
406
+ }
407
+ } else if (error instanceof Error) {
408
+ this.log.error(`Telegram send error: ${error.message}`);
409
+ } else {
410
+ this.log.error(`Telegram send error: ${String(error)}`);
411
+ }
412
+ throw error;
413
+ }
414
+ }
415
+
416
+ async sendAudio(sessionId: string, audio: Buffer, mimeType: string): Promise<void> {
417
+ if (!this.bot) {
418
+ throw new Error("Telegram bot not started");
419
+ }
420
+
421
+ const chatId = this.getChatIdFromSession(sessionId);
422
+
423
+ if (isNaN(chatId)) {
424
+ throw new Error(`Invalid chat ID from session: ${sessionId}`);
425
+ }
426
+
427
+ // Retry logic for sendVoice with exponential backoff
428
+ const maxRetries = 2;
429
+ const backoffMs = [3000, 6000];
430
+
431
+ for (let attempt = 0; attempt < maxRetries; attempt++) {
432
+ // Use explicit timeout for sendVoice (30 seconds)
433
+ const controller = new AbortController();
434
+ const timeoutId = setTimeout(() => controller.abort(), 30000);
435
+
436
+ try {
437
+ const inputFile = new InputFile(audio, "voice.ogg");
438
+
439
+ // Use type assertion to bypass grammY type limitations - signal is supported at runtime
440
+ // via the underlying fetch API but not exposed in grammy's type definitions
441
+ await this.bot!.api.sendVoice(chatId, inputFile, {
442
+ signal: controller.signal,
443
+ } as any);
444
+
445
+ this.log.info(`✅ Voice sent to ${chatId}`);
446
+ return;
447
+ } catch (error: unknown) {
448
+ const err = error as Error & { error_code?: number };
449
+
450
+ // Don't retry on client errors (4xx)
451
+ if (err.error_code === 400) {
452
+ this.log.error(`Bad Request: ${err.message}`);
453
+ throw error;
454
+ }
455
+
456
+ if (attempt < maxRetries - 1) {
457
+ this.log.warn(`sendVoice attempt ${attempt + 1} failed, retrying in ${backoffMs[attempt]}ms: ${err.message}`);
458
+ await new Promise(resolve => setTimeout(resolve, backoffMs[attempt]));
459
+ } else {
460
+ this.log.error(`Telegram sendVoice failed after ${maxRetries} attempts: ${err.message}`);
461
+ throw error;
462
+ }
463
+ } finally {
464
+ // Always clear the timeout to prevent resource leaks
465
+ clearTimeout(timeoutId);
466
+ }
467
+ }
468
+ }
469
+
470
+ private async sendWithRetry(
471
+ chatId: number,
472
+ text: string,
473
+ replyToId?: number
474
+ ): Promise<void> {
475
+ const maxRetries = 3;
476
+ const backoffMs = [1000, 2000, 4000];
477
+
478
+ for (let attempt = 0; attempt < maxRetries; attempt++) {
479
+ try {
480
+ const html = this.markdownToHTML(text);
481
+ const options: any = { parse_mode: "HTML" };
482
+ if (replyToId) {
483
+ options.reply_parameters = { message_id: replyToId };
484
+ }
485
+ await this.bot!.api.sendMessage(chatId, html, options);
486
+ return;
487
+ } catch (error: unknown) {
488
+ const err = error as Error & { error_code?: number; parameters?: { retry_after?: number } };
489
+
490
+ if (err.error_code === 400 && err.message.includes("can't parse entities")) {
491
+ this.log.warn(`Markdown parsing failed, falling back to plain text for chatId: ${chatId}`);
492
+ await this.bot!.api.sendMessage(chatId, text, {
493
+ reply_parameters: replyToId ? { message_id: replyToId } : undefined
494
+ });
495
+ return;
496
+ }
497
+
498
+ if (err.error_code === 400) {
499
+ this.log.error(`Bad Request: ${err.message}`);
500
+ throw error;
501
+ }
502
+
503
+ if (err.error_code === 429) {
504
+ const retryAfter = err.parameters?.retry_after ?? 1;
505
+ this.log.warn(`Rate limited, waiting ${retryAfter}s`);
506
+ await new Promise((resolve) => setTimeout(resolve, retryAfter * 1000));
507
+ continue;
508
+ }
509
+
510
+ if (attempt < maxRetries - 1) {
511
+ this.log.warn(`Send failed, retrying in ${backoffMs[attempt]}ms (attempt ${attempt + 1}/${maxRetries})`);
512
+ await new Promise((resolve) => setTimeout(resolve, backoffMs[attempt]));
513
+ } else {
514
+ throw error;
515
+ }
516
+ }
517
+ }
518
+ }
519
+
520
+ private chunkMessage(content: string, maxLength: number): string[] {
521
+ const chunks: string[] = [];
522
+ let remaining = content;
523
+
524
+ while (remaining.length > 0) {
525
+ if (remaining.length <= maxLength) {
526
+ chunks.push(remaining);
527
+ break;
528
+ }
529
+
530
+ let splitPoint = remaining.lastIndexOf("\n\n", maxLength);
531
+ if (splitPoint === -1 || splitPoint < maxLength * 0.5) {
532
+ splitPoint = remaining.lastIndexOf("\n", maxLength);
533
+ }
534
+ if (splitPoint === -1 || splitPoint < maxLength * 0.5) {
535
+ splitPoint = remaining.lastIndexOf(" ", maxLength);
536
+ }
537
+ if (splitPoint === -1 || splitPoint < maxLength * 0.5) {
538
+ splitPoint = maxLength;
539
+ }
540
+
541
+ chunks.push(remaining.slice(0, splitPoint));
542
+ remaining = remaining.slice(splitPoint).trim();
543
+ }
544
+
545
+ return chunks;
546
+ }
547
+
548
+ private markdownToHTML(text: string): string {
549
+ // ── Step 1: extract code blocks before any escaping ────────────────────
550
+ // Prevents code content from being HTML-escaped or markdown-converted.
551
+ const codeBlocks: string[] = [];
552
+ const inlineCodes: string[] = [];
553
+
554
+ let out = text
555
+ // Fenced code blocks (``` ... ```) — strip optional language hint
556
+ .replace(/```(?:[^\n]*)\n?([\s\S]*?)```/g, (_m, code: string) => {
557
+ const idx = codeBlocks.push(code.trim()) - 1;
558
+ return `\x00BLOCK${idx}\x00`;
559
+ })
560
+ // Inline code (`...`)
561
+ .replace(/`([^`\n]+)`/g, (_m, code: string) => {
562
+ const idx = inlineCodes.push(code) - 1;
563
+ return `\x00INLINE${idx}\x00`;
564
+ });
565
+
566
+ // ── Step 2: escape HTML entities in the remaining text ─────────────────
567
+ out = out
568
+ .replace(/&/g, "&amp;")
569
+ .replace(/</g, "&lt;")
570
+ .replace(/>/g, "&gt;");
571
+
572
+ // ── Step 3: block-level conversions ────────────────────────────────────
573
+ // Headers: ### h3, ## h2, # h1 → <b>text</b>
574
+ out = out.replace(/^#{1,6}\s+(.+)$/gm, "<b>$1</b>");
575
+
576
+ // Horizontal rules → blank line
577
+ out = out.replace(/^---+$/gm, "");
578
+
579
+ // ── Step 4: inline conversions ─────────────────────────────────────────
580
+ // Bold **text** or __text__
581
+ out = out.replace(/\*\*(.+?)\*\*/gs, "<b>$1</b>");
582
+ out = out.replace(/__(.+?)__/gs, "<b>$1</b>");
583
+
584
+ // Italic *text* (single star, not double) — avoid greedy cross-line
585
+ out = out.replace(/(?<!\*)\*(?!\*)(.+?)(?<!\*)\*(?!\*)/gs, "<i>$1</i>");
586
+
587
+ // Italic _text_ — only match when surrounded by non-word chars (avoids snake_case)
588
+ out = out.replace(/(?<!\w)_(?!\s)(.+?)(?<!\s)_(?!\w)/gs, "<i>$1</i>");
589
+
590
+ // Strikethrough ~~text~~
591
+ out = out.replace(/~~(.+?)~~/gs, "<s>$1</s>");
592
+
593
+ // ── Step 5: restore code placeholders (now safely escaped) ─────────────
594
+ // Restore inline code
595
+ out = out.replace(/\x00INLINE(\d+)\x00/g, (_m, i) => {
596
+ const code = inlineCodes[Number(i)] ?? "";
597
+ return `<code>${code.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;")}</code>`;
598
+ });
599
+
600
+ // Restore block code
601
+ out = out.replace(/\x00BLOCK(\d+)\x00/g, (_m, i) => {
602
+ const code = codeBlocks[Number(i)] ?? "";
603
+ return `<pre><code>${code.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;")}</code></pre>`;
604
+ });
605
+
606
+ return out;
607
+ }
608
+ }
609
+
610
+ export function createTelegramChannel(accountId: string, config: TelegramConfig): TelegramChannel {
611
+ return new TelegramChannel(accountId, config);
612
+ }