@johpaz/hive-agents 0.0.35 → 0.0.37

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 (441) hide show
  1. package/README.md +64 -39
  2. package/dist/hive.js +3231 -3189
  3. package/dist/tool-worker.js +218406 -0
  4. package/dist/ui/assets/{AgentCreateForm-B4eK7efF.js → AgentCreateForm-tJZv9FZC.js} +1 -1
  5. package/dist/ui/assets/{AgentDetailPage-BD2uoJWk.js → AgentDetailPage-Du-mRcAX.js} +1 -1
  6. package/dist/ui/assets/AgentNewPage-DIFYd_Ys.js +1 -0
  7. package/dist/ui/assets/{AgentsPage-4JUZXvkA.js → AgentsPage-YvSgWRiw.js} +6 -6
  8. package/dist/ui/assets/CanvasPage-DtMwGvxf.js +33 -0
  9. package/dist/ui/assets/{ChannelsPage-BUn7-nhV.js → ChannelsPage-BdBXWHjj.js} +1 -1
  10. package/dist/ui/assets/DashboardPage-ghl1ZguH.js +6 -0
  11. package/dist/ui/assets/{LoginPage-C8j_urUD.js → LoginPage-CAmSI9Vy.js} +1 -1
  12. package/dist/ui/assets/LogsPage-DAPBHkwK.js +1 -0
  13. package/dist/ui/assets/MeetingPage-WjjGOqqU.js +1 -0
  14. package/dist/ui/assets/{NotFound-Drh-sJPN.js → NotFound-BMeQSGcG.js} +1 -1
  15. package/dist/ui/assets/ProvidersPage-Ct6HsAi1.js +1 -0
  16. package/dist/ui/assets/{RecoverPage-DNb1Pr8h.js → RecoverPage-DpW3l-yv.js} +1 -1
  17. package/dist/ui/assets/SettingsPage-DBJ7_E6C.js +9 -0
  18. package/dist/ui/assets/SetupPage-DKmLVUaj.js +1 -0
  19. package/dist/ui/assets/{WebChatPage-R-YOwA4F.js → WebChatPage-CVRcKept.js} +2 -2
  20. package/dist/ui/assets/accordion-C5d5Rm5z.js +1 -0
  21. package/dist/ui/assets/{alert-U8FsgWi7.js → alert-C-NE-P3s.js} +1 -1
  22. package/dist/ui/assets/{alert-dialog-CRdMkkmk.js → alert-dialog-C5mzbHdP.js} +1 -1
  23. package/dist/ui/assets/{badge-Cli1jnH5.js → badge-ChpACfWO.js} +1 -1
  24. package/dist/ui/assets/chevron-up-BYhk0K2J.js +1 -0
  25. package/dist/ui/assets/{dialog-DQ3s-LuO.js → dialog-QnZ0ad8O.js} +1 -1
  26. package/dist/ui/assets/dropdown-menu-BK-CO3Od.js +1 -0
  27. package/dist/ui/assets/{es-DcMjrpbA.js → es-NQNoaWDx.js} +1 -1
  28. package/dist/ui/assets/index-B2fCYtTS.css +2 -0
  29. package/dist/ui/assets/index-DMCjjdqf.js +116 -0
  30. package/dist/ui/assets/{label-0BvGVXvZ.js → label-D2H1IR_J.js} +1 -1
  31. package/dist/ui/assets/progress-BherYzY6.js +1 -0
  32. package/dist/ui/assets/scroll-area-DkeyX32e.js +1 -0
  33. package/dist/ui/assets/{slider-D47dOrRa.js → slider-CsiUDxc3.js} +1 -1
  34. package/dist/ui/assets/switch-BDwN8RYV.js +1 -0
  35. package/dist/ui/assets/{table-DhowbNxQ.js → table-CSc8ubon.js} +1 -1
  36. package/dist/ui/assets/terminal-DN38Q456.js +1 -0
  37. package/dist/ui/assets/useProviders-C6_QHsEi.js +1 -0
  38. package/dist/ui/assets/{vendor-radix-JY4ncZrD.js → vendor-radix-cw1bQaVC.js} +4 -4
  39. package/dist/ui/assets/{vendor-react-CscwQerf.js → vendor-react-D4s9E-zj.js} +1 -1
  40. package/dist/ui/dist/assets/AgentCreateForm-tJZv9FZC.js +1 -0
  41. package/dist/ui/dist/assets/AgentDetailPage-Du-mRcAX.js +1 -0
  42. package/dist/ui/dist/assets/AgentNewPage-DIFYd_Ys.js +1 -0
  43. package/dist/ui/dist/assets/AgentsPage-YvSgWRiw.js +10 -0
  44. package/dist/ui/dist/assets/CanvasPage-DtMwGvxf.js +33 -0
  45. package/dist/ui/dist/assets/ChannelsPage-BdBXWHjj.js +8 -0
  46. package/dist/ui/dist/assets/DashboardPage-ghl1ZguH.js +6 -0
  47. package/dist/ui/dist/assets/LoginPage-CAmSI9Vy.js +1 -0
  48. package/dist/ui/dist/assets/LogsPage-DAPBHkwK.js +1 -0
  49. package/dist/ui/dist/assets/MeetingPage-WjjGOqqU.js +1 -0
  50. package/dist/ui/dist/assets/NotFound-BMeQSGcG.js +1 -0
  51. package/dist/ui/dist/assets/ProvidersPage-Ct6HsAi1.js +1 -0
  52. package/dist/ui/dist/assets/RecoverPage-DpW3l-yv.js +1 -0
  53. package/dist/ui/dist/assets/SettingsPage-DBJ7_E6C.js +9 -0
  54. package/dist/ui/dist/assets/SetupPage-DKmLVUaj.js +1 -0
  55. package/dist/ui/dist/assets/WebChatPage-CVRcKept.js +16 -0
  56. package/dist/ui/dist/assets/accordion-C5d5Rm5z.js +1 -0
  57. package/dist/ui/dist/assets/activity-c3pNngT_.js +1 -0
  58. package/dist/ui/dist/assets/alert-C-NE-P3s.js +1 -0
  59. package/dist/ui/dist/assets/alert-dialog-C5mzbHdP.js +1 -0
  60. package/dist/ui/dist/assets/arrow-left-CBcbX5EZ.js +1 -0
  61. package/dist/ui/dist/assets/badge-ChpACfWO.js +1 -0
  62. package/dist/ui/dist/assets/calendar-B-KZ9RQO.js +1 -0
  63. package/dist/ui/dist/assets/card-CNf6BS2e.js +1 -0
  64. package/dist/ui/dist/assets/chevron-left-D4U-5A27.js +1 -0
  65. package/dist/ui/dist/assets/chevron-right-CR4Skrf3.js +1 -0
  66. package/dist/ui/dist/assets/chevron-up-BYhk0K2J.js +1 -0
  67. package/dist/ui/dist/assets/circle-alert-CyHDwUj8.js +1 -0
  68. package/dist/ui/dist/assets/circle-check-Bb54Ebmu.js +1 -0
  69. package/dist/ui/dist/assets/cpu-Cdgc_B1K.js +1 -0
  70. package/dist/ui/dist/assets/dialog-QnZ0ad8O.js +1 -0
  71. package/dist/ui/dist/assets/download-C3ifGMjJ.js +1 -0
  72. package/dist/ui/dist/assets/dropdown-menu-BK-CO3Od.js +1 -0
  73. package/dist/ui/dist/assets/es-NQNoaWDx.js +1 -0
  74. package/dist/ui/dist/assets/external-link-BvxYeTP1.js +1 -0
  75. package/dist/ui/dist/assets/eye-DqNTU_GD.js +1 -0
  76. package/dist/ui/dist/assets/file-text-BT_9S9SM.js +1 -0
  77. package/dist/ui/dist/assets/folder-open-BhH8y9ac.js +1 -0
  78. package/dist/ui/dist/assets/format-GVHeOyWI.js +1 -0
  79. package/dist/ui/dist/assets/gateway-url-COCbW0IR.js +1 -0
  80. package/dist/ui/dist/assets/gauge-D_TMa4i9.js +1 -0
  81. package/dist/ui/dist/assets/globe-DeCQTCDJ.js +1 -0
  82. package/dist/ui/dist/assets/hexagon-DsGOUl-H.js +1 -0
  83. package/dist/ui/dist/assets/history-BSG-Ypqf.js +1 -0
  84. package/dist/ui/dist/assets/index-B2fCYtTS.css +2 -0
  85. package/dist/ui/dist/assets/index-DMCjjdqf.js +116 -0
  86. package/dist/ui/dist/assets/info-NwLoa2Mj.js +1 -0
  87. package/dist/ui/dist/assets/key-3EP0dhkT.js +1 -0
  88. package/dist/ui/dist/assets/label-D2H1IR_J.js +1 -0
  89. package/dist/ui/dist/assets/loader-circle-CZNax6kS.js +1 -0
  90. package/dist/ui/dist/assets/lock-Ei1_J-Nq.js +1 -0
  91. package/dist/ui/dist/assets/pause-BUqah9Bi.js +1 -0
  92. package/dist/ui/dist/assets/play-NcZ4swwL.js +1 -0
  93. package/dist/ui/dist/assets/plus-CX1xyhp5.js +1 -0
  94. package/dist/ui/dist/assets/progress-BherYzY6.js +1 -0
  95. package/dist/ui/dist/assets/refresh-cw-DaYdjQFk.js +1 -0
  96. package/dist/ui/dist/assets/rolldown-runtime-S-ySWqyJ.js +1 -0
  97. package/dist/ui/dist/assets/save-CUdYyHNy.js +1 -0
  98. package/dist/ui/dist/assets/scroll-area-DkeyX32e.js +1 -0
  99. package/dist/ui/dist/assets/send-B0H5SEIE.js +1 -0
  100. package/dist/ui/dist/assets/settings-Ds4SqD8s.js +1 -0
  101. package/dist/ui/dist/assets/slider-CsiUDxc3.js +14 -0
  102. package/dist/ui/dist/assets/sparkles-yUEb-7oH.js +1 -0
  103. package/dist/ui/dist/assets/square-BD81nFtN.js +1 -0
  104. package/dist/ui/dist/assets/switch-BDwN8RYV.js +1 -0
  105. package/dist/ui/dist/assets/table-CSc8ubon.js +1 -0
  106. package/dist/ui/dist/assets/terminal-DN38Q456.js +1 -0
  107. package/dist/ui/dist/assets/textarea-CXgXWKrT.js +1 -0
  108. package/dist/ui/dist/assets/trash-2-CNjMkoq6.js +1 -0
  109. package/dist/ui/dist/assets/triangle-alert-C9Y8Ub4X.js +1 -0
  110. package/dist/ui/dist/assets/useProviders-C6_QHsEi.js +1 -0
  111. package/dist/ui/dist/assets/utils-3pnRFmFe.js +1 -0
  112. package/dist/ui/dist/assets/vendor-charts-Bu2lyBKP.js +65 -0
  113. package/dist/ui/dist/assets/vendor-query-DsWPbQdG.js +1 -0
  114. package/dist/ui/dist/assets/vendor-radix-cw1bQaVC.js +63 -0
  115. package/dist/ui/dist/assets/vendor-react-D4s9E-zj.js +1 -0
  116. package/dist/ui/dist/assets/vendor-router-C9pIYwbJ.js +3 -0
  117. package/dist/ui/dist/assets/volume-2-CeSXNDv4.js +1 -0
  118. package/dist/ui/dist/assets/zap-hlXjpSeA.js +1 -0
  119. package/dist/ui/dist/favicon.ico +0 -0
  120. package/dist/ui/dist/index.html +40 -0
  121. package/dist/ui/dist/placeholder.svg +1 -0
  122. package/dist/ui/index.html +6 -6
  123. package/package.json +138 -13
  124. package/packages/cli/src/adapters/binary.ts +461 -0
  125. package/packages/cli/src/adapters/bun-global.ts +378 -0
  126. package/packages/cli/src/adapters/config.ts +314 -0
  127. package/packages/cli/src/adapters/docker.ts +308 -0
  128. package/packages/cli/src/adapters/factory.ts +168 -0
  129. package/packages/cli/src/adapters/index.ts +80 -0
  130. package/packages/cli/src/adapters/types.ts +218 -0
  131. package/packages/cli/src/commands/agent-run.ts +168 -0
  132. package/packages/cli/src/commands/agents.ts +398 -0
  133. package/packages/cli/src/commands/chat.ts +142 -0
  134. package/packages/cli/src/commands/config.ts +49 -0
  135. package/packages/cli/src/commands/cron.ts +487 -0
  136. package/packages/cli/src/commands/dev.ts +58 -0
  137. package/packages/cli/src/commands/doctor.ts +320 -0
  138. package/packages/cli/src/commands/gateway.ts +719 -0
  139. package/packages/cli/src/commands/logs.ts +57 -0
  140. package/packages/cli/src/commands/mcp.ts +175 -0
  141. package/packages/cli/src/commands/message.ts +77 -0
  142. package/packages/cli/src/commands/migrate.ts +90 -0
  143. package/packages/cli/src/commands/onboard.ts +1656 -0
  144. package/packages/cli/src/commands/security.ts +144 -0
  145. package/packages/cli/src/commands/service.ts +50 -0
  146. package/packages/cli/src/commands/sessions.ts +116 -0
  147. package/packages/cli/src/commands/skills.ts +215 -0
  148. package/packages/cli/src/commands/update.ts +203 -0
  149. package/packages/cli/src/index.ts +210 -0
  150. package/packages/cli/src/ui-bundle.generated.ts +3 -0
  151. package/packages/cli/src/utils/token.ts +6 -0
  152. package/packages/core/src/agent/agent-loop.ts +691 -0
  153. package/packages/core/src/agent/compaction.ts +240 -0
  154. package/packages/core/src/agent/context-compiler.ts +467 -0
  155. package/packages/core/src/agent/context-guard.ts +91 -0
  156. package/packages/core/src/agent/conversation-store.ts +244 -0
  157. package/packages/core/src/agent/curator.ts +158 -0
  158. package/packages/core/src/agent/hooks.ts +166 -0
  159. package/packages/core/src/agent/llm-client.ts +167 -0
  160. package/packages/core/src/agent/llm-providers/anthropic.ts +212 -0
  161. package/packages/core/src/agent/llm-providers/deepseek.ts +8 -0
  162. package/packages/core/src/agent/llm-providers/gemini.ts +215 -0
  163. package/packages/core/src/agent/llm-providers/groq.ts +5 -0
  164. package/packages/core/src/agent/llm-providers/interface.ts +195 -0
  165. package/packages/core/src/agent/llm-providers/kimi.ts +8 -0
  166. package/packages/core/src/agent/llm-providers/local-llama.ts +37 -0
  167. package/packages/core/src/agent/llm-providers/mistral.ts +5 -0
  168. package/packages/core/src/agent/llm-providers/nvidia.ts +5 -0
  169. package/packages/core/src/agent/llm-providers/ollama.ts +175 -0
  170. package/packages/core/src/agent/llm-providers/openai-compat-base.ts +379 -0
  171. package/packages/core/src/agent/llm-providers/openai.ts +5 -0
  172. package/packages/core/src/agent/llm-providers/openrouter.ts +5 -0
  173. package/packages/core/src/agent/llm-providers/qwen.ts +5 -0
  174. package/packages/core/src/agent/native-tools.ts +31 -0
  175. package/packages/core/src/agent/playbook-selector.ts +147 -0
  176. package/packages/core/src/agent/prompt-builder.ts +169 -0
  177. package/packages/core/src/agent/providers/index.ts +204 -0
  178. package/packages/core/src/agent/providers.ts +1 -0
  179. package/packages/core/src/agent/reflector.ts +200 -0
  180. package/packages/core/src/agent/service.ts +267 -0
  181. package/packages/core/src/agent/skill-selector.ts +479 -0
  182. package/packages/core/src/agent/stuck-loop.ts +133 -0
  183. package/packages/core/src/agent/tool-selector.ts +569 -0
  184. package/packages/core/src/agent/tracer.ts +100 -0
  185. package/packages/core/src/auth/auth.ts +108 -0
  186. package/packages/core/src/auth/index.ts +1 -0
  187. package/packages/core/src/canvas/a2ui-tools.ts +255 -0
  188. package/packages/core/src/canvas/canvas-manager.ts +390 -0
  189. package/packages/core/src/canvas/canvas-tools.ts +448 -0
  190. package/packages/core/src/canvas/emitter.ts +149 -0
  191. package/packages/core/src/canvas/index.ts +3 -0
  192. package/packages/core/src/channels/base.ts +154 -0
  193. package/packages/core/src/channels/discord.ts +273 -0
  194. package/packages/core/src/channels/index.ts +7 -0
  195. package/packages/core/src/channels/manager.ts +450 -0
  196. package/packages/core/src/channels/slack.ts +323 -0
  197. package/packages/core/src/channels/telegram.ts +612 -0
  198. package/packages/core/src/channels/webchat.ts +139 -0
  199. package/packages/core/src/channels/whatsapp.ts +548 -0
  200. package/packages/core/src/config/index.ts +12 -0
  201. package/packages/core/src/config/loader.ts +569 -0
  202. package/packages/core/src/events/agent-bus.ts +460 -0
  203. package/packages/core/src/events/event-bus.ts +169 -0
  204. package/packages/core/src/gateway/channel-notify.ts +64 -0
  205. package/packages/core/src/gateway/helpers/cors.ts +32 -0
  206. package/packages/core/src/gateway/helpers/index.ts +4 -0
  207. package/packages/core/src/gateway/helpers/narration.ts +57 -0
  208. package/packages/core/src/gateway/helpers/path.ts +13 -0
  209. package/packages/core/src/gateway/helpers/redact.ts +61 -0
  210. package/packages/core/src/gateway/index.ts +5 -0
  211. package/packages/core/src/gateway/initializer.ts +363 -0
  212. package/packages/core/src/gateway/lane-queue.ts +169 -0
  213. package/packages/core/src/gateway/llm-local/client.ts +94 -0
  214. package/packages/core/src/gateway/llm-local/detector.ts +321 -0
  215. package/packages/core/src/gateway/llm-local/downloader.ts +216 -0
  216. package/packages/core/src/gateway/llm-local/index.ts +34 -0
  217. package/packages/core/src/gateway/llm-local/manager.ts +186 -0
  218. package/packages/core/src/gateway/llm-local/models.ts +149 -0
  219. package/packages/core/src/gateway/llm-local/server.ts +179 -0
  220. package/packages/core/src/gateway/resolver.ts +108 -0
  221. package/packages/core/src/gateway/router.ts +124 -0
  222. package/packages/core/src/gateway/routes/agents.ts +210 -0
  223. package/packages/core/src/gateway/routes/auth.ts +244 -0
  224. package/packages/core/src/gateway/routes/channels.ts +484 -0
  225. package/packages/core/src/gateway/routes/chat.ts +241 -0
  226. package/packages/core/src/gateway/routes/config.ts +12 -0
  227. package/packages/core/src/gateway/routes/cron-api.ts +544 -0
  228. package/packages/core/src/gateway/routes/ethics.ts +46 -0
  229. package/packages/core/src/gateway/routes/llm-local.ts +271 -0
  230. package/packages/core/src/gateway/routes/mcp.ts +319 -0
  231. package/packages/core/src/gateway/routes/meeting.ts +232 -0
  232. package/packages/core/src/gateway/routes/models.ts +163 -0
  233. package/packages/core/src/gateway/routes/multimodal.ts +93 -0
  234. package/packages/core/src/gateway/routes/providers.ts +220 -0
  235. package/packages/core/src/gateway/routes/setup.ts +441 -0
  236. package/packages/core/src/gateway/routes/skills.ts +115 -0
  237. package/packages/core/src/gateway/routes/system.ts +469 -0
  238. package/packages/core/src/gateway/routes/tasks.ts +44 -0
  239. package/packages/core/src/gateway/routes/tools.ts +59 -0
  240. package/packages/core/src/gateway/routes/tts-local.ts +388 -0
  241. package/packages/core/src/gateway/routes/users.ts +122 -0
  242. package/packages/core/src/gateway/routes/voice.ts +189 -0
  243. package/packages/core/src/gateway/routes/workspace.ts +281 -0
  244. package/packages/core/src/gateway/server.ts +2744 -0
  245. package/packages/core/src/gateway/session.ts +95 -0
  246. package/packages/core/src/gateway/slash-commands.ts +207 -0
  247. package/packages/core/src/gateway/tts/README.md +94 -0
  248. package/packages/core/src/gateway/tts/package.json +25 -0
  249. package/packages/core/src/gateway/tts/src/client.ts +59 -0
  250. package/packages/core/src/gateway/tts/src/detect.ts +42 -0
  251. package/packages/core/src/gateway/tts/src/index.ts +15 -0
  252. package/packages/core/src/gateway/tts/src/install.ts +129 -0
  253. package/packages/core/src/gateway/tts/src/models.ts +50 -0
  254. package/packages/core/src/gateway/tts/src/server.ts +252 -0
  255. package/packages/core/src/gateway/tts/voices/.gitkeep +0 -0
  256. package/packages/core/src/heartbeat/index.ts +157 -0
  257. package/packages/core/src/index.ts +56 -0
  258. package/packages/core/src/mcp/hot-reload.ts +148 -0
  259. package/packages/core/src/mcp/singleton.ts +21 -0
  260. package/packages/core/src/mcp/tool-sync.ts +176 -0
  261. package/packages/core/src/multimodal/index.ts +2 -0
  262. package/packages/core/src/multimodal/types.ts +28 -0
  263. package/packages/core/src/multimodal/vision-service.ts +283 -0
  264. package/packages/core/src/plugins/api.ts +128 -0
  265. package/packages/core/src/plugins/index.ts +2 -0
  266. package/packages/core/src/plugins/loader.ts +365 -0
  267. package/packages/core/src/resilience/circuit-breaker.ts +225 -0
  268. package/packages/core/src/scheduler/CronScheduler.ts +699 -0
  269. package/packages/core/src/scheduler/dag/AgentExecutor.ts +53 -0
  270. package/packages/core/src/scheduler/dag/DAGScheduler.ts +250 -0
  271. package/packages/core/src/scheduler/dag/EventBridge.ts +122 -0
  272. package/packages/core/src/scheduler/dag/TaskGraph.ts +192 -0
  273. package/packages/core/src/scheduler/dag/TaskNode.ts +97 -0
  274. package/packages/core/src/scheduler/dag/TaskResult.ts +22 -0
  275. package/packages/core/src/scheduler/dag/errors.ts +37 -0
  276. package/packages/core/src/scheduler/dag/index.ts +26 -0
  277. package/packages/core/src/scheduler/dag/presets/ResearchPreset.ts +97 -0
  278. package/packages/core/src/scheduler/dag/strategies/ParallelStrategy.ts +21 -0
  279. package/packages/core/src/scheduler/dag/strategies/PriorityStrategy.ts +46 -0
  280. package/packages/core/src/scheduler/index.ts +22 -0
  281. package/packages/core/src/scheduler/integration.ts +237 -0
  282. package/packages/core/src/scheduler/types.ts +164 -0
  283. package/packages/core/src/security/google-chat.ts +269 -0
  284. package/packages/core/src/security/index.ts +192 -0
  285. package/packages/core/src/security/pairing.ts +250 -0
  286. package/packages/core/src/security/rate-limit.ts +270 -0
  287. package/packages/core/src/security/signal.ts +321 -0
  288. package/packages/core/src/state/store.ts +312 -0
  289. package/packages/core/src/storage/crypto.ts +197 -0
  290. package/packages/core/src/storage/migrate.ts +147 -0
  291. package/packages/core/src/storage/onboarding.ts +1506 -0
  292. package/packages/core/src/storage/schema.ts +666 -0
  293. package/packages/core/src/storage/seed.ts +628 -0
  294. package/packages/core/src/storage/sqlite.ts +407 -0
  295. package/packages/core/src/storage/usage.ts +374 -0
  296. package/packages/core/src/tool-runtime/index.ts +502 -0
  297. package/packages/core/src/tool-runtime/tool-worker.ts +125 -0
  298. package/packages/core/src/tools/agents/get-available-models.ts +118 -0
  299. package/packages/core/src/tools/agents/index.ts +610 -0
  300. package/packages/core/src/tools/canvas/index.ts +420 -0
  301. package/packages/core/src/tools/cli/index.ts +142 -0
  302. package/packages/core/src/tools/core/index.ts +478 -0
  303. package/packages/core/src/tools/cron/index.ts +635 -0
  304. package/packages/core/src/tools/filesystem/fs-delete.ts +78 -0
  305. package/packages/core/src/tools/filesystem/fs-edit.ts +106 -0
  306. package/packages/core/src/tools/filesystem/fs-exists.ts +63 -0
  307. package/packages/core/src/tools/filesystem/fs-glob.ts +108 -0
  308. package/packages/core/src/tools/filesystem/fs-list.ts +129 -0
  309. package/packages/core/src/tools/filesystem/fs-read.ts +72 -0
  310. package/packages/core/src/tools/filesystem/fs-write.ts +67 -0
  311. package/packages/core/src/tools/filesystem/index.ts +34 -0
  312. package/packages/core/src/tools/filesystem/workspace-guard.ts +62 -0
  313. package/packages/core/src/tools/index.ts +197 -0
  314. package/packages/core/src/tools/meeting/index.ts +363 -0
  315. package/packages/core/src/tools/office/index.ts +47 -0
  316. package/packages/core/src/tools/office/office-escribir-docx.ts +192 -0
  317. package/packages/core/src/tools/office/office-escribir-pdf.ts +172 -0
  318. package/packages/core/src/tools/office/office-escribir-pptx.ts +174 -0
  319. package/packages/core/src/tools/office/office-escribir-xlsx.ts +116 -0
  320. package/packages/core/src/tools/office/office-leer-docx.ts +93 -0
  321. package/packages/core/src/tools/office/office-leer-pdf.ts +114 -0
  322. package/packages/core/src/tools/office/office-leer-pptx.ts +136 -0
  323. package/packages/core/src/tools/office/office-leer-xlsx.ts +124 -0
  324. package/packages/core/src/tools/types.ts +39 -0
  325. package/packages/core/src/tools/voice/index.ts +104 -0
  326. package/packages/core/src/tools/web/browser-click.ts +78 -0
  327. package/packages/core/src/tools/web/browser-extract.ts +139 -0
  328. package/packages/core/src/tools/web/browser-navigate.ts +106 -0
  329. package/packages/core/src/tools/web/browser-screenshot.ts +87 -0
  330. package/packages/core/src/tools/web/browser-script.ts +88 -0
  331. package/packages/core/src/tools/web/browser-service.ts +554 -0
  332. package/packages/core/src/tools/web/browser-type.ts +101 -0
  333. package/packages/core/src/tools/web/browser-wait.ts +136 -0
  334. package/packages/core/src/tools/web/index.ts +41 -0
  335. package/packages/core/src/tools/web/web-fetch.ts +78 -0
  336. package/packages/core/src/tools/web/web-search.ts +123 -0
  337. package/packages/core/src/utils/benchmark.ts +80 -0
  338. package/packages/core/src/utils/crypto.ts +73 -0
  339. package/packages/core/src/utils/date.ts +42 -0
  340. package/packages/core/src/utils/index.ts +5 -0
  341. package/packages/core/src/utils/logger.ts +389 -0
  342. package/packages/core/src/utils/retry.ts +70 -0
  343. package/packages/core/src/utils/toon.ts +253 -0
  344. package/packages/core/src/voice/index.ts +643 -0
  345. package/packages/mcp/src/config.ts +13 -0
  346. package/packages/mcp/src/index.ts +1 -0
  347. package/packages/mcp/src/logger.ts +47 -0
  348. package/packages/mcp/src/manager.ts +439 -0
  349. package/packages/mcp/src/transports/index.ts +67 -0
  350. package/packages/mcp/src/transports/sse.ts +238 -0
  351. package/packages/mcp/src/transports/websocket.ts +159 -0
  352. package/packages/skills/src/bundled/agents/agent_spawner/SKILL.md +167 -0
  353. package/packages/skills/src/bundled/agents/code_delegator/SKILL.md +156 -0
  354. package/packages/skills/src/bundled/agents/memory_manager/SKILL.md +143 -0
  355. package/packages/skills/src/bundled/agents/research_and_remember/SKILL.md +139 -0
  356. package/packages/skills/src/bundled/agents/task_orchestrator/SKILL.md +198 -0
  357. package/packages/skills/src/bundled/canvas/a2ui_dashboard/SKILL.md +176 -0
  358. package/packages/skills/src/bundled/canvas/a2ui_form/SKILL.md +202 -0
  359. package/packages/skills/src/bundled/canvas/a2ui_interactive/SKILL.md +206 -0
  360. package/packages/skills/src/bundled/canvas/canvas_dashboard/SKILL.md +146 -0
  361. package/packages/skills/src/bundled/canvas/canvas_interact/SKILL.md +148 -0
  362. package/packages/skills/src/bundled/canvas/canvas_report/SKILL.md +146 -0
  363. package/packages/skills/src/bundled/cli/cli_pipeline/SKILL.md +136 -0
  364. package/packages/skills/src/bundled/cli/cli_safe_exec/SKILL.md +125 -0
  365. package/packages/skills/src/bundled/cron_manager/SKILL.md +188 -0
  366. package/packages/skills/src/bundled/cron_reminder/SKILL.md +112 -0
  367. package/packages/skills/src/bundled/filesystem/file_manager/SKILL.md +118 -0
  368. package/packages/skills/src/bundled/filesystem/file_read_and_summarize/SKILL.md +108 -0
  369. package/packages/skills/src/bundled/filesystem/file_writer/SKILL.md +135 -0
  370. package/packages/skills/src/bundled/meeting/meeting_transcription/SKILL.md +213 -0
  371. package/packages/skills/src/bundled/office/office_document_manager/SKILL.md +262 -0
  372. package/packages/skills/src/bundled/search_knowledge/busqueda_fts5/SKILL.md +74 -0
  373. package/packages/skills/src/bundled/voice/voice_assistant/SKILL.md +174 -0
  374. package/packages/skills/src/bundled/voice/voice_input/SKILL.md +146 -0
  375. package/packages/skills/src/bundled/voice/voice_output/SKILL.md +151 -0
  376. package/packages/skills/src/bundled/web/browser_automate/SKILL.md +120 -0
  377. package/packages/skills/src/bundled/web/browser_scrape/SKILL.md +109 -0
  378. package/packages/skills/src/bundled/web/web_monitor/SKILL.md +127 -0
  379. package/packages/skills/src/bundled/web/web_research/SKILL.md +119 -0
  380. package/packages/skills/src/bundled-data.generated.ts +1964 -0
  381. package/packages/skills/src/index.ts +1 -0
  382. package/packages/skills/src/loader.ts +388 -0
  383. package/dist/ui/assets/AgentNewPage-GB-tVN50.js +0 -1
  384. package/dist/ui/assets/BridgePage-DDcDILKu.js +0 -1
  385. package/dist/ui/assets/CanvasPage-oOk2sGOD.js +0 -33
  386. package/dist/ui/assets/DashboardPage-DV_2qWYJ.js +0 -6
  387. package/dist/ui/assets/LogsPage-DayYjh01.js +0 -1
  388. package/dist/ui/assets/MeetingPage-C01uPuqj.js +0 -1
  389. package/dist/ui/assets/ProjectsPage-B8_am_Ib.js +0 -1
  390. package/dist/ui/assets/ProvidersPage-DBzi66e4.js +0 -1
  391. package/dist/ui/assets/SettingsPage-CFA_Tknl.js +0 -9
  392. package/dist/ui/assets/SetupPage-BrUWbhvT.js +0 -1
  393. package/dist/ui/assets/accordion-DdAEfIXR.js +0 -1
  394. package/dist/ui/assets/chevron-down-DIosfU_U.js +0 -1
  395. package/dist/ui/assets/chevron-up-CI-W21Fy.js +0 -1
  396. package/dist/ui/assets/circle-S0-ouLz-.js +0 -1
  397. package/dist/ui/assets/circle-minus-CE0iJrl8.js +0 -1
  398. package/dist/ui/assets/circle-x-jUJ5zZvQ.js +0 -1
  399. package/dist/ui/assets/dropdown-menu-C2CXM1VE.js +0 -1
  400. package/dist/ui/assets/index-BN0875JH.css +0 -2
  401. package/dist/ui/assets/index-CH6sBa3Q.js +0 -116
  402. package/dist/ui/assets/pencil-5VdSj-h5.js +0 -1
  403. package/dist/ui/assets/progress-JN30I5fF.js +0 -1
  404. package/dist/ui/assets/scroll-area-BQQPitM8.js +0 -1
  405. package/dist/ui/assets/search-ChPgnVKj.js +0 -1
  406. package/dist/ui/assets/switch-C7W2-KEx.js +0 -1
  407. package/dist/ui/assets/terminal-C-R5Fckz.js +0 -1
  408. package/dist/ui/assets/useProviders-TBnWn-Hq.js +0 -1
  409. /package/dist/ui/assets/{card-DFKnZ6ky.js → card-CNf6BS2e.js} +0 -0
  410. /package/dist/ui/assets/{circle-alert-KuAm2FWh.js → circle-alert-CyHDwUj8.js} +0 -0
  411. /package/dist/ui/assets/{circle-check-6Ard1-2z.js → circle-check-Bb54Ebmu.js} +0 -0
  412. /package/dist/ui/assets/{cpu-KDy6-FAI.js → cpu-Cdgc_B1K.js} +0 -0
  413. /package/dist/ui/assets/{download-Cjbk4Rek.js → download-C3ifGMjJ.js} +0 -0
  414. /package/dist/ui/assets/{external-link-HtrFM63g.js → external-link-BvxYeTP1.js} +0 -0
  415. /package/dist/ui/assets/{eye-D1dB40_o.js → eye-DqNTU_GD.js} +0 -0
  416. /package/dist/ui/assets/{file-text-CE58EfH0.js → file-text-BT_9S9SM.js} +0 -0
  417. /package/dist/ui/assets/{folder-open-DIPKeiI_.js → folder-open-BhH8y9ac.js} +0 -0
  418. /package/dist/ui/assets/{format-BwdV8bB5.js → format-GVHeOyWI.js} +0 -0
  419. /package/dist/ui/assets/{gateway-url-D5uj6Nxg.js → gateway-url-COCbW0IR.js} +0 -0
  420. /package/dist/ui/assets/{gauge-DmQmJHEg.js → gauge-D_TMa4i9.js} +0 -0
  421. /package/dist/ui/assets/{globe-_hUGxQF4.js → globe-DeCQTCDJ.js} +0 -0
  422. /package/dist/ui/assets/{hexagon-BaNGQlQj.js → hexagon-DsGOUl-H.js} +0 -0
  423. /package/dist/ui/assets/{history-BfZVGlZa.js → history-BSG-Ypqf.js} +0 -0
  424. /package/dist/ui/assets/{info-CBZ5-AlC.js → info-NwLoa2Mj.js} +0 -0
  425. /package/dist/ui/assets/{key-Bv5DdTPh.js → key-3EP0dhkT.js} +0 -0
  426. /package/dist/ui/assets/{loader-circle-C4hhXLgp.js → loader-circle-CZNax6kS.js} +0 -0
  427. /package/dist/ui/assets/{lock-CkZYexqw.js → lock-Ei1_J-Nq.js} +0 -0
  428. /package/dist/ui/assets/{pause-Bpy1_s7y.js → pause-BUqah9Bi.js} +0 -0
  429. /package/dist/ui/assets/{play-Cj4osqJZ.js → play-NcZ4swwL.js} +0 -0
  430. /package/dist/ui/assets/{plus-BQhgZN3A.js → plus-CX1xyhp5.js} +0 -0
  431. /package/dist/ui/assets/{refresh-cw-BfREHVQM.js → refresh-cw-DaYdjQFk.js} +0 -0
  432. /package/dist/ui/assets/{save-FFTD4dMp.js → save-CUdYyHNy.js} +0 -0
  433. /package/dist/ui/assets/{settings-BdHKUL92.js → settings-Ds4SqD8s.js} +0 -0
  434. /package/dist/ui/assets/{sparkles-r4uJbJAl.js → sparkles-yUEb-7oH.js} +0 -0
  435. /package/dist/ui/assets/{square-G7Hyufqm.js → square-BD81nFtN.js} +0 -0
  436. /package/dist/ui/assets/{textarea-5kyuD04X.js → textarea-CXgXWKrT.js} +0 -0
  437. /package/dist/ui/assets/{trash-2-DXVBRWfh.js → trash-2-CNjMkoq6.js} +0 -0
  438. /package/dist/ui/assets/{triangle-alert-Bu5seg9O.js → triangle-alert-C9Y8Ub4X.js} +0 -0
  439. /package/dist/ui/assets/{vendor-router-CCECILJ0.js → vendor-router-C9pIYwbJ.js} +0 -0
  440. /package/dist/ui/assets/{volume-2-s9DuS696.js → volume-2-CeSXNDv4.js} +0 -0
  441. /package/dist/ui/assets/{zap-BPHZzXKV.js → zap-hlXjpSeA.js} +0 -0
@@ -0,0 +1,1506 @@
1
+ import { logger } from "../utils/logger.ts";
2
+ import { getDb, initializeDatabase } from "./sqlite";
3
+ import {
4
+ storeProviderApiKey,
5
+ storeChannelConfig,
6
+ storeMcpEnv,
7
+ loadProviderApiKey,
8
+ loadChannelConfig,
9
+ } from "./crypto";
10
+ import { seedAllData, SEED_DATA } from "./seed";
11
+ import { SkillLoader } from "@johpaz/hive-agents-skills";
12
+
13
+ export interface OnboardingSection {
14
+ step: "user" | "skills" | "ethics" | "tools" | "provider" | "model" | "channel" | "mcp" | "agent" | "complete";
15
+ userId: string;
16
+ data: Record<string, unknown>;
17
+ completedAt?: number;
18
+ }
19
+
20
+ const log = logger.child("onboarding");
21
+ // 9️⃣ Hive System Prompt
22
+
23
+ const HIVE_SYSTEM_PROMPT = `
24
+ # HIVE — Agente Coordinador
25
+
26
+ Sos Bee, coordinador de Hive. Resolvés tareas del usuario directamente o delegando a workers especializados. Tu rol es "coordinator".
27
+
28
+ ## ⚡ REGLAS CRÍTICAS
29
+
30
+ 1. **Ética primero** — Operás bajo un Código de Ética obligatorio. No podés ignorarlo.
31
+ 2. **Confirmá antes de guardar** — Siempre verificá con el usuario antes de persistir datos en la BD.
32
+ 3. **Buscá antes de crear** — Usá search_knowledge para capacidades, find_agent para workers.
33
+ 4. **Mínimo privilegio** — Asigná solo las tools necesarias a cada worker.
34
+ 5. **Nunca cli_exec para cron** — Usá siempre cron.create para tareas programadas.
35
+ ## 🔍 DISCOVERY — CÓMO ENCONTRAR MÁS CAPACIDADES
36
+
37
+ Arrancás con solo 4 herramientas. Para descubrir más, usá **search_knowledge**:
38
+
39
+ - \`search_knowledge(type="tools", query="leer archivos")\` → herramientas nativas
40
+ - \`search_knowledge(type="mcp", query="listar bases datos")\` → herramientas MCP externas
41
+ - \`search_knowledge(type="skills", query="debuggear código")\` → skills (instrucciones de tareas)
42
+ - \`search_knowledge(type="playbook", query="seguridad")\` → playbook (buenas prácticas)
43
+ - \`search_knowledge(type="all", query="buscar web internet")\` → busca en todo
44
+
45
+ La búsqueda es bilingüe: buscá en español y si hay pocos resultados se re-intenta con equivalentes en inglés.
46
+
47
+ **Prioridad:** SIEMPRE preferí herramientas nativas sobre MCP cuando ambas resuelven la tarea.
48
+
49
+ ## 📋 FLUJO DE TRABAJO
50
+
51
+ **Tarea simple (1-2 pasos):** Ejecutala directo con tus tools.
52
+
53
+ **Tarea repetitiva:** Usá cron.create. Preguntá al usuario cada cuánto ejecutarla.
54
+
55
+ **Tarea compleja (múltiples workers):** Creá un agente con create_agent, descomponé el trabajo, delegá con delegate_task.
56
+
57
+ **Worker:** find_agent → ¿existe? → reutilizalo. Si no → create_agent con system_prompt claro y tools_json mínimo. **delegate_task** lo activa.
58
+
59
+ **Cierre:** Usá notify o report_progress para informar al usuario del resultado final.
60
+
61
+ ## 🧠 MEMORIA
62
+
63
+ - \`save_note\` — Persiste notas por conversación (sobrevive compresión)
64
+ - \`memory_write\` / \`memory_read\` — Memoria cross-conversación por clave
65
+ - Playbook — Reglas aprendidas inyectadas automáticamente
66
+
67
+ ## 📡 CANALES
68
+
69
+ webchat (siempre activo) · telegram · discord · slack · whatsapp
70
+ Canal preferido para cron: telegram > discord > webchat
71
+ `
72
+ export function initOnboardingDb(): void {
73
+ try {
74
+ initializeDatabase();
75
+
76
+ // Verificar si la DB ya tiene datos antes de hacer seed
77
+ const db = getDb();
78
+ const userCount = db.query("SELECT COUNT(*) as count FROM users").get() as { count: number };
79
+
80
+ if (userCount.count > 0) {
81
+ log.info("✅ DB ya inicializada con " + userCount.count + " usuario(s). Saltando seed.");
82
+ return;
83
+ }
84
+
85
+ log.info("🌱 Ejecutando seed de datos...");
86
+ seedAllData();
87
+ log.info("✅ Seed completado correctamente.");
88
+ } catch (e) {
89
+ log.error("⚠️ Fallo al inicializar/poblar la DB:", { error: (e as Error).message });
90
+ }
91
+ }
92
+
93
+ export function saveUserProfile(data: {
94
+ userId?: string;
95
+ userName?: string;
96
+ userLanguage?: string;
97
+ userTimezone?: string;
98
+ userOccupation?: string;
99
+ userNotes?: string;
100
+ agentName?: string;
101
+ agentId?: string;
102
+ agentDescription?: string;
103
+ agentTone?: string;
104
+ channelUserId?: string;
105
+ }): string {
106
+ try {
107
+ const db = getDb();
108
+ let finalUserId = data.userId;
109
+
110
+ if (!finalUserId) {
111
+ // 1️⃣ Dejar que SQLite genere el ID automáticamente con randomblob(16)
112
+ const result = db.query(`
113
+ INSERT INTO users(name, language, timezone, occupation, notes)
114
+ VALUES(?, ?, ?, ?, ?) RETURNING id
115
+ `).get(
116
+ data.userName || null,
117
+ data.userLanguage || null,
118
+ data.userTimezone || null,
119
+ data.userOccupation || null,
120
+ data.userNotes || null
121
+ ) as { id: string };
122
+ finalUserId = result.id;
123
+ log.info("✅ User created with auto-generated ID", { userId: finalUserId });
124
+ } else {
125
+ // 1️⃣ Upsert con ID explícito (flujo web o actualización)
126
+ db.query(`
127
+ INSERT INTO users(id, name, language, timezone, occupation, notes)
128
+ VALUES(?, ?, ?, ?, ?, ?)
129
+ ON CONFLICT(id) DO UPDATE SET
130
+ name = COALESCE(excluded.name, name),
131
+ language = COALESCE(excluded.language, language),
132
+ timezone = COALESCE(excluded.timezone, timezone),
133
+ occupation = COALESCE(excluded.occupation, occupation),
134
+ notes = COALESCE(excluded.notes, notes)
135
+ `).run(
136
+ finalUserId,
137
+ data.userName || null,
138
+ data.userLanguage || null,
139
+ data.userTimezone || null,
140
+ data.userOccupation || null,
141
+ data.userNotes || null
142
+ );
143
+ }
144
+
145
+ // 2️⃣ Crear identidad base para webchat (sesión única)
146
+ if (data.channelUserId) {
147
+ db.query(`
148
+ INSERT OR REPLACE INTO user_identities(user_id, channel, channel_user_id)
149
+ VALUES(?, 'webchat', ?)
150
+ `).run(finalUserId, data.channelUserId);
151
+ log.info("✅ User identity created for webchat", { userId: finalUserId });
152
+ }
153
+
154
+ // 3️⃣ Crear o actualizar agente
155
+ if (data.agentId && data.agentName) {
156
+
157
+ db.query(`
158
+ INSERT INTO agents
159
+ (id, user_id, name, description, tone, system_prompt, status, role)
160
+ VALUES(?, ?, ?, ?, ?, ?, 'idle', 'coordinator')
161
+ ON CONFLICT(id) DO UPDATE SET
162
+ user_id = COALESCE(excluded.user_id, user_id),
163
+ name = COALESCE(excluded.name, name),
164
+ description = COALESCE(excluded.description, description),
165
+ tone = COALESCE(excluded.tone, tone),
166
+ system_prompt = excluded.system_prompt,
167
+ role = 'coordinator'
168
+ `).run(
169
+ data.agentId,
170
+ finalUserId,
171
+ data.agentName,
172
+ data.agentDescription || null,
173
+ data.agentTone || null,
174
+ HIVE_SYSTEM_PROMPT,
175
+ );
176
+ }
177
+
178
+ return finalUserId;
179
+ } catch (e) {
180
+ log.error("⚠️ Error saving user profile:", { error: (e as Error).message });
181
+ throw e;
182
+ }
183
+ }
184
+
185
+ export function activateSkills(userId: string, skillIds: string[]): void {
186
+ try {
187
+ const db = getDb();
188
+ // Activar skills seleccionadas
189
+ for (const skillId of skillIds) {
190
+ db.query(`UPDATE skills SET active = 1 WHERE id = ? `).run(skillId);
191
+ }
192
+ log.info("✅ Skills activadas:", { skillIds: skillIds.join(", ") });
193
+ } catch (e) {
194
+ log.error("⚠️ Error activating skills:", { error: (e as Error).message });
195
+ }
196
+ }
197
+
198
+ export function activateEthics(userId: string, ethicsId: string): void {
199
+ try {
200
+ const db = getDb();
201
+ // Activar el ethics seleccionado
202
+ db.query(`UPDATE ethics SET active = 1 WHERE id = ? `).run(ethicsId);
203
+ // Desactivar los demás
204
+ db.query(`UPDATE ethics SET active = 0 WHERE id != ? `).run(ethicsId);
205
+ log.info("✅ Ethics activado:", { ethicsId });
206
+ } catch (e) {
207
+ log.error("⚠️ Error activating ethics:", { error: (e as Error).message });
208
+ }
209
+ }
210
+
211
+ export function activateTools(userId: string, toolIds: string[]): void {
212
+ try {
213
+ const db = getDb();
214
+ // Activar tools seleccionadas
215
+ for (const toolId of toolIds) {
216
+ db.query(`UPDATE tools SET active = 1, enabled = 1 WHERE id = ? `).run(toolId);
217
+ }
218
+ log.info("✅ Tools activadas:", { toolIds: toolIds.join(", ") });
219
+ } catch (e) {
220
+ log.error("⚠️ Error activating tools:", { error: (e as Error).message });
221
+ }
222
+ }
223
+
224
+ /**
225
+ * Activate all browser tools when Chromium is available
226
+ * Called from gateway initializer when browser service connects successfully
227
+ */
228
+ export function activateBrowserTools(): void {
229
+ try {
230
+ const db = getDb();
231
+ const browserToolIds = [
232
+ "browser_navigate",
233
+ "browser_screenshot",
234
+ "browser_click",
235
+ "browser_type",
236
+ "browser_extract",
237
+ "browser_script",
238
+ "browser_wait",
239
+ ];
240
+
241
+ for (const toolId of browserToolIds) {
242
+ db.query(`UPDATE tools SET active = 1, enabled = 1 WHERE id = ? `).run(toolId);
243
+ }
244
+ log.info("✅ Browser tools activated (Chromium available)");
245
+ } catch (e) {
246
+ log.error("⚠️ Error activating browser tools:", { error: (e as Error).message });
247
+ }
248
+ }
249
+
250
+ export async function saveProviderConfig(data: {
251
+ userId: string;
252
+ provider: string;
253
+ model: string;
254
+ apiKey?: string;
255
+ baseUrl?: string;
256
+ }): Promise<void> {
257
+ try {
258
+ const db = getDb();
259
+
260
+ // 1️⃣ Primero: Actualizar provider global con API key del usuario
261
+ db.query(`
262
+ UPDATE providers SET base_url = ?, enabled = 1, active = 1 WHERE id = ?
263
+ `).run(data.baseUrl || null, data.provider);
264
+
265
+ if (data.apiKey) {
266
+ await storeProviderApiKey(data.provider as string, data.apiKey as string);
267
+ }
268
+
269
+ log.info("✅ Provider actualizado:", { provider: data.provider });
270
+
271
+ // 2️⃣ Segundo: Activar el modelo seleccionado
272
+ // For Ollama, models are inserted dynamically (not seeded), ensure row exists first
273
+ if (data.provider === "ollama" && data.model) {
274
+ db.query(`
275
+ INSERT OR IGNORE INTO models(id, name, provider_id, model_type, enabled, active)
276
+ VALUES(?, ?, 'ollama', 'llm', 1, 1)
277
+ `).run(data.model, data.model);
278
+ }
279
+
280
+ db.query(`
281
+ UPDATE models SET enabled = 1, active = 1
282
+ WHERE id = ?
283
+ `).run(data.model);
284
+
285
+ log.info("✅ Model activado:", { model: data.model });
286
+ } catch (e) {
287
+ log.error("⚠️ Error saving provider:", { error: (e as Error).message });
288
+ throw e;
289
+ }
290
+ }
291
+
292
+ export function activateMcpServers(userId: string, mcpIds: string[]): void {
293
+ try {
294
+ const db = getDb();
295
+ // Activar MCP servers seleccionados
296
+ for (const mcpId of mcpIds) {
297
+ db.query(`UPDATE mcp_servers SET active = 1, enabled = 1 WHERE id = ? `).run(mcpId);
298
+ }
299
+ log.info("✅ MCP servers activados:", { mcpIds: mcpIds.join(", ") });
300
+ } catch (e) {
301
+ log.error("⚠️ Error activating MCP servers:", { error: (e as Error).message });
302
+ }
303
+ }
304
+
305
+
306
+ export function saveAgentConfig(data: {
307
+ userId: string;
308
+ agentId?: string;
309
+ agentName: string;
310
+ providerId: string;
311
+ modelId: string;
312
+ tone: string;
313
+ description?: string;
314
+ }): string {
315
+ try {
316
+ const db = getDb();
317
+ let finalAgentId = data.agentId;
318
+
319
+ // Validate FK references — use null if the referenced row doesn't exist
320
+ // (e.g. custom Ollama model IDs are not in the seed models table)
321
+ const rawProviderId = data.providerId || null;
322
+ const rawModelId = data.modelId || null;
323
+ const safeProviderId = rawProviderId && db.query("SELECT id FROM providers WHERE id = ?").get(rawProviderId) ? rawProviderId : null;
324
+ const safeModelId = rawModelId && db.query("SELECT id FROM models WHERE id = ?").get(rawModelId) ? rawModelId : null;
325
+
326
+ // Si no se pasa agentId, dejar que SQLite lo genere automáticamente
327
+ if (!finalAgentId) {
328
+ const result = db.query(`
329
+ INSERT INTO agents
330
+ (user_id, name, description, tone, system_prompt, provider_id, model_id, status, role, enabled)
331
+ VALUES(?, ?, ?, ?, ?, ?, ?, 'idle', 'coordinator', 1)
332
+ RETURNING id
333
+ `).get(
334
+ data.userId,
335
+ data.agentName,
336
+ data.description || null,
337
+ data.tone,
338
+ HIVE_SYSTEM_PROMPT,
339
+ safeProviderId,
340
+ safeModelId
341
+ ) as { id: string };
342
+ finalAgentId = result.id;
343
+ log.info("✅ Agent created with auto-generated ID", { agentId: finalAgentId });
344
+ } else {
345
+ // INSERT or UPDATE agent (crea nuevo o actualiza existente)
346
+ db.query(`
347
+ INSERT INTO agents
348
+ (id, user_id, name, description, tone, system_prompt, provider_id, model_id, status, role, enabled)
349
+ VALUES(?, ?, ?, ?, ?, ?, ?, ?, 'idle', 'coordinator', 1)
350
+ ON CONFLICT(id) DO UPDATE SET
351
+ user_id = COALESCE(excluded.user_id, user_id),
352
+ name = COALESCE(excluded.name, name),
353
+ description = COALESCE(excluded.description, description),
354
+ tone = COALESCE(excluded.tone, tone),
355
+ system_prompt = excluded.system_prompt,
356
+ provider_id = COALESCE(excluded.provider_id, provider_id),
357
+ model_id = COALESCE(excluded.model_id, model_id),
358
+ status = 'idle',
359
+ enabled = 1,
360
+ role = 'coordinator'
361
+ `).run(
362
+ data.agentId,
363
+ data.userId,
364
+ data.agentName,
365
+ data.description || null,
366
+ data.tone,
367
+ HIVE_SYSTEM_PROMPT,
368
+ safeProviderId,
369
+ safeModelId
370
+ );
371
+ }
372
+
373
+ return finalAgentId;
374
+ } catch (e) {
375
+ log.error("⚠️ Error saving agent:", { error: (e as Error).message });
376
+ throw e;
377
+ }
378
+ }
379
+
380
+ export async function activateChannel(userId: string, data: {
381
+ channelId: string;
382
+ channelUserId?: string; // For creating user_identity
383
+ config?: Record<string, unknown>;
384
+ }): Promise<void> {
385
+ try {
386
+ const db = getDb();
387
+
388
+ db.query(`
389
+ UPDATE channels SET user_id = ?, active = 1, enabled = 1, status = 'connected' WHERE id = ?
390
+ `).run(userId, data.channelId);
391
+
392
+ if (data.config && Object.keys(data.config).length > 0) {
393
+ await storeChannelConfig(data.channelId, data.config);
394
+ }
395
+
396
+ // Create user_identity for the channel if channelUserId provided
397
+ if (data.channelUserId) {
398
+ const channelType = data.channelId; // webchat, telegram, discord, etc.
399
+ db.query(`
400
+ INSERT OR REPLACE INTO user_identities(user_id, channel, channel_user_id)
401
+ VALUES(?, ?, ?)
402
+ `).run(userId, channelType, data.channelUserId);
403
+ log.info("✅ User identity created", { userId, channel: channelType });
404
+ }
405
+
406
+ log.info("✅ Channel activated:", { channelId: data.channelId, userId });
407
+ } catch (e) {
408
+ log.error("⚠️ Error activating channel:", { error: (e as Error).message });
409
+ }
410
+ }
411
+
412
+ export async function saveVoiceConfig(data: {
413
+ userId: string;
414
+ channelId: string;
415
+ voiceEnabled: boolean;
416
+ sttProvider: string;
417
+ ttsProvider: string;
418
+ sttApiKey?: string;
419
+ ttsApiKey?: string;
420
+ }): Promise<void> {
421
+ try {
422
+ const db = getDb();
423
+
424
+ // Activate STT and TTS models
425
+ db.query(`UPDATE models SET active = 1, enabled = 1 WHERE id = ? `).run(data.sttProvider);
426
+ db.query(`UPDATE models SET active = 1, enabled = 1 WHERE id = ? `).run(data.ttsProvider);
427
+
428
+ // Determine provider IDs based on model IDs
429
+ let sttProviderId = "";
430
+ let ttsProviderId = "";
431
+
432
+ if (data.sttProvider.startsWith("whisper") || data.sttProvider === "distil-whisper-large-v3-en") {
433
+ sttProviderId = "groq";
434
+ } else if (data.sttProvider === "whisper-1") {
435
+ sttProviderId = "openai";
436
+ }
437
+
438
+ if (data.ttsProvider.startsWith("eleven")) {
439
+ ttsProviderId = "elevenlabs";
440
+ } else if (data.ttsProvider.startsWith("tts-") || data.ttsProvider.startsWith("gpt-")) {
441
+ ttsProviderId = "openai";
442
+ } else if (data.ttsProvider.startsWith("gemini")) {
443
+ ttsProviderId = "gemini";
444
+ } else if (data.ttsProvider.startsWith("qwen")) {
445
+ ttsProviderId = "qwen";
446
+ }
447
+
448
+ // Save STT API key to provider if provided
449
+ if (data.sttApiKey && sttProviderId) {
450
+ db.query(`UPDATE providers SET enabled = 1, active = 1 WHERE id = ?`).run(sttProviderId);
451
+ await storeProviderApiKey(sttProviderId, data.sttApiKey);
452
+ log.info("✅ STT API key guardada en keychain", { provider: sttProviderId });
453
+ }
454
+
455
+ // Save TTS API key to provider if provided
456
+ if (data.ttsApiKey && ttsProviderId) {
457
+ db.query(`UPDATE providers SET enabled = 1, active = 1 WHERE id = ?`).run(ttsProviderId);
458
+ await storeProviderApiKey(ttsProviderId, data.ttsApiKey);
459
+ log.info("✅ TTS API key guardada en keychain", { provider: ttsProviderId });
460
+ }
461
+
462
+ // Update channel with voice config
463
+ db.query(`
464
+ UPDATE channels
465
+ SET user_id = ?, voice_enabled = ?, stt_provider = ?, tts_provider = ?
466
+ WHERE id = ?
467
+ `).run(data.userId, data.voiceEnabled ? 1 : 0, data.sttProvider, data.ttsProvider, data.channelId);
468
+
469
+ log.info("✅ Voice config saved:", {
470
+ channelId: data.channelId,
471
+ userId: data.userId,
472
+ sttProvider: data.sttProvider,
473
+ ttsProvider: data.ttsProvider,
474
+ sttProviderId,
475
+ ttsProviderId
476
+ });
477
+ } catch (e) {
478
+ log.error("⚠️ Error saving voice config:", { error: (e as Error).message });
479
+ }
480
+ }
481
+
482
+ export async function saveMcpServer(data: {
483
+ userId: string;
484
+ name: string;
485
+ transport: string;
486
+ command?: string;
487
+ args?: string[];
488
+ env?: Record<string, string>;
489
+ url?: string;
490
+ enabled?: boolean;
491
+ }): Promise<void> {
492
+ try {
493
+ const db = getDb();
494
+
495
+ const mcpId = `${data.userId}:${data.name} `;
496
+
497
+ db.query(`
498
+ INSERT OR REPLACE INTO mcp_servers
499
+ (id, user_id, name, transport, command, args, url, enabled, builtin)
500
+ VALUES(?, ?, ?, ?, ?, ?, ?, ?, 0)
501
+ `).run(
502
+ mcpId,
503
+ data.userId,
504
+ data.name,
505
+ data.transport,
506
+ data.command || null,
507
+ JSON.stringify(data.args || []),
508
+ data.url || null,
509
+ data.enabled ? 1 : 0
510
+ );
511
+
512
+ if (data.env && Object.keys(data.env).length > 0) {
513
+ await storeMcpEnv(mcpId, data.env);
514
+ }
515
+
516
+ log.info("✅ MCP server saved:", { name: data.name });
517
+ } catch (e) {
518
+ log.error("⚠️ Error saving MCP server:", { error: (e as Error).message });
519
+ }
520
+ }
521
+
522
+ export function saveToolSelection(userId: string, tools: string[]): void {
523
+ try {
524
+ const db = getDb();
525
+
526
+ for (const tool of tools) {
527
+ // Activar la herramienta (ya existe del seed)
528
+ db.query(`
529
+ UPDATE tools SET active = 1, enabled = 1
530
+ WHERE id = ?
531
+ `).run(tool);
532
+ }
533
+
534
+ log.info("✅ Tools activadas:", { tools: tools.join(", ") });
535
+ } catch (e) {
536
+ log.error("⚠️ Error saving tools:", { error: (e as Error).message });
537
+ }
538
+ }
539
+
540
+ export function activateProvider(providerId: string): void {
541
+ try {
542
+ const db = getDb();
543
+ db.query(`
544
+ UPDATE providers SET active = 1, enabled = 1
545
+ WHERE id = ?
546
+ `).run(providerId);
547
+ log.info("✅ Provider activado:", { providerId });
548
+ } catch (e) {
549
+ log.error("⚠️ Error activating provider:", { error: (e as Error).message });
550
+ }
551
+ }
552
+
553
+ export function activateModel(modelId: string): void {
554
+ try {
555
+ const db = getDb();
556
+ db.query(`
557
+ UPDATE models SET active = 1, enabled = 1
558
+ WHERE id = ?
559
+ `).run(modelId);
560
+ log.info("✅ Model activado:", { modelId });
561
+ } catch (e) {
562
+ log.error("⚠️ Error activating model:", { error: (e as Error).message });
563
+ }
564
+ }
565
+
566
+
567
+
568
+ export function activateMcpServer(mcpName: string): void {
569
+ try {
570
+ const db = getDb();
571
+ db.query(`
572
+ UPDATE mcp_servers SET active = 1, enabled = 1
573
+ WHERE id = ?
574
+ `).run(mcpName);
575
+ log.info("✅ MCP server activado:", { mcpName });
576
+ } catch (e) {
577
+ log.error("⚠️ Error activating MCP server:", { error: (e as Error).message });
578
+ }
579
+ }
580
+
581
+ export function deactivateProvider(providerId: string): void {
582
+ try {
583
+ const db = getDb();
584
+ db.query(`
585
+ UPDATE providers SET active = 0, enabled = 0
586
+ WHERE id = ?
587
+ `).run(providerId);
588
+ log.warn("⚠️ Provider desactivado:", { providerId });
589
+ } catch (e) {
590
+ log.error("⚠️ Error deactivating provider:", { error: (e as Error).message });
591
+ }
592
+ }
593
+
594
+ export function deactivateModel(modelId: string): void {
595
+ try {
596
+ const db = getDb();
597
+ db.query(`
598
+ UPDATE models SET active = 0, enabled = 0
599
+ WHERE id = ?
600
+ `).run(modelId);
601
+ log.warn("⚠️ Model desactivado:", { modelId });
602
+ } catch (e) {
603
+ log.error("⚠️ Error deactivating model:", { error: (e as Error).message });
604
+ }
605
+ }
606
+
607
+ export function deactivateChannel(channelType: string): void {
608
+ try {
609
+ const db = getDb();
610
+ db.query(`
611
+ UPDATE channels SET active = 0, enabled = 0
612
+ WHERE id = ?
613
+ `).run(channelType);
614
+ log.warn("⚠️ Channel desactivado:", { channelType });
615
+ } catch (e) {
616
+ log.error("⚠️ Error deactivating channel:", { error: (e as Error).message });
617
+ }
618
+ }
619
+
620
+ export function deactivateMcpServer(mcpName: string): void {
621
+ try {
622
+ const db = getDb();
623
+ db.query(`
624
+ UPDATE mcp_servers SET active = 0, enabled = 0
625
+ WHERE id = ?
626
+ `).run(mcpName);
627
+ log.warn("⚠️ MCP server desactivado:", { mcpName });
628
+ } catch (e) {
629
+ log.error("⚠️ Error deactivating MCP server:", { error: (e as Error).message });
630
+ }
631
+ }
632
+
633
+ export function getAllProviders(): Array<{
634
+ id: string;
635
+ name: string;
636
+ baseUrl: string | null;
637
+ enabled: boolean;
638
+ active: boolean;
639
+ }> {
640
+ try {
641
+ const db = getDb();
642
+ const results = db.query(`
643
+ SELECT id, name, base_url, enabled, active
644
+ FROM providers
645
+ `).all() as Array<{
646
+ id: string;
647
+ name: string;
648
+ base_url: string | null;
649
+ enabled: number;
650
+ active: number;
651
+ }>;
652
+
653
+ return results.map(r => ({
654
+ id: r.id,
655
+ name: r.name,
656
+ baseUrl: r.base_url,
657
+ enabled: r.enabled === 1,
658
+ active: r.active === 1,
659
+ }));
660
+ } catch (e) {
661
+ log.warn("[onboarding] ⚠️ Error getting providers:", (e as Error).message);
662
+ return [];
663
+ }
664
+ }
665
+
666
+ export function getAllModels(): Array<{
667
+ id: string;
668
+ name: string;
669
+ providerId: string;
670
+ contextWindow: number | null;
671
+ capabilities: string | null;
672
+ enabled: boolean;
673
+ active: boolean;
674
+ }> {
675
+ try {
676
+ const db = getDb();
677
+ const results = db.query(`
678
+ SELECT id, name, provider_id, context_window, capabilities, enabled, active
679
+ FROM models
680
+ `).all() as Array<{
681
+ id: string;
682
+ name: string;
683
+ provider_id: string;
684
+ context_window: number | null;
685
+ capabilities: string | null;
686
+ enabled: number;
687
+ active: number;
688
+ }>;
689
+
690
+ return results.map(r => ({
691
+ id: r.id,
692
+ name: r.name,
693
+ providerId: r.provider_id,
694
+ contextWindow: r.context_window,
695
+ capabilities: r.capabilities,
696
+ enabled: r.enabled === 1,
697
+ active: r.active === 1,
698
+ }));
699
+ } catch (e) {
700
+ log.error("⚠️ Error getting models:", { error: (e as Error).message });
701
+ return [];
702
+ }
703
+ }
704
+
705
+ export function getAllEthics(): Array<{
706
+ id: string;
707
+ name: string;
708
+ description: string | null;
709
+ content: string;
710
+ isDefault: boolean;
711
+ active: boolean;
712
+ }> {
713
+ try {
714
+ const db = getDb();
715
+ const results = db.query(`
716
+ SELECT id, name, description, content, is_default, active
717
+ FROM ethics
718
+ `).all() as Array<{
719
+ id: string;
720
+ name: string;
721
+ description: string | null;
722
+ content: string;
723
+ is_default: number;
724
+ active: number;
725
+ }>;
726
+
727
+ return results.map(r => ({
728
+ id: r.id,
729
+ name: r.name,
730
+ description: r.description,
731
+ content: r.content,
732
+ isDefault: r.is_default === 1,
733
+ active: r.active === 1,
734
+ }));
735
+ } catch (e) {
736
+ log.error("⚠️ Error getting ethics:", { error: (e as Error).message });
737
+ return [];
738
+ }
739
+ }
740
+
741
+ export function getAllSkills(): Array<{
742
+ id: string;
743
+ name: string;
744
+ description: string | null;
745
+ source: string;
746
+ isGlobal: boolean;
747
+ enabled: boolean;
748
+ active: boolean;
749
+ }> {
750
+ try {
751
+ const db = getDb();
752
+ const results = db.query(`
753
+ SELECT id, name, api_key_encrypted, api_key_iv, base_url, enabled
754
+ FROM providers
755
+ `).all() as Array<{
756
+ id: string;
757
+ name: string;
758
+ description: string | null;
759
+ source: string;
760
+ enabled: number;
761
+ active: number;
762
+ }>;
763
+
764
+ return results.map(r => ({
765
+ id: r.id,
766
+ name: r.name,
767
+ description: r.description,
768
+ source: r.source,
769
+ isGlobal: false,
770
+ enabled: r.enabled === 1,
771
+ active: r.active === 1,
772
+ }));
773
+ } catch (e) {
774
+ log.error("⚠️ Error getting skills:", { error: (e as Error).message });
775
+ return [];
776
+ }
777
+ }
778
+
779
+ export function getAllDbTools(): Array<{
780
+ id: string;
781
+ name: string;
782
+ description: string | null;
783
+ category: string | null;
784
+ enabled: boolean;
785
+ active: boolean;
786
+ }> {
787
+ try {
788
+ const db = getDb();
789
+ const results = db.query(`
790
+ SELECT id, name, description, category, enabled, active
791
+ FROM tools
792
+ `).all() as Array<{
793
+ id: string;
794
+ name: string;
795
+ description: string | null;
796
+ category: string | null;
797
+ enabled: number;
798
+ active: number;
799
+ }>;
800
+
801
+ return results.map(r => ({
802
+ id: r.id,
803
+ name: r.name,
804
+ description: r.description,
805
+ category: r.category,
806
+ enabled: r.enabled === 1,
807
+ active: r.active === 1,
808
+ }));
809
+ } catch (e) {
810
+ log.error("⚠️ Error getting tools:", { error: (e as Error).message });
811
+ return [];
812
+ }
813
+ }
814
+
815
+ export function getAllMcpServers(): Array<{
816
+ id: string;
817
+ name: string;
818
+ transport: string;
819
+ command: string | null;
820
+ args: string | null;
821
+ url: string | null;
822
+ builtin: boolean;
823
+ enabled: boolean;
824
+ active: boolean;
825
+ }> {
826
+ try {
827
+ const db = getDb();
828
+ const results = db.query(`
829
+ SELECT id, name, transport, command, args, url, builtin, enabled, active
830
+ FROM mcp_servers
831
+ `).all() as Array<{
832
+ id: string;
833
+ name: string;
834
+ transport: string;
835
+ command: string | null;
836
+ args: string | null;
837
+ url: string | null;
838
+ builtin: number;
839
+ enabled: number;
840
+ active: number;
841
+ }>;
842
+
843
+ return results.map(r => ({
844
+ id: r.id,
845
+ name: r.name,
846
+ transport: r.transport,
847
+ command: r.command,
848
+ args: r.args,
849
+ url: r.url,
850
+ builtin: r.builtin === 1,
851
+ enabled: r.enabled === 1,
852
+ active: r.active === 1,
853
+ }));
854
+ } catch (e) {
855
+ log.error("⚠️ Error getting MCP servers:", { error: (e as Error).message });
856
+ return [];
857
+ }
858
+ }
859
+
860
+ export function getAllChannels(): Array<{
861
+ id: string;
862
+ type: string;
863
+ accountId: string;
864
+ status: string;
865
+ enabled: boolean;
866
+ active: boolean;
867
+ }> {
868
+ try {
869
+ const db = getDb();
870
+ const results = db.query(`
871
+ SELECT id, type, id as account_id, status, enabled, active
872
+ FROM channels
873
+ `).all() as Array<{
874
+ id: string;
875
+ type: string;
876
+ account_id: string;
877
+ status: string;
878
+ enabled: number;
879
+ active: number;
880
+ }>;
881
+
882
+ return results.map(r => ({
883
+ id: r.id,
884
+ type: r.type,
885
+ accountId: r.id,
886
+ status: r.status,
887
+ enabled: r.enabled === 1,
888
+ active: r.active === 1,
889
+ }));
890
+ } catch (e) {
891
+ log.warn("[onboarding] ⚠️ Error getting channels:", (e as Error).message);
892
+ return [];
893
+ }
894
+ }
895
+
896
+ export function getActiveTools(): Array<{
897
+ id: string;
898
+ name: string;
899
+ description: string | null;
900
+ category: string | null;
901
+ }> {
902
+ try {
903
+ const db = getDb();
904
+ const results = db.query(`
905
+ SELECT id, name, description, category
906
+ FROM tools WHERE active = 1
907
+ `).all() as Array<{
908
+ id: string;
909
+ name: string;
910
+ description: string | null;
911
+ category: string | null;
912
+ }>;
913
+
914
+ return results.map(r => ({
915
+ id: r.id,
916
+ name: r.name,
917
+ description: r.description,
918
+ category: r.category,
919
+ }));
920
+ } catch (e) {
921
+ log.error("⚠️ Error getting active tools:", { error: (e as Error).message });
922
+ return [];
923
+ }
924
+ }
925
+
926
+ export function getOnboardingProgress(userId: string): OnboardingSection | null {
927
+ try {
928
+ const db = getDb();
929
+ const result = db.query<{ step: string; data: string }, [string]>(
930
+ "SELECT step, data FROM onboarding_progress WHERE user_id = ? LIMIT 1"
931
+ ).get(userId);
932
+
933
+ if (result) {
934
+ return {
935
+ step: result.step as OnboardingSection["step"],
936
+ userId,
937
+ data: JSON.parse(result.data),
938
+ completedAt: Date.now(),
939
+ };
940
+ }
941
+ return null;
942
+ } catch {
943
+ return null;
944
+ }
945
+ }
946
+
947
+ export function saveOnboardingProgress(section: OnboardingSection): void {
948
+ try {
949
+ const db = getDb();
950
+ db.query(`
951
+ INSERT OR REPLACE INTO onboarding_progress(id, user_id, step, data)
952
+ VALUES(?, ?, ?, ?)
953
+ `).run(section.userId, section.userId, section.step, JSON.stringify(section.data));
954
+ } catch (e) {
955
+ log.error("⚠️ Error saving progress:", { error: (e as Error).message });
956
+ }
957
+ }
958
+
959
+ export async function getUserProviders(userId: string): Promise<Array<{
960
+ id: string;
961
+ name: string;
962
+ apiKey: string | null;
963
+ baseUrl: string | null;
964
+ enabled: boolean;
965
+ }>> {
966
+ try {
967
+ const db = getDb();
968
+ const results = db.query(`
969
+ SELECT id, name, api_key_encrypted, api_key_iv, base_url, enabled
970
+ FROM providers
971
+ `).all() as Array<{
972
+ id: string;
973
+ name: string;
974
+ api_key_encrypted: string | null;
975
+ api_key_iv: string | null;
976
+ base_url: string | null;
977
+ enabled: number;
978
+ }>;
979
+
980
+ return Promise.all(results.map(async r => ({
981
+ id: r.name,
982
+ name: r.name,
983
+ apiKey: await loadProviderApiKey(r.name) || null,
984
+ baseUrl: r.base_url,
985
+ enabled: r.enabled === 1,
986
+ })));
987
+ } catch (e) {
988
+ log.warn("[onboarding] ⚠️ Error getting providers:", (e as Error).message);
989
+ return [];
990
+ }
991
+ }
992
+
993
+ export async function getUserChannels(userId: string): Promise<Array<{
994
+ id: string;
995
+ type: string;
996
+ accountId: string;
997
+ config: Record<string, unknown>;
998
+ enabled: boolean;
999
+ }>> {
1000
+ try {
1001
+ const db = getDb();
1002
+ const results = db.query<{
1003
+ id: string;
1004
+ type: string;
1005
+ account_id: string;
1006
+ enabled: number;
1007
+ }, [string]>(`
1008
+ SELECT id, type, id as account_id, enabled FROM channels WHERE user_id = ?
1009
+ `).all(userId);
1010
+
1011
+ return Promise.all(results.map(async r => ({
1012
+ id: r.type,
1013
+ type: r.type,
1014
+ accountId: r.id,
1015
+ config: await loadChannelConfig(r.id),
1016
+ enabled: r.enabled === 1,
1017
+ })));
1018
+ } catch (e) {
1019
+ log.warn("[onboarding] ⚠️ Error getting channels:", (e as Error).message);
1020
+ return [];
1021
+ }
1022
+ }
1023
+
1024
+ export function getUserAgents(userId: string): Array<{
1025
+ id: string;
1026
+ name: string;
1027
+ providerId: string | null;
1028
+ modelId: string | null;
1029
+ tone: string;
1030
+ }> {
1031
+ try {
1032
+ const db = getDb();
1033
+ const results = db.query<{
1034
+ id: string;
1035
+ name: string;
1036
+ provider_id: string | null;
1037
+ model_id: string | null;
1038
+ tone: string;
1039
+ }, [string]>(`
1040
+ SELECT id, name, provider_id, model_id, tone
1041
+ FROM agents WHERE user_id = ?
1042
+ `).all(userId);
1043
+
1044
+ return results.map(r => ({
1045
+ id: r.id,
1046
+ name: r.name,
1047
+ providerId: r.provider_id,
1048
+ modelId: r.model_id,
1049
+ tone: r.tone || "friendly",
1050
+ }));
1051
+ } catch (e) {
1052
+ log.error("⚠️ Error getting agents:", { error: (e as Error).message });
1053
+ return [];
1054
+ }
1055
+ }
1056
+
1057
+ // ─── Identity Resolution Helpers ──────────────────────────────────────────────
1058
+ // These functions resolve userId and agentId from the database instead of environment variables
1059
+
1060
+ /**
1061
+ * Get the single user ID from the database.
1062
+ * Hive is designed around a single-user model, so this returns the first user found.
1063
+ * @returns The user ID or null if no users exist
1064
+ */
1065
+ export function getSingleUserId(): string | null {
1066
+ try {
1067
+ const db = getDb();
1068
+ const result = db.query("SELECT id FROM users LIMIT 1").get() as { id: string } | undefined;
1069
+ return result?.id || null;
1070
+ } catch (e) {
1071
+ log.warn("[getSingleUserId] ⚠️ Error getting user ID:", (e as Error).message);
1072
+ return null;
1073
+ }
1074
+ }
1075
+
1076
+ /**
1077
+ * Get the coordinator agent ID from the database.
1078
+ * The coordinator is the agent with role = 'coordinator'.
1079
+ * @returns The coordinator agent ID or null if not found
1080
+ */
1081
+ export function getCoordinatorAgentId(): string | null {
1082
+ try {
1083
+ const db = getDb();
1084
+ const result = db.query("SELECT id FROM agents WHERE role = 'coordinator' LIMIT 1").get() as { id: string } | undefined;
1085
+ return result?.id || null;
1086
+ } catch (e) {
1087
+ log.warn("[getCoordinatorAgentId] ⚠️ Error getting coordinator agent ID:", (e as Error).message);
1088
+ return null;
1089
+ }
1090
+ }
1091
+
1092
+ /**
1093
+ * Get the user ID associated with a specific channel identity.
1094
+ * @param channel The channel type (e.g., 'webchat', 'telegram', 'discord')
1095
+ * @param channelUserId The channel-specific user ID (e.g., Telegram chat_id)
1096
+ * @returns The Hive user ID or null if not found
1097
+ */
1098
+ export function getUserIdFromChannelIdentity(channel: string, channelUserId: string): string | null {
1099
+ try {
1100
+ const db = getDb();
1101
+ const result = db.query(
1102
+ "SELECT user_id FROM user_identities WHERE channel = ? AND channel_user_id = ? LIMIT 1"
1103
+ ).get(channel, channelUserId) as { user_id: string } | undefined;
1104
+ return result?.user_id || null;
1105
+ } catch (e) {
1106
+ log.warn("[getUserIdFromChannelIdentity] ⚠️ Error getting user ID from channel identity:", (e as Error).message);
1107
+ return null;
1108
+ }
1109
+ }
1110
+
1111
+ /**
1112
+ * Resolve the user ID from various sources with priority:
1113
+ * 1. Explicit userId parameter
1114
+ * 2. Channel identity lookup (if channel and channelUserId provided)
1115
+ * 3. Single user from database
1116
+ * 4. Null (no user found)
1117
+ */
1118
+ export function resolveUserId(
1119
+ opts: {
1120
+ userId?: string | null;
1121
+ threadId?: string | null;
1122
+ channel?: string | null;
1123
+ channelUserId?: string | null;
1124
+ }
1125
+ ): string | null {
1126
+ // Priority 1: Explicit userId
1127
+ if (opts.userId) {
1128
+ return opts.userId;
1129
+ }
1130
+
1131
+ // Priority 2: Channel identity lookup
1132
+ if (opts.channel && opts.channelUserId) {
1133
+ const userId = getUserIdFromChannelIdentity(opts.channel, opts.channelUserId);
1134
+ if (userId) {
1135
+ return userId;
1136
+ }
1137
+ }
1138
+
1139
+ // Priority 3: Single user from database
1140
+ const singleUserId = getSingleUserId();
1141
+ if (singleUserId) {
1142
+ return singleUserId;
1143
+ }
1144
+
1145
+ // Priority 4: No user found
1146
+ return null;
1147
+ }
1148
+
1149
+ /**
1150
+ * Get the default agent ID with priority:
1151
+ * 1. Coordinator agent (role = 'coordinator')
1152
+ * 2. First enabled agent
1153
+ * 3. Null (no agent found)
1154
+ */
1155
+ export function getDefaultAgentId(): string | null {
1156
+ try {
1157
+ const db = getDb();
1158
+
1159
+ // Try coordinator first
1160
+ const coordinator = db.query(
1161
+ "SELECT id FROM agents WHERE role = 'coordinator' AND enabled = 1 LIMIT 1"
1162
+ ).get() as { id: string } | undefined;
1163
+
1164
+ if (coordinator?.id) {
1165
+ return coordinator.id;
1166
+ }
1167
+
1168
+ // Fallback to first enabled agent
1169
+ const firstAgent = db.query(
1170
+ "SELECT id FROM agents WHERE enabled = 1 LIMIT 1"
1171
+ ).get() as { id: string } | undefined;
1172
+
1173
+ return firstAgent?.id || null;
1174
+ } catch (e) {
1175
+ log.warn("[getDefaultAgentId] ⚠️ Error getting default agent ID:", (e as Error).message);
1176
+ return null;
1177
+ }
1178
+ }
1179
+
1180
+ /**
1181
+ * Resolve the agent ID with priority:
1182
+ * 1. Explicit agentId parameter
1183
+ * 2. Coordinator agent from database
1184
+ * 3. First enabled agent from database
1185
+ * 4. Null (no agent found)
1186
+ */
1187
+ export function resolveAgentId(agentId?: string | null): string | null {
1188
+ // Priority 1: Explicit agentId
1189
+ if (agentId) {
1190
+ return agentId;
1191
+ }
1192
+
1193
+ // Priority 2: Default from database (coordinator or first enabled)
1194
+ return getDefaultAgentId();
1195
+ }
1196
+
1197
+ /**
1198
+ * Get user preferences (notes) for a given user ID
1199
+ */
1200
+ export function getUserPreferences(userId: string): string | null {
1201
+ try {
1202
+ const db = getDb();
1203
+ const result = db.query("SELECT notes FROM users WHERE id = ?").get(userId) as { notes: string | null } | undefined;
1204
+ return result?.notes || null;
1205
+ } catch (e) {
1206
+ log.warn("[getUserPreferences] ⚠️ Error getting user preferences:", (e as Error).message);
1207
+ return null;
1208
+ }
1209
+ }
1210
+
1211
+ /**
1212
+ * Get agent configuration by ID
1213
+ */
1214
+ export function getAgentConfig(agentId: string): {
1215
+ id: string;
1216
+ user_id: string;
1217
+ name: string;
1218
+ description: string | null;
1219
+ system_prompt: string | null;
1220
+ tone: string | null;
1221
+ provider_id: string | null;
1222
+ model_id: string | null;
1223
+ tools_json: string | null;
1224
+ skills_json: string | null;
1225
+ max_iterations: number;
1226
+ } | null {
1227
+ try {
1228
+ const db = getDb();
1229
+ const result = db.query(`
1230
+ SELECT id, user_id, name, description, system_prompt, tone,
1231
+ provider_id, model_id, tools_json, skills_json, max_iterations
1232
+ FROM agents WHERE id = ?
1233
+ `).get(agentId) as {
1234
+ id: string;
1235
+ user_id: string;
1236
+ name: string;
1237
+ description: string | null;
1238
+ system_prompt: string | null;
1239
+ tone: string | null;
1240
+ provider_id: string | null;
1241
+ model_id: string | null;
1242
+ tools_json: string | null;
1243
+ skills_json: string | null;
1244
+ max_iterations: number;
1245
+ } | undefined;
1246
+
1247
+ return result || null;
1248
+ } catch (e) {
1249
+ log.warn("[getAgentConfig] ⚠️ Error getting agent config:", (e as Error).message);
1250
+ return null;
1251
+ }
1252
+ }
1253
+
1254
+ /**
1255
+ * Idempotent startup migrations. Runs on every gateway start.
1256
+ * Each migration is guarded by the schema_migrations table — once applied, it never re-runs.
1257
+ */
1258
+ export function runStartupMigrations(): void {
1259
+ try {
1260
+ const db = getDb();
1261
+
1262
+ const applied = (v: string) =>
1263
+ !!db.query("SELECT 1 FROM schema_migrations WHERE version = ?").get(v);
1264
+ const markApplied = (v: string) =>
1265
+ db.query("INSERT OR IGNORE INTO schema_migrations(version) VALUES(?)").run(v);
1266
+
1267
+ // v0.0.29 — consolidate tools + skills: drop and recreate tables with current schema, reseed
1268
+ if (!applied("v0.0.29")) {
1269
+ const db = getDb();
1270
+ log.info("[migration v0.0.29] Dropping and recreating tools + skills tables...");
1271
+
1272
+ db.run("DROP TABLE IF EXISTS skills_fts");
1273
+ db.run("DROP TABLE IF EXISTS skills");
1274
+ db.run("DROP TABLE IF EXISTS tools_fts");
1275
+ db.run("DROP TABLE IF EXISTS tools");
1276
+
1277
+ db.run(`CREATE TABLE tools (
1278
+ id TEXT PRIMARY KEY,
1279
+ name TEXT NOT NULL UNIQUE,
1280
+ description TEXT,
1281
+ category TEXT,
1282
+ enabled INTEGER NOT NULL DEFAULT 1,
1283
+ active INTEGER NOT NULL DEFAULT 1,
1284
+ created_at INTEGER NOT NULL DEFAULT (unixepoch()),
1285
+ updated_at INTEGER NOT NULL DEFAULT (unixepoch())
1286
+ )`);
1287
+
1288
+ db.run(`CREATE VIRTUAL TABLE tools_fts USING fts5(tool_name, name, description, category)`);
1289
+
1290
+ db.run(`CREATE TABLE skills (
1291
+ id TEXT PRIMARY KEY,
1292
+ name TEXT NOT NULL,
1293
+ description TEXT,
1294
+ version TEXT DEFAULT '0.0.1',
1295
+ author TEXT DEFAULT 'Anonymous',
1296
+ icon TEXT DEFAULT '🧩',
1297
+ category TEXT NOT NULL,
1298
+ permissions TEXT,
1299
+ dependencies TEXT,
1300
+ tools TEXT NOT NULL,
1301
+ triggers TEXT NOT NULL,
1302
+ preferred_agents TEXT,
1303
+ body TEXT NOT NULL,
1304
+ version_num INTEGER DEFAULT 1,
1305
+ active INTEGER DEFAULT 1,
1306
+ created_at TEXT DEFAULT (datetime('now')),
1307
+ updated_at TEXT DEFAULT (datetime('now'))
1308
+ )`);
1309
+
1310
+ db.run(`CREATE VIRTUAL TABLE skills_fts USING fts5(id, name, description, category, tools, triggers, body)`);
1311
+
1312
+ db.run("CREATE INDEX IF NOT EXISTS idx_skills_category ON skills(category)");
1313
+ db.run("CREATE INDEX IF NOT EXISTS idx_skills_active ON skills(active)");
1314
+
1315
+ db.run(`DROP TRIGGER IF EXISTS skills_ai`);
1316
+ db.run(`DROP TRIGGER IF EXISTS skills_au`);
1317
+ db.run(`DROP TRIGGER IF EXISTS skills_ad`);
1318
+ db.run(`CREATE TRIGGER skills_ai AFTER INSERT ON skills BEGIN
1319
+ INSERT INTO skills_fts(id, name, description, category, tools, triggers, body)
1320
+ VALUES (new.id, new.name, new.description, new.category, new.tools, new.triggers, new.body);
1321
+ END`);
1322
+ db.run(`CREATE TRIGGER skills_au AFTER UPDATE ON skills BEGIN
1323
+ DELETE FROM skills_fts WHERE id = old.id;
1324
+ INSERT INTO skills_fts(id, name, description, category, tools, triggers, body)
1325
+ VALUES (new.id, new.name, new.description, new.category, new.tools, new.triggers, new.body);
1326
+ END`);
1327
+ db.run(`CREATE TRIGGER skills_ad AFTER DELETE ON skills BEGIN
1328
+ DELETE FROM skills_fts WHERE id = old.id;
1329
+ END`);
1330
+
1331
+ // Reseed tools
1332
+ const insertToolFts = db.prepare(`INSERT OR REPLACE INTO tools_fts(tool_name, name, description, category) VALUES (?, ?, ?, ?)`);
1333
+ let toolCount = 0;
1334
+ for (const tool of SEED_DATA.tools) {
1335
+ db.query(`INSERT INTO tools (id, name, description, category, enabled, active, created_at, updated_at) VALUES (?, ?, ?, ?, 1, 1, (unixepoch()), (unixepoch()))`)
1336
+ .run(tool.id, tool.name, tool.description, tool.category);
1337
+ insertToolFts.run(tool.name, tool.name, tool.description, tool.category);
1338
+ toolCount++;
1339
+ }
1340
+ log.info(`[migration v0.0.29] ✅ ${toolCount} tools re-seeded`);
1341
+
1342
+ // Reseed skills from SkillLoader
1343
+ const skillLoader = new SkillLoader({ workspacePath: process.env.HIVE_HOME || process.cwd() });
1344
+ const bundledSkills = skillLoader.loadBundledSkills();
1345
+ log.info(`[migration v0.0.29] 📚 SkillLoader loaded ${bundledSkills.length} bundled skills`);
1346
+ let skillCount = 0;
1347
+ for (const s of bundledSkills) {
1348
+ db.query(`
1349
+ INSERT OR REPLACE INTO skills (
1350
+ id, name, description, version, author, icon, category,
1351
+ permissions, dependencies, tools, triggers, preferred_agents,
1352
+ body, version_num, active, created_at, updated_at
1353
+ )
1354
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 1, (unixepoch()), (unixepoch()))
1355
+ `).run(
1356
+ s.name, s.name, s.description || "",
1357
+ typeof s.version === "string" ? s.version : String(s.version || "0.0.1"),
1358
+ s.author || "Anonymous",
1359
+ s.icon || "🧩",
1360
+ s.category || "general",
1361
+ JSON.stringify(s.permissions || []),
1362
+ JSON.stringify(s.dependencies || []),
1363
+ (s.tools || []).join(","),
1364
+ (s.triggers || []).join(","),
1365
+ JSON.stringify(s.preferred_agents || []),
1366
+ s.content || "",
1367
+ parseInt(String(s.version || "0.0.1").split(".")[0]) || 1
1368
+ );
1369
+ skillCount++;
1370
+ }
1371
+ log.info(`[migration v0.0.29] ✅ ${skillCount} skills re-seeded (FTS5 auto-synced via triggers)`);
1372
+
1373
+ markApplied("v0.0.29");
1374
+ log.info("✅ Migration v0.0.29: tools + skills consolidated, dropped and recreated");
1375
+ }
1376
+
1377
+ // v0.0.30 — add NVIDIA NIM provider + 12 free models (without dropping existing data)
1378
+ if (!applied("v0.0.30")) {
1379
+ const db = getDb();
1380
+ log.info("[migration v0.0.30] Ensuring providers table exists...");
1381
+ db.run(`CREATE TABLE IF NOT EXISTS providers (
1382
+ id TEXT PRIMARY KEY,
1383
+ name TEXT NOT NULL UNIQUE,
1384
+ api_key_encrypted TEXT,
1385
+ api_key_iv TEXT,
1386
+ headers_encrypted TEXT,
1387
+ headers_iv TEXT,
1388
+ base_url TEXT,
1389
+ category TEXT NOT NULL DEFAULT 'llm',
1390
+ num_ctx INTEGER,
1391
+ num_gpu INTEGER DEFAULT -1,
1392
+ enabled INTEGER NOT NULL DEFAULT 1,
1393
+ active INTEGER NOT NULL DEFAULT 0,
1394
+ created_at INTEGER NOT NULL DEFAULT (unixepoch())
1395
+ )`);
1396
+ log.info("[migration v0.0.30] Ensuring models table exists...");
1397
+ db.run(`CREATE TABLE IF NOT EXISTS models (
1398
+ id TEXT PRIMARY KEY,
1399
+ provider_id TEXT REFERENCES providers(id) ON DELETE CASCADE,
1400
+ name TEXT NOT NULL,
1401
+ model_type TEXT NOT NULL DEFAULT 'llm',
1402
+ context_window INTEGER NOT NULL DEFAULT 20000,
1403
+ capabilities TEXT,
1404
+ enabled INTEGER NOT NULL DEFAULT 1,
1405
+ active INTEGER NOT NULL DEFAULT 0
1406
+ )`);
1407
+ db.run("CREATE INDEX IF NOT EXISTS idx_models_provider ON models(provider_id)");
1408
+ db.run("CREATE INDEX IF NOT EXISTS idx_models_type ON models(model_type)");
1409
+ log.info("[migration v0.0.30] Adding new providers and models...");
1410
+ for (const provider of SEED_DATA.providers) {
1411
+ db.query(`
1412
+ INSERT OR IGNORE INTO providers (id, name, base_url, category, enabled, active)
1413
+ VALUES (?, ?, ?, ?, 1, 0)
1414
+ `).run(provider.id, provider.name, provider.baseUrl || null, provider.category || 'llm');
1415
+ }
1416
+ const ollamaHost = process.env.OLLAMA_HOST;
1417
+ if (ollamaHost) {
1418
+ db.query(`UPDATE providers SET base_url = ? WHERE id = 'ollama'`).run(ollamaHost);
1419
+ log.info(`[migration v0.0.30] ✅ Ollama base_url set to ${ollamaHost} (from OLLAMA_HOST env)`);
1420
+ }
1421
+ let modelCount = 0;
1422
+ for (const model of SEED_DATA.models) {
1423
+ db.query(`
1424
+ INSERT OR IGNORE INTO models (id, provider_id, name, model_type, context_window, capabilities, enabled, active)
1425
+ VALUES (?, ?, ?, ?, ?, ?, 1, 0)
1426
+ `).run(model.id, model.providerId, model.name, model.modelType, model.contextWindow || null, model.capabilities || null);
1427
+ modelCount++;
1428
+ }
1429
+ log.info(`[migration v0.0.30] ✅ Added ${SEED_DATA.providers.length} providers and ${modelCount} models`);
1430
+ markApplied("v0.0.30");
1431
+ log.info("✅ Migration v0.0.30: NVIDIA NIM provider + 12 free models added");
1432
+ }
1433
+
1434
+ // v0.0.31 — Update coordinator system_prompt to reduced version + sync bundled skills
1435
+ if (!applied("v0.0.31")) {
1436
+ const db = getDb();
1437
+ log.info("[migration v0.0.31] Updating coordinator system_prompt...");
1438
+
1439
+ // Update coordinator system_prompt with new concise version
1440
+ db.run(`UPDATE agents SET system_prompt = ? WHERE role = 'coordinator'`, [HIVE_SYSTEM_PROMPT]);
1441
+ const updated = db.query("SELECT name FROM agents WHERE role = 'coordinator' AND system_prompt = ?").get(HIVE_SYSTEM_PROMPT);
1442
+ if (updated) {
1443
+ log.info("[migration v0.0.31] ✅ Coordinator system_prompt updated");
1444
+ } else {
1445
+ log.warn("[migration v0.0.31] ⚠️ Coordinator update may have failed - checking length...");
1446
+ }
1447
+
1448
+ // Add/update skills from bundled data (busqueda_fts5, canvas_report, memory_manager minimal set)
1449
+ log.info("[migration v0.0.31] Verifying minimal skills exist...");
1450
+ const skillLoader = new SkillLoader({ workspacePath: process.env.HIVE_HOME || process.cwd() });
1451
+ const bundledSkills = skillLoader.loadBundledSkills();
1452
+
1453
+ let skillsAdded = 0;
1454
+ for (const s of bundledSkills) {
1455
+ db.query(`
1456
+ INSERT OR IGNORE INTO skills (
1457
+ id, name, description, version, author, icon, category,
1458
+ permissions, dependencies, tools, triggers, preferred_agents,
1459
+ body, version_num, active, created_at, updated_at
1460
+ )
1461
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 1, (unixepoch()), (unixepoch()))
1462
+ `).run(
1463
+ s.name, s.name, s.description || "", String(s.version || "1.0.0"),
1464
+ s.author || "Hive", s.icon || "🧩", s.category || "general",
1465
+ JSON.stringify(s.permissions || []), JSON.stringify(s.dependencies || []),
1466
+ (s.tools || []).join(","), (s.triggers || []).join(","), "[]",
1467
+ s.content || "", 100
1468
+ );
1469
+ skillsAdded++;
1470
+ }
1471
+ log.info(`[migration v0.0.31] ✅ ${skillsAdded} skills synced from bundle`);
1472
+
1473
+ // Sync skills_fts (FTS5 index)
1474
+ log.info("[migration v0.0.31] Syncing skills_fts index...");
1475
+ db.run("DELETE FROM skills_fts");
1476
+ const ftsInsert = db.prepare("INSERT INTO skills_fts(id, name, description, category, tools, triggers, body) VALUES(?, ?, ?, ?, ?, ?, ?)");
1477
+ const activeSkills = db.query("SELECT * FROM skills WHERE active = 1").all() as any[];
1478
+ for (const s of activeSkills) {
1479
+ ftsInsert.run(s.id, s.name, s.description || "", s.category || "", s.tools || "", s.triggers || "", s.body || "");
1480
+ }
1481
+ log.info(`[migration v0.0.31] ✅ ${activeSkills.length} skills indexed in FTS5`);
1482
+
1483
+ markApplied("v0.0.31");
1484
+ log.info("✅ Migration v0.0.31: Reduced system_prompt + skills sync");
1485
+ }
1486
+
1487
+ // v0.0.32 — add vision/multimodal columns to channels table
1488
+ if (!applied("v0.0.32")) {
1489
+ const db = getDb();
1490
+ log.info("[migration v0.0.32] Adding vision columns to channels table...");
1491
+
1492
+ const addCol = (col: string, def: string) => {
1493
+ try { db.run(`ALTER TABLE channels ADD COLUMN ${col} ${def}`); } catch { /* already exists */ }
1494
+ };
1495
+ addCol("vision_enabled", "INTEGER NOT NULL DEFAULT 0");
1496
+ addCol("ocr_provider", "TEXT");
1497
+ addCol("vision_provider", "TEXT");
1498
+ addCol("vision_model_id", "TEXT");
1499
+
1500
+ markApplied("v0.0.32");
1501
+ log.info("✅ Migration v0.0.32: vision columns added to channels");
1502
+ }
1503
+ } catch (e) {
1504
+ log.error("⚠️ runStartupMigrations failed:", { error: (e as Error).message });
1505
+ }
1506
+ }