cognova 0.2.13 → 0.2.14

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 (386) hide show
  1. package/.output/nitro.json +1 -1
  2. package/.output/public/_nuxt/-mGU8_Hv.js +1 -0
  3. package/.output/public/_nuxt/0GqCtQ9S.js +1 -0
  4. package/.output/public/_nuxt/{DFpmIy6J.js → 1wCoXZ14.js} +1 -1
  5. package/.output/public/_nuxt/2J1KxdHv.js +1 -0
  6. package/.output/public/_nuxt/6VDUZECX.js +1 -0
  7. package/.output/public/_nuxt/{C7m9zGMG.js → 8WMJQbWG.js} +1 -1
  8. package/.output/public/_nuxt/9Rw88G6h.js +1 -0
  9. package/.output/public/_nuxt/{BjsKx597.js → B-yW4SD3.js} +1 -1
  10. package/.output/public/_nuxt/B20jNAhm.js +1 -0
  11. package/.output/public/_nuxt/B3OpTH_e.js +1 -0
  12. package/.output/public/_nuxt/B9Y3_B5G.js +1 -0
  13. package/.output/public/_nuxt/B9_vmatf.js +1 -0
  14. package/.output/public/_nuxt/B9o6sFST.js +1 -0
  15. package/.output/public/_nuxt/{CseYuM6E.js → BAY3_Hrq.js} +1 -1
  16. package/.output/public/_nuxt/{B_9zJTqe.js → BD5rPkc2.js} +3 -3
  17. package/.output/public/_nuxt/BGYoW3kO.js +1 -0
  18. package/.output/public/_nuxt/BHUy5EAj.js +1 -0
  19. package/.output/public/_nuxt/BLdMRpJD.js +1 -0
  20. package/.output/public/_nuxt/{D6tVZcRs.js → BOCn_SGf.js} +12 -12
  21. package/.output/public/_nuxt/BQi8LIrn.js +1 -0
  22. package/.output/public/_nuxt/BS1t375R.js +1 -0
  23. package/.output/public/_nuxt/BTGeP1bA.js +1 -0
  24. package/.output/public/_nuxt/{pdYvpiud.js → BVYYP4eQ.js} +5 -5
  25. package/.output/public/_nuxt/BWQ7zE01.js +1 -0
  26. package/.output/public/_nuxt/BWqJInD3.js +1 -0
  27. package/.output/public/_nuxt/BXdQ9ASJ.js +1 -0
  28. package/.output/public/_nuxt/{DQhm-UPG.js → BXxZokD_.js} +2 -2
  29. package/.output/public/_nuxt/BZ7DAtPi.js +1 -0
  30. package/.output/public/_nuxt/BZm9w7en.js +1 -0
  31. package/.output/public/_nuxt/B_hNqC64.js +1 -0
  32. package/.output/public/_nuxt/Be47YE2L.js +1 -0
  33. package/.output/public/_nuxt/BgIS9_ti.js +39 -0
  34. package/.output/public/_nuxt/BgavRUl_.js +1 -0
  35. package/.output/public/_nuxt/Bh0yGTzr.js +1 -0
  36. package/.output/public/_nuxt/BhhMUror.js +1 -0
  37. package/.output/public/_nuxt/Bj5e7QPz.js +1 -0
  38. package/.output/public/_nuxt/{9kAKMaPC.js → Bnn59-FS.js} +1 -1
  39. package/.output/public/_nuxt/BoCU3mWu.js +1 -0
  40. package/.output/public/_nuxt/Br6epbzY.js +1 -0
  41. package/.output/public/_nuxt/Br81Sr2R.js +1 -0
  42. package/.output/public/_nuxt/BrkEOLHu.js +9 -0
  43. package/.output/public/_nuxt/BtrNCc2S.js +1 -0
  44. package/.output/public/_nuxt/BxsQlbgl.js +1 -0
  45. package/.output/public/_nuxt/BzrhNhdT.js +1 -0
  46. package/.output/public/_nuxt/{B-DMcEU9.js → C-78dDNd.js} +1 -1
  47. package/.output/public/_nuxt/C1oaoi1p.js +1 -0
  48. package/.output/public/_nuxt/C2-_hcwB.js +1 -0
  49. package/.output/public/_nuxt/{TxMdabnL.js → C2Gh3qqr.js} +1 -1
  50. package/.output/public/_nuxt/C2OHaW6l.js +1 -0
  51. package/.output/public/_nuxt/C3szZmvA.js +1 -0
  52. package/.output/public/_nuxt/C3xzleKP.js +1 -0
  53. package/.output/public/_nuxt/C4sG6rdW.js +1 -0
  54. package/.output/public/_nuxt/C5Cu9Fx6.js +1 -0
  55. package/.output/public/_nuxt/{LRO7YHoH.js → C5gfF7J1.js} +1 -1
  56. package/.output/public/_nuxt/C6Eoiclo.js +1 -0
  57. package/.output/public/_nuxt/C7hFztZL.js +1 -0
  58. package/.output/public/_nuxt/CAVUAxNU.js +2 -0
  59. package/.output/public/_nuxt/{CiNxIhaq.js → CCeM5lW2.js} +1 -1
  60. package/.output/public/_nuxt/CDcQ31Eh.js +1 -0
  61. package/.output/public/_nuxt/CHbHVtCy.js +1 -0
  62. package/.output/public/_nuxt/CHnVFnBW.js +1 -0
  63. package/.output/public/_nuxt/CLNcmNQS.js +1 -0
  64. package/.output/public/_nuxt/{D7N3EZ-I.js → CPwCTHun.js} +1 -1
  65. package/.output/public/_nuxt/{CFmvNggn.js → CS8SdmH2.js} +1 -1
  66. package/.output/public/_nuxt/CTGm_mc8.js +1 -0
  67. package/.output/public/_nuxt/{DNcOC5zj.js → CTQFGHjS.js} +1 -1
  68. package/.output/public/_nuxt/{B0nzD8Sk.js → CVVtVzXC.js} +1 -1
  69. package/.output/public/_nuxt/CZNOaqeX.js +1 -0
  70. package/.output/public/_nuxt/C_A_NkeC.js +2 -0
  71. package/.output/public/_nuxt/{CGplHfmR.js → C_doutX-.js} +1 -1
  72. package/.output/public/_nuxt/{BrX-PnSK.js → CbDLhrNA.js} +2 -2
  73. package/.output/public/_nuxt/CePKCqSb.js +1 -0
  74. package/.output/public/_nuxt/Cet4T_yO.js +1 -0
  75. package/.output/public/_nuxt/{C6OSRpRd.js → CjJPkhbc.js} +1 -1
  76. package/.output/public/_nuxt/CkZT4LGq.js +1 -0
  77. package/.output/public/_nuxt/CkrW8sGL.js +1 -0
  78. package/.output/public/_nuxt/Co0UxVsx.js +1 -0
  79. package/.output/public/_nuxt/CqS0zXYQ.js +1 -0
  80. package/.output/public/_nuxt/CskGv_Km.js +1 -0
  81. package/.output/public/_nuxt/{DuzpliIL.js → CuvkTsqs.js} +1 -1
  82. package/.output/public/_nuxt/{B2wI_pYg.js → CxMuZEwX.js} +1 -1
  83. package/.output/public/_nuxt/{9O1MXkck.js → CxSijT71.js} +8 -8
  84. package/.output/public/_nuxt/Cywo6tZI.js +1 -0
  85. package/.output/public/_nuxt/D1reIfpX.js +1 -0
  86. package/.output/public/_nuxt/D1uV2uir.js +1 -0
  87. package/.output/public/_nuxt/{BWuL2CzO.js → D2edadpd.js} +1 -1
  88. package/.output/public/_nuxt/D3cEeQh7.js +1 -0
  89. package/.output/public/_nuxt/D41A2mE2.js +1 -0
  90. package/.output/public/_nuxt/D49P2RhG.js +1 -0
  91. package/.output/public/_nuxt/D867g6Ds.js +1 -0
  92. package/.output/public/_nuxt/DEFWIjWl.js +1 -0
  93. package/.output/public/_nuxt/DFTEBTzZ.js +1 -0
  94. package/.output/public/_nuxt/{-HePz7lp.js → DHRexj9X.js} +2 -2
  95. package/.output/public/_nuxt/DL4EpgqQ.js +1 -0
  96. package/.output/public/_nuxt/DLHnP6tw.js +1 -0
  97. package/.output/public/_nuxt/DM20WaLq.js +1 -0
  98. package/.output/public/_nuxt/{B8DFEjxA.js → DNAMjHbb.js} +1 -1
  99. package/.output/public/_nuxt/{CLkkdThv.js → DP8t9VWs.js} +24 -24
  100. package/.output/public/_nuxt/DTR31rjp.js +1 -0
  101. package/.output/public/_nuxt/{Bc8bTnkd.js → DTlSLSo1.js} +3 -3
  102. package/.output/public/_nuxt/{DowkFZ2V.js → DVdnhfXT.js} +1 -1
  103. package/.output/public/_nuxt/{DvHS7_h2.js → DZikIgHK.js} +1 -1
  104. package/.output/public/_nuxt/D_YGqvw_.js +1 -0
  105. package/.output/public/_nuxt/D_k1YwXm.js +1 -0
  106. package/.output/public/_nuxt/Daf2MbWG.js +7 -0
  107. package/.output/public/_nuxt/DcJ0GstJ.js +1 -0
  108. package/.output/public/_nuxt/DcYKh6QA.js +1 -0
  109. package/.output/public/_nuxt/DhN3_DYH.js +1 -0
  110. package/.output/public/_nuxt/DhSvBSt3.js +1 -0
  111. package/.output/public/_nuxt/DhlIWT8K.js +1 -0
  112. package/.output/public/_nuxt/DjsqyRqt.js +1 -0
  113. package/.output/public/_nuxt/DpSM97eH.js +1 -0
  114. package/.output/public/_nuxt/DqR9SdeU.js +1 -0
  115. package/.output/public/_nuxt/DqmQtg6Y.js +1 -0
  116. package/.output/public/_nuxt/Dsuag_iW.js +1 -0
  117. package/.output/public/_nuxt/Dtr_0IbE.js +1 -0
  118. package/.output/public/_nuxt/DwrmFEZN.js +1 -0
  119. package/.output/public/_nuxt/DxE8r3r4.js +1 -0
  120. package/.output/public/_nuxt/G_CsVlOR.js +1 -0
  121. package/.output/public/_nuxt/Gyw_2f6x.js +1 -0
  122. package/.output/public/_nuxt/HStC1ZyE.js +1 -0
  123. package/.output/public/_nuxt/Hh9mv0Ek.js +1 -0
  124. package/.output/public/_nuxt/LR0kCjbe.js +1 -0
  125. package/.output/public/_nuxt/MYeLvJGV.js +1 -0
  126. package/.output/public/_nuxt/NKs0EGrh.js +1 -0
  127. package/.output/public/_nuxt/PY5EGujn.js +1 -0
  128. package/.output/public/_nuxt/PamJNol9.js +1 -0
  129. package/.output/public/_nuxt/RlvwEbHv.js +1 -0
  130. package/.output/public/_nuxt/{BghuwIGa.js → TNpdJOlc.js} +1 -1
  131. package/.output/public/_nuxt/TSYrPbLR.js +1 -0
  132. package/.output/public/_nuxt/U-eBrbR4.js +1 -0
  133. package/.output/public/_nuxt/UuqXScSw.js +1 -0
  134. package/.output/public/_nuxt/V04-MrLN.js +1 -0
  135. package/.output/public/_nuxt/X0o5GcBb.js +1 -0
  136. package/.output/public/_nuxt/XQNzmQy9.js +1 -0
  137. package/.output/public/_nuxt/Y59XKprr.js +1 -0
  138. package/.output/public/_nuxt/YZQjZgsH.js +1 -0
  139. package/.output/public/_nuxt/_-TGPiLQ.js +1 -0
  140. package/.output/public/_nuxt/builds/latest.json +1 -1
  141. package/.output/public/_nuxt/builds/meta/d7188f50-b42c-4d2c-afab-066d318f0af8.json +1 -0
  142. package/.output/public/_nuxt/dashboard.ByJQ-Wzh.css +1 -0
  143. package/.output/public/_nuxt/entry.ZJxWCrU6.css +1 -0
  144. package/.output/public/_nuxt/{D12qPplu.js → hCeWb_38.js} +1 -1
  145. package/.output/public/_nuxt/{sBzyvWMJ.js → hrPTRWjM.js} +1 -1
  146. package/.output/public/_nuxt/jC4pIK1p.js +1 -0
  147. package/.output/public/_nuxt/jTT1R-Vz.js +1 -0
  148. package/.output/public/_nuxt/{CRRw0Thu.js → kkAMoB43.js} +1 -1
  149. package/.output/public/_nuxt/{h_bXa-f2.js → mzM4BGtv.js} +1 -1
  150. package/.output/public/_nuxt/o-s8JBm2.js +1 -0
  151. package/.output/public/_nuxt/pwJTkIQ4.js +1 -0
  152. package/.output/public/_nuxt/{BL1mkqgd.js → rIgg2Arf.js} +3 -3
  153. package/.output/public/_nuxt/subdxgSQ.js +1 -0
  154. package/.output/public/_nuxt/t8B72leH.js +1 -0
  155. package/.output/public/_nuxt/vCFAHwdt.js +1 -0
  156. package/.output/public/_nuxt/z-MP0bB7.js +1 -0
  157. package/.output/server/chunks/build/CodeIcon-CWD5HcV7.mjs +1 -1
  158. package/.output/server/chunks/build/DropdownMenu-BBrV9nXz.mjs +1 -1
  159. package/.output/server/chunks/build/{EditorToolbar-DIfb5arC.mjs → EditorToolbar-B9OwSI5e.mjs} +3 -3
  160. package/.output/server/chunks/build/{EditorToolbar-DIfb5arC.mjs.map → EditorToolbar-B9OwSI5e.mjs.map} +1 -1
  161. package/.output/server/chunks/build/Img-CWLmvN1t.mjs +1 -1
  162. package/.output/server/chunks/build/MDC-Dx0YPDhe.mjs +1 -1
  163. package/.output/server/chunks/build/Select-BB1oLrCD.mjs +1 -1
  164. package/.output/server/chunks/build/SelectMenu-DPssg6zD.mjs +1 -1
  165. package/.output/server/chunks/build/Table-DCwTlhCj.mjs +1 -1
  166. package/.output/server/chunks/build/Tooltip-TRyl6dje.mjs +1 -1
  167. package/.output/server/chunks/build/Tree-DUhXKd8y.mjs +1 -1
  168. package/.output/server/chunks/build/{_id_-DN00UDdO.mjs → _id_-CwBeklIM.mjs} +296 -430
  169. package/.output/server/chunks/build/_id_-CwBeklIM.mjs.map +1 -0
  170. package/.output/server/chunks/build/{_name_-BnS_KEfX.mjs → _name_-D7MtW4Vu.mjs} +2 -2
  171. package/.output/server/chunks/build/{_name_-BnS_KEfX.mjs.map → _name_-D7MtW4Vu.mjs.map} +1 -1
  172. package/.output/server/chunks/build/{_uuid_-DfJaumTE.mjs → _uuid_-lvG92ein.mjs} +4 -4
  173. package/.output/server/chunks/build/{_uuid_-DfJaumTE.mjs.map → _uuid_-lvG92ein.mjs.map} +1 -1
  174. package/.output/server/chunks/build/account-LDZ4TL6x.mjs +513 -0
  175. package/.output/server/chunks/build/account-LDZ4TL6x.mjs.map +1 -0
  176. package/.output/server/chunks/build/app-CGhRZPNT.mjs +252 -0
  177. package/.output/server/chunks/build/app-CGhRZPNT.mjs.map +1 -0
  178. package/.output/server/chunks/build/{chat-m4-n9vC6.mjs → chat-BphuYhvA.mjs} +18 -27
  179. package/.output/server/chunks/build/chat-BphuYhvA.mjs.map +1 -0
  180. package/.output/server/chunks/build/client.precomputed.mjs +1 -1
  181. package/.output/server/chunks/build/cookie-C_iulBi6.mjs +1 -1
  182. package/.output/server/chunks/build/{dashboard-CiVTAZuF.mjs → dashboard-nDujDyOg.mjs} +55 -16
  183. package/.output/server/chunks/build/{dashboard-CiVTAZuF.mjs.map → dashboard-nDujDyOg.mjs.map} +1 -1
  184. package/.output/server/chunks/build/{docs-ChGwOPg5.mjs → docs-Bwucwp0r.mjs} +664 -592
  185. package/.output/server/chunks/build/docs-Bwucwp0r.mjs.map +1 -0
  186. package/.output/server/chunks/build/fetch-BB7Qzkwe.mjs +1 -1
  187. package/.output/server/chunks/build/{hooks-D328DcO6.mjs → hooks-D6PmTth8.mjs} +19 -29
  188. package/.output/server/chunks/build/hooks-D6PmTth8.mjs.map +1 -0
  189. package/.output/server/chunks/build/{index-CAnGTRlu.mjs → index-CJkn2jiM.mjs} +2 -2
  190. package/.output/server/chunks/build/{index-CAnGTRlu.mjs.map → index-CJkn2jiM.mjs.map} +1 -1
  191. package/.output/server/chunks/build/index-CxDxc9fm.mjs +1 -1
  192. package/.output/server/chunks/build/index-Cz9Y6NwN.mjs +723 -0
  193. package/.output/server/chunks/build/index-Cz9Y6NwN.mjs.map +1 -0
  194. package/.output/server/chunks/build/index-hwhuKhuZ.mjs +76 -0
  195. package/.output/server/chunks/build/index-hwhuKhuZ.mjs.map +1 -0
  196. package/.output/server/chunks/build/integrations-D5JWURiJ.mjs +1499 -0
  197. package/.output/server/chunks/build/integrations-D5JWURiJ.mjs.map +1 -0
  198. package/.output/server/chunks/build/{library-Aeg7_Lsb.mjs → library-DxRdgP6X.mjs} +2 -2
  199. package/.output/server/chunks/build/{library-Aeg7_Lsb.mjs.map → library-DxRdgP6X.mjs.map} +1 -1
  200. package/.output/server/chunks/build/{login-DnnElTl2.mjs → login-BmER_VoU.mjs} +2 -2
  201. package/.output/server/chunks/build/{login-DnnElTl2.mjs.map → login-BmER_VoU.mjs.map} +1 -1
  202. package/.output/server/chunks/build/manage-secrets-BWzqc_-f.mjs +669 -0
  203. package/.output/server/chunks/build/manage-secrets-BWzqc_-f.mjs.map +1 -0
  204. package/.output/server/chunks/build/server.mjs +65 -34
  205. package/.output/server/chunks/build/server.mjs.map +1 -1
  206. package/.output/server/chunks/build/settings-neokAVE5.mjs +154 -0
  207. package/.output/server/chunks/build/settings-neokAVE5.mjs.map +1 -0
  208. package/.output/server/chunks/build/styles.mjs +2 -2
  209. package/.output/server/chunks/build/{tasks-DnAFqbtt.mjs → tasks-CnpIQNpS.mjs} +27 -37
  210. package/.output/server/chunks/build/tasks-CnpIQNpS.mjs.map +1 -0
  211. package/.output/server/chunks/build/{useAgents-DHEXiFSc.mjs → useAgents-nmbkB9-_.mjs} +5 -26
  212. package/.output/server/chunks/build/useAgents-nmbkB9-_.mjs.map +1 -0
  213. package/.output/server/chunks/build/{view-n2sYa4Zh.mjs → view-mb0ISqfM.mjs} +3 -3
  214. package/.output/server/chunks/build/{view-n2sYa4Zh.mjs.map → view-mb0ISqfM.mjs.map} +1 -1
  215. package/.output/server/chunks/nitro/nitro.mjs +1000 -858
  216. package/.output/server/chunks/nitro/nitro.mjs.map +1 -1
  217. package/.output/server/chunks/routes/api/index.get.mjs +17 -2
  218. package/.output/server/chunks/routes/api/index.get.mjs.map +1 -1
  219. package/.output/server/chunks/routes/api/index.get3.mjs +21 -3
  220. package/.output/server/chunks/routes/api/index.get3.mjs.map +1 -1
  221. package/.output/server/chunks/routes/api/index.get4.mjs +10 -9
  222. package/.output/server/chunks/routes/api/index.get4.mjs.map +1 -1
  223. package/.output/server/chunks/routes/api/index.get9.mjs +10 -8
  224. package/.output/server/chunks/routes/api/index.get9.mjs.map +1 -1
  225. package/.output/server/chunks/routes/api/memory/search.get.mjs +10 -5
  226. package/.output/server/chunks/routes/api/memory/search.get.mjs.map +1 -1
  227. package/.output/server/chunks/routes/renderer.mjs +1 -1
  228. package/.output/server/index.mjs +1 -1
  229. package/.output/server/package.json +1 -1
  230. package/app/components/AssistantPanel.client.vue +16 -314
  231. package/app/components/agents/AgentCard.vue +111 -0
  232. package/app/components/agents/AgentInfoCard.vue +54 -0
  233. package/app/components/agents/AgentRunHistory.vue +103 -0
  234. package/app/components/agents/AgentRunModal.vue +1 -24
  235. package/app/components/agents/AgentStatsCards.vue +1 -26
  236. package/app/components/assistant/AssistantChat.vue +156 -0
  237. package/app/components/assistant/AssistantTerminal.client.vue +178 -0
  238. package/app/components/chat/ConversationList.vue +2 -12
  239. package/app/components/files/FileTree.vue +23 -202
  240. package/app/components/files/FileTreeModals.vue +226 -0
  241. package/app/components/hooks/HookStatsCards.vue +1 -6
  242. package/app/components/hooks/ToolBreakdownTable.vue +1 -6
  243. package/app/components/search/DashboardSearch.vue +38 -1
  244. package/app/components/tasks/TaskCard.vue +2 -7
  245. package/app/components/tasks/TaskDetail.vue +4 -9
  246. package/app/composables/useSearch.ts +21 -11
  247. package/app/layouts/dashboard.vue +1 -1
  248. package/app/pages/agents/[id].vue +6 -197
  249. package/app/pages/agents/index.vue +9 -142
  250. package/app/pages/settings/account.vue +243 -0
  251. package/app/pages/settings/app.vue +230 -0
  252. package/app/pages/settings/index.vue +12 -0
  253. package/app/pages/settings/integrations.vue +794 -0
  254. package/app/pages/settings/manage-secrets.vue +295 -0
  255. package/app/pages/settings.vue +20 -1581
  256. package/dist/cli/index.js +26 -2
  257. package/package.json +1 -1
  258. package/server/api/agents/index.get.ts +20 -1
  259. package/server/api/conversations/index.get.ts +23 -5
  260. package/server/api/documents/index.get.ts +11 -9
  261. package/server/api/memory/search.get.ts +11 -6
  262. package/server/api/tasks/index.get.ts +11 -9
  263. package/server/drizzle/migrations/0016_full_text_search.sql +127 -0
  264. package/server/drizzle/migrations/meta/_journal.json +7 -0
  265. package/shared/types/index.ts +7 -1
  266. package/shared/utils/formatting.ts +105 -0
  267. package/.output/public/_nuxt/4ALIM-zZ.js +0 -1
  268. package/.output/public/_nuxt/5sUbkh_6.js +0 -16
  269. package/.output/public/_nuxt/6bB8Ev7a.js +0 -1
  270. package/.output/public/_nuxt/7rT1DCe2.js +0 -1
  271. package/.output/public/_nuxt/B2PqR2Vu.js +0 -1
  272. package/.output/public/_nuxt/B5FuOh7E.js +0 -1
  273. package/.output/public/_nuxt/B6om4MW2.js +0 -1
  274. package/.output/public/_nuxt/B7ikW4eF.js +0 -1
  275. package/.output/public/_nuxt/B9kWNcU7.js +0 -1
  276. package/.output/public/_nuxt/BAZ8sewA.js +0 -1
  277. package/.output/public/_nuxt/BCPwL4ma.js +0 -1
  278. package/.output/public/_nuxt/BCrlmHh_.js +0 -1
  279. package/.output/public/_nuxt/BD-AFJWW.js +0 -1
  280. package/.output/public/_nuxt/BGcQMReV.js +0 -1
  281. package/.output/public/_nuxt/BNJJSRKh.js +0 -1
  282. package/.output/public/_nuxt/BNeeERBt.js +0 -1
  283. package/.output/public/_nuxt/BSJb5amZ.js +0 -1
  284. package/.output/public/_nuxt/BSsaE9Db.js +0 -1
  285. package/.output/public/_nuxt/BVO3XpHT.js +0 -1
  286. package/.output/public/_nuxt/B_Lr1vlV.js +0 -1
  287. package/.output/public/_nuxt/Bl0qBhCG.js +0 -1
  288. package/.output/public/_nuxt/Bl43dkDq.js +0 -1
  289. package/.output/public/_nuxt/BnMTFF5R.js +0 -1
  290. package/.output/public/_nuxt/BtV7oNn3.js +0 -1
  291. package/.output/public/_nuxt/BvFYnRMR.js +0 -1
  292. package/.output/public/_nuxt/BvTUBUNN.js +0 -1
  293. package/.output/public/_nuxt/ByLsRRoQ.js +0 -1
  294. package/.output/public/_nuxt/C1LcEMwB.js +0 -1
  295. package/.output/public/_nuxt/C2IiXp9N.js +0 -2
  296. package/.output/public/_nuxt/C796kFT9.js +0 -1
  297. package/.output/public/_nuxt/C8AtdrMH.js +0 -1
  298. package/.output/public/_nuxt/CAWbHTgy.js +0 -1
  299. package/.output/public/_nuxt/CJPrV25_.js +0 -1
  300. package/.output/public/_nuxt/CKKEWapF.js +0 -1
  301. package/.output/public/_nuxt/CNjv28J2.js +0 -1
  302. package/.output/public/_nuxt/CT8s4rqa.js +0 -1
  303. package/.output/public/_nuxt/CZSOrxUy.js +0 -1
  304. package/.output/public/_nuxt/CaNEL9JC.js +0 -39
  305. package/.output/public/_nuxt/CbTLg9oX.js +0 -1
  306. package/.output/public/_nuxt/CfCXpVn5.js +0 -1
  307. package/.output/public/_nuxt/ChmNlvWR.js +0 -1
  308. package/.output/public/_nuxt/Ck0QYdxe.js +0 -1
  309. package/.output/public/_nuxt/Ckb0pu4-.js +0 -1
  310. package/.output/public/_nuxt/CkwPRs1D.js +0 -1
  311. package/.output/public/_nuxt/CmEJg8C6.js +0 -2
  312. package/.output/public/_nuxt/CmL_vMJD.js +0 -1
  313. package/.output/public/_nuxt/Cq8zPxkT.js +0 -1
  314. package/.output/public/_nuxt/CxRnB4NC.js +0 -1
  315. package/.output/public/_nuxt/D0zMyG8n.js +0 -1
  316. package/.output/public/_nuxt/D1XYB283.js +0 -1
  317. package/.output/public/_nuxt/D2NxqyzW.js +0 -1
  318. package/.output/public/_nuxt/D5xyrvFu.js +0 -1
  319. package/.output/public/_nuxt/D8iBB0Py.js +0 -1
  320. package/.output/public/_nuxt/D8oIH8m1.js +0 -1
  321. package/.output/public/_nuxt/DB2zZev7.js +0 -1
  322. package/.output/public/_nuxt/DBrOAqkm.js +0 -1
  323. package/.output/public/_nuxt/DDXDFweK.js +0 -1
  324. package/.output/public/_nuxt/DFZkCmLQ.js +0 -1
  325. package/.output/public/_nuxt/DKZmgHNU.js +0 -1
  326. package/.output/public/_nuxt/DR8tGJhL.js +0 -1
  327. package/.output/public/_nuxt/DVAEVTjy.js +0 -1
  328. package/.output/public/_nuxt/DVqrPkCJ.js +0 -1
  329. package/.output/public/_nuxt/DWZ9ieYa.js +0 -1
  330. package/.output/public/_nuxt/DWj6VsZv.js +0 -1
  331. package/.output/public/_nuxt/DXJ9PxCv.js +0 -1
  332. package/.output/public/_nuxt/D_ziPROx.js +0 -1
  333. package/.output/public/_nuxt/Da2vwoYG.js +0 -1
  334. package/.output/public/_nuxt/Ddz3HcBB.js +0 -1
  335. package/.output/public/_nuxt/DgYei0bK.js +0 -1
  336. package/.output/public/_nuxt/Di_3GV_R.js +0 -1
  337. package/.output/public/_nuxt/Djog1f_e.js +0 -1
  338. package/.output/public/_nuxt/Dkap2-Pj.js +0 -7
  339. package/.output/public/_nuxt/DlJe_sHk.js +0 -1
  340. package/.output/public/_nuxt/DlPOQpH_.js +0 -1
  341. package/.output/public/_nuxt/DmYWMtVA.js +0 -1
  342. package/.output/public/_nuxt/DmxKU7sH.js +0 -1
  343. package/.output/public/_nuxt/DsodHRrQ.js +0 -1
  344. package/.output/public/_nuxt/DwSY6_2U.js +0 -1
  345. package/.output/public/_nuxt/DypJaSm-.js +0 -1
  346. package/.output/public/_nuxt/DzKaXH6P.js +0 -1
  347. package/.output/public/_nuxt/FK-jSuOT.js +0 -1
  348. package/.output/public/_nuxt/Fc2JsQt4.js +0 -1
  349. package/.output/public/_nuxt/IYCBGuRS.js +0 -1
  350. package/.output/public/_nuxt/NrRzUJNY.js +0 -1
  351. package/.output/public/_nuxt/OeVS0Rsb.js +0 -1
  352. package/.output/public/_nuxt/OlF0QnKF.js +0 -1
  353. package/.output/public/_nuxt/QuAoqY7t.js +0 -1
  354. package/.output/public/_nuxt/RlXHkmOd.js +0 -9
  355. package/.output/public/_nuxt/WZnvL9Dh.js +0 -1
  356. package/.output/public/_nuxt/ZvG7a1W3.js +0 -1
  357. package/.output/public/_nuxt/aPNZBVrG.js +0 -1
  358. package/.output/public/_nuxt/builds/meta/495aca73-bfa5-456e-b96a-f02e009c72d3.json +0 -1
  359. package/.output/public/_nuxt/dashboard.BxCOkJwt.css +0 -1
  360. package/.output/public/_nuxt/entry.C_udkZt9.css +0 -1
  361. package/.output/public/_nuxt/evY81hM3.js +0 -1
  362. package/.output/public/_nuxt/i6QBzaEi.js +0 -1
  363. package/.output/public/_nuxt/iTVKJ1kw.js +0 -1
  364. package/.output/public/_nuxt/j92uR3uR.js +0 -1
  365. package/.output/public/_nuxt/jdUkeAj_.js +0 -1
  366. package/.output/public/_nuxt/jeRvcMHU.js +0 -1
  367. package/.output/public/_nuxt/kuv0zpKq.js +0 -1
  368. package/.output/public/_nuxt/l3lKQs7b.js +0 -1
  369. package/.output/public/_nuxt/qIgZ7OXa.js +0 -1
  370. package/.output/public/_nuxt/qcVwZv8e.js +0 -1
  371. package/.output/public/_nuxt/ru8fqqWs.js +0 -1
  372. package/.output/public/_nuxt/sgmhgpCS.js +0 -1
  373. package/.output/public/_nuxt/y2jv0da-.js +0 -1
  374. package/.output/public/_nuxt/yyS4-kAX.js +0 -1
  375. package/.output/public/_nuxt/zIoBLBHF.js +0 -1
  376. package/.output/public/_nuxt/zpazwPgx.js +0 -1
  377. package/.output/server/chunks/build/_id_-DN00UDdO.mjs.map +0 -1
  378. package/.output/server/chunks/build/chat-m4-n9vC6.mjs.map +0 -1
  379. package/.output/server/chunks/build/docs-ChGwOPg5.mjs.map +0 -1
  380. package/.output/server/chunks/build/hooks-D328DcO6.mjs.map +0 -1
  381. package/.output/server/chunks/build/index-C9PuieXh.mjs +0 -820
  382. package/.output/server/chunks/build/index-C9PuieXh.mjs.map +0 -1
  383. package/.output/server/chunks/build/settings-B2KXoGcz.mjs +0 -3232
  384. package/.output/server/chunks/build/settings-B2KXoGcz.mjs.map +0 -1
  385. package/.output/server/chunks/build/tasks-DnAFqbtt.mjs.map +0 -1
  386. package/.output/server/chunks/build/useAgents-DHEXiFSc.mjs.map +0 -1
@@ -0,0 +1,794 @@
1
+ <script setup lang="ts">
2
+ import type { Bridge, BridgePlatform } from '~~/shared/types'
3
+
4
+ const toast = useToast()
5
+
6
+ // Bridges state
7
+ const bridgesData = ref<Bridge[]>([])
8
+ const bridgesLoading = ref(false)
9
+ const bridgeModal = ref(false)
10
+ const bridgeSaving = ref(false)
11
+ const bridgeDeleteConfirm = ref(false)
12
+ const bridgeToDelete = ref<Bridge | null>(null)
13
+
14
+ const bridgeForm = reactive({
15
+ platform: 'telegram' as BridgePlatform,
16
+ name: ''
17
+ })
18
+
19
+ // Bridge config modal state
20
+ const bridgeConfigModal = ref(false)
21
+ const editingBridge = ref<Bridge | null>(null)
22
+ const bridgeConfigSaving = ref(false)
23
+
24
+ const bridgeConfigForm = reactive({
25
+ name: '',
26
+ // Telegram
27
+ botUsername: '',
28
+ allowedChatIds: '',
29
+ // Discord
30
+ listenMode: 'mentions' as 'mentions' | 'dm' | 'all',
31
+ guildId: '',
32
+ channelId: '',
33
+ // iMessage
34
+ strategy: 'imsg' as 'imsg' | 'bluebubbles',
35
+ allowedNumbers: '',
36
+ blueBubblesUrl: '',
37
+ // Google
38
+ enabledServices: [] as string[],
39
+ account: '',
40
+ // Email
41
+ imapHost: '',
42
+ imapPort: '',
43
+ smtpHost: '',
44
+ smtpPort: '',
45
+ emailAddress: ''
46
+ })
47
+
48
+ // Secrets for validation
49
+ const secretKeys = ref<string[]>([])
50
+
51
+ async function fetchSecretKeys() {
52
+ try {
53
+ const { data } = await $fetch<{ data: { key: string }[] }>('/api/secrets')
54
+ secretKeys.value = data.map(s => s.key)
55
+ } catch {
56
+ // Silently fail
57
+ }
58
+ }
59
+
60
+ const discordListenModeOptions = [
61
+ { value: 'mentions', label: 'Mentions & DMs' },
62
+ { value: 'dm', label: 'DMs only' },
63
+ { value: 'all', label: 'All messages' }
64
+ ]
65
+
66
+ const imessageStrategyOptions = [
67
+ { value: 'imsg', label: 'Local (imsg CLI)' },
68
+ { value: 'bluebubbles', label: 'BlueBubbles' }
69
+ ]
70
+
71
+ const googleServiceOptions = [
72
+ { value: 'gmail', label: 'Gmail' },
73
+ { value: 'calendar', label: 'Calendar' },
74
+ { value: 'drive', label: 'Drive' },
75
+ { value: 'contacts', label: 'Contacts' },
76
+ { value: 'tasks', label: 'Tasks' }
77
+ ]
78
+
79
+ const platformNamePlaceholders: Record<BridgePlatform, string> = {
80
+ telegram: 'My Telegram Bot',
81
+ discord: 'My Discord Bot',
82
+ imessage: 'iMessage Bridge',
83
+ google: 'Google Suite',
84
+ email: 'Work Email'
85
+ }
86
+
87
+ const platformRequiredSecrets: Record<BridgePlatform, string[]> = {
88
+ telegram: ['TELEGRAM_BOT_TOKEN'],
89
+ discord: ['DISCORD_BOT_TOKEN'],
90
+ imessage: [],
91
+ google: [],
92
+ email: []
93
+ }
94
+
95
+ const platformOptions: { value: BridgePlatform, label: string, icon: string }[] = [
96
+ { value: 'telegram', label: 'Telegram', icon: 'i-lucide-send' },
97
+ { value: 'discord', label: 'Discord', icon: 'i-lucide-message-circle' },
98
+ { value: 'imessage', label: 'iMessage', icon: 'i-lucide-smartphone' },
99
+ { value: 'google', label: 'Google Suite', icon: 'i-lucide-mail' },
100
+ { value: 'email', label: 'Email (IMAP)', icon: 'i-lucide-at-sign' }
101
+ ]
102
+
103
+ function getMissingSecrets(platform: BridgePlatform): string[] {
104
+ const required = platformRequiredSecrets[platform]
105
+ if (!required.length) return []
106
+ const existing = new Set(secretKeys.value)
107
+ return required.filter(k => !existing.has(k))
108
+ }
109
+
110
+ const healthColors: Record<string, string> = {
111
+ connected: 'text-success',
112
+ disconnected: 'text-dimmed',
113
+ error: 'text-error',
114
+ unconfigured: 'text-dimmed'
115
+ }
116
+
117
+ async function fetchBridges() {
118
+ bridgesLoading.value = true
119
+ try {
120
+ const { data } = await $fetch<{ data: Bridge[] }>('/api/bridges')
121
+ bridgesData.value = data
122
+ } catch {
123
+ toast.add({ title: 'Failed to load integrations', color: 'error' })
124
+ }
125
+ bridgesLoading.value = false
126
+ }
127
+
128
+ function openBridgeConfig(bridge: Bridge) {
129
+ editingBridge.value = bridge
130
+ bridgeConfigForm.name = bridge.name
131
+
132
+ const config = bridge.config ? JSON.parse(bridge.config) : {}
133
+
134
+ // Reset all fields
135
+ bridgeConfigForm.botUsername = ''
136
+ bridgeConfigForm.allowedChatIds = ''
137
+ bridgeConfigForm.listenMode = 'mentions'
138
+ bridgeConfigForm.guildId = ''
139
+ bridgeConfigForm.channelId = ''
140
+ bridgeConfigForm.strategy = 'imsg'
141
+ bridgeConfigForm.allowedNumbers = ''
142
+ bridgeConfigForm.blueBubblesUrl = ''
143
+ bridgeConfigForm.enabledServices = []
144
+ bridgeConfigForm.account = ''
145
+ bridgeConfigForm.imapHost = ''
146
+ bridgeConfigForm.imapPort = ''
147
+ bridgeConfigForm.smtpHost = ''
148
+ bridgeConfigForm.smtpPort = ''
149
+ bridgeConfigForm.emailAddress = ''
150
+
151
+ // Populate platform-specific fields from config
152
+ switch (bridge.platform) {
153
+ case 'telegram':
154
+ bridgeConfigForm.botUsername = config.botUsername || ''
155
+ bridgeConfigForm.allowedChatIds = (config.allowedChatIds || []).join(', ')
156
+ break
157
+ case 'discord':
158
+ bridgeConfigForm.listenMode = config.listenMode || 'mentions'
159
+ bridgeConfigForm.guildId = config.guildId || ''
160
+ bridgeConfigForm.channelId = config.channelId || ''
161
+ break
162
+ case 'imessage':
163
+ bridgeConfigForm.strategy = config.strategy || 'imsg'
164
+ bridgeConfigForm.allowedNumbers = (config.allowedNumbers || []).join(', ')
165
+ bridgeConfigForm.blueBubblesUrl = config.blueBubblesUrl || ''
166
+ break
167
+ case 'google':
168
+ bridgeConfigForm.enabledServices = config.enabledServices || []
169
+ bridgeConfigForm.account = config.account || ''
170
+ break
171
+ case 'email':
172
+ bridgeConfigForm.imapHost = config.imapHost || ''
173
+ bridgeConfigForm.imapPort = config.imapPort?.toString() || ''
174
+ bridgeConfigForm.smtpHost = config.smtpHost || ''
175
+ bridgeConfigForm.smtpPort = config.smtpPort?.toString() || ''
176
+ bridgeConfigForm.emailAddress = config.emailAddress || ''
177
+ break
178
+ }
179
+
180
+ bridgeConfigModal.value = true
181
+ }
182
+
183
+ async function handleBridgeConfigSave() {
184
+ if (!editingBridge.value) return
185
+
186
+ const platform = editingBridge.value.platform
187
+ let config: Record<string, unknown> = {}
188
+
189
+ // Preserve existing config (like webhookSecret) and merge new fields
190
+ if (editingBridge.value.config)
191
+ config = JSON.parse(editingBridge.value.config)
192
+
193
+ switch (platform) {
194
+ case 'telegram':
195
+ config.botUsername = bridgeConfigForm.botUsername || undefined
196
+ config.allowedChatIds = bridgeConfigForm.allowedChatIds
197
+ ? bridgeConfigForm.allowedChatIds.split(',').map(s => s.trim()).filter(Boolean)
198
+ : undefined
199
+ break
200
+ case 'discord':
201
+ config.listenMode = bridgeConfigForm.listenMode
202
+ config.guildId = bridgeConfigForm.guildId || undefined
203
+ config.channelId = bridgeConfigForm.channelId || undefined
204
+ break
205
+ case 'imessage':
206
+ config.strategy = bridgeConfigForm.strategy
207
+ config.allowedNumbers = bridgeConfigForm.allowedNumbers
208
+ ? bridgeConfigForm.allowedNumbers.split(',').map(s => s.trim()).filter(Boolean)
209
+ : undefined
210
+ config.blueBubblesUrl = bridgeConfigForm.blueBubblesUrl || undefined
211
+ break
212
+ case 'google':
213
+ config.enabledServices = bridgeConfigForm.enabledServices
214
+ config.account = bridgeConfigForm.account || undefined
215
+ break
216
+ case 'email':
217
+ config.imapHost = bridgeConfigForm.imapHost || undefined
218
+ config.imapPort = bridgeConfigForm.imapPort ? Number(bridgeConfigForm.imapPort) : undefined
219
+ config.smtpHost = bridgeConfigForm.smtpHost || undefined
220
+ config.smtpPort = bridgeConfigForm.smtpPort ? Number(bridgeConfigForm.smtpPort) : undefined
221
+ config.emailAddress = bridgeConfigForm.emailAddress || undefined
222
+ break
223
+ }
224
+
225
+ bridgeConfigSaving.value = true
226
+ try {
227
+ await $fetch(`/api/bridges/${editingBridge.value.id}` as string, {
228
+ method: 'PUT',
229
+ body: { name: bridgeConfigForm.name, config }
230
+ })
231
+ toast.add({ title: 'Integration updated', color: 'success' })
232
+ bridgeConfigModal.value = false
233
+ await fetchBridges()
234
+ } catch (err: unknown) {
235
+ const error = err as { data?: { message?: string } }
236
+ toast.add({ title: 'Failed to update integration', description: error.data?.message, color: 'error' })
237
+ }
238
+ bridgeConfigSaving.value = false
239
+ }
240
+
241
+ function openCreateBridge() {
242
+ bridgeForm.platform = 'telegram'
243
+ bridgeForm.name = ''
244
+ bridgeModal.value = true
245
+ }
246
+
247
+ async function handleBridgeCreate() {
248
+ if (!bridgeForm.name) {
249
+ toast.add({ title: 'Name is required', color: 'error' })
250
+ return
251
+ }
252
+ const missing = getMissingSecrets(bridgeForm.platform)
253
+ if (missing.length) {
254
+ toast.add({
255
+ title: 'Missing required secrets',
256
+ description: `Add ${missing.join(', ')} in the Secrets tab first.`,
257
+ color: 'error'
258
+ })
259
+ return
260
+ }
261
+ bridgeSaving.value = true
262
+ try {
263
+ await $fetch('/api/bridges', {
264
+ method: 'POST',
265
+ body: { platform: bridgeForm.platform, name: bridgeForm.name }
266
+ })
267
+ toast.add({ title: 'Integration created', color: 'success' })
268
+ bridgeModal.value = false
269
+ await fetchBridges()
270
+ } catch (err: unknown) {
271
+ const error = err as { data?: { message?: string } }
272
+ toast.add({ title: 'Failed to create integration', description: error.data?.message, color: 'error' })
273
+ }
274
+ bridgeSaving.value = false
275
+ }
276
+
277
+ async function toggleBridge(bridge: Bridge) {
278
+ try {
279
+ await $fetch(`/api/bridges/${bridge.id}` as string, {
280
+ method: 'PUT',
281
+ body: { enabled: !bridge.enabled }
282
+ })
283
+ await fetchBridges()
284
+ } catch {
285
+ toast.add({ title: 'Failed to update integration', color: 'error' })
286
+ }
287
+ }
288
+
289
+ function confirmDeleteBridge(bridge: Bridge) {
290
+ bridgeToDelete.value = bridge
291
+ bridgeDeleteConfirm.value = true
292
+ }
293
+
294
+ async function handleDeleteBridge() {
295
+ if (!bridgeToDelete.value) return
296
+ try {
297
+ await $fetch(`/api/bridges/${bridgeToDelete.value.id}` as string, { method: 'DELETE' })
298
+ toast.add({ title: 'Integration deleted', color: 'success' })
299
+ bridgeDeleteConfirm.value = false
300
+ bridgeToDelete.value = null
301
+ await fetchBridges()
302
+ } catch {
303
+ toast.add({ title: 'Failed to delete integration', color: 'error' })
304
+ }
305
+ }
306
+
307
+ onMounted(() => {
308
+ fetchBridges()
309
+ fetchSecretKeys()
310
+ })
311
+ </script>
312
+
313
+ <template>
314
+ <div class="py-6">
315
+ <div class="flex items-center justify-between mb-6">
316
+ <div>
317
+ <h3 class="text-lg font-semibold">
318
+ Integrations
319
+ </h3>
320
+ <p class="text-sm text-dimmed">
321
+ Connect external platforms to the message bridge.
322
+ </p>
323
+ </div>
324
+ <UButton
325
+ icon="i-lucide-plus"
326
+ @click="openCreateBridge"
327
+ >
328
+ Add Integration
329
+ </UButton>
330
+ </div>
331
+
332
+ <div
333
+ v-if="bridgesLoading"
334
+ class="space-y-3"
335
+ >
336
+ <USkeleton
337
+ v-for="i in 3"
338
+ :key="i"
339
+ class="h-16 w-full"
340
+ />
341
+ </div>
342
+
343
+ <div
344
+ v-else-if="bridgesData.length === 0"
345
+ class="py-12 text-center"
346
+ >
347
+ <UIcon
348
+ name="i-lucide-plug"
349
+ class="size-12 mx-auto mb-4 text-dimmed"
350
+ />
351
+ <p class="text-dimmed">
352
+ No integrations configured.
353
+ </p>
354
+ <p class="text-sm text-dimmed mt-1">
355
+ Connect Telegram, Discord, iMessage, or Google Suite.
356
+ </p>
357
+ </div>
358
+
359
+ <div
360
+ v-else
361
+ class="space-y-3"
362
+ >
363
+ <div
364
+ v-for="bridge in bridgesData"
365
+ :key="bridge.id"
366
+ class="border border-default rounded-lg px-4 py-3 cursor-pointer hover:bg-elevated/50 transition-colors"
367
+ @click="openBridgeConfig(bridge)"
368
+ >
369
+ <div class="flex items-center justify-between">
370
+ <div class="flex items-center gap-3">
371
+ <UIcon
372
+ :name="platformOptions.find(p => p.value === bridge.platform)?.icon || 'i-lucide-plug'"
373
+ class="size-5 text-dimmed"
374
+ />
375
+ <div>
376
+ <span class="font-medium">{{ bridge.name }}</span>
377
+ <span class="text-sm text-dimmed ml-2">{{ platformOptions.find(p => p.value === bridge.platform)?.label }}</span>
378
+ </div>
379
+ </div>
380
+ <div class="flex items-center gap-3">
381
+ <span
382
+ class="text-xs capitalize"
383
+ :class="healthColors[bridge.healthStatus] || 'text-dimmed'"
384
+ >
385
+ {{ bridge.healthStatus }}
386
+ </span>
387
+ <USwitch
388
+ :model-value="bridge.enabled"
389
+ @click.stop
390
+ @update:model-value="toggleBridge(bridge)"
391
+ />
392
+ <UButton
393
+ variant="ghost"
394
+ color="error"
395
+ icon="i-lucide-trash-2"
396
+ size="xs"
397
+ @click.stop="confirmDeleteBridge(bridge)"
398
+ />
399
+ </div>
400
+ </div>
401
+ <p
402
+ v-if="bridge.healthMessage"
403
+ class="text-xs text-dimmed mt-1 pl-8"
404
+ >
405
+ {{ bridge.healthMessage }}
406
+ </p>
407
+ </div>
408
+ </div>
409
+
410
+ <!-- Bridge Create Modal -->
411
+ <UModal v-model:open="bridgeModal">
412
+ <template #header>
413
+ <h3 class="text-lg font-semibold">
414
+ Add Integration
415
+ </h3>
416
+ </template>
417
+ <template #body>
418
+ <div class="space-y-4">
419
+ <UFormField
420
+ label="Platform"
421
+ name="platform"
422
+ >
423
+ <USelect
424
+ v-model="bridgeForm.platform"
425
+ :items="platformOptions"
426
+ value-key="value"
427
+ class="w-full"
428
+ />
429
+ </UFormField>
430
+
431
+ <!-- Missing secrets warning -->
432
+ <div
433
+ v-if="getMissingSecrets(bridgeForm.platform).length"
434
+ class="flex items-start gap-2 rounded-lg bg-error/10 border border-error/20 p-3 text-sm"
435
+ >
436
+ <UIcon
437
+ name="i-lucide-alert-triangle"
438
+ class="size-4 mt-0.5 text-error shrink-0"
439
+ />
440
+ <div>
441
+ <p class="font-medium text-error">
442
+ Missing required secrets
443
+ </p>
444
+ <p class="text-dimmed mt-1">
445
+ Add the following in Settings &rarr; Secrets before creating:
446
+ </p>
447
+ <ul class="mt-1 space-y-0.5">
448
+ <li
449
+ v-for="key in getMissingSecrets(bridgeForm.platform)"
450
+ :key="key"
451
+ >
452
+ <code class="text-xs bg-elevated px-1.5 py-0.5 rounded">{{ key }}</code>
453
+ </li>
454
+ </ul>
455
+ </div>
456
+ </div>
457
+
458
+ <UFormField
459
+ label="Name"
460
+ name="name"
461
+ >
462
+ <UInput
463
+ v-model="bridgeForm.name"
464
+ :placeholder="platformNamePlaceholders[bridgeForm.platform]"
465
+ class="w-full"
466
+ />
467
+ </UFormField>
468
+ <div class="flex justify-end gap-2 pt-4">
469
+ <UButton
470
+ variant="ghost"
471
+ @click="bridgeModal = false"
472
+ >
473
+ Cancel
474
+ </UButton>
475
+ <UButton
476
+ :loading="bridgeSaving"
477
+ :disabled="getMissingSecrets(bridgeForm.platform).length > 0"
478
+ @click="handleBridgeCreate"
479
+ >
480
+ Create
481
+ </UButton>
482
+ </div>
483
+ </div>
484
+ </template>
485
+ </UModal>
486
+
487
+ <!-- Bridge Delete Confirmation Modal -->
488
+ <UModal v-model:open="bridgeDeleteConfirm">
489
+ <template #header>
490
+ <h3 class="text-lg font-semibold">
491
+ Delete Integration
492
+ </h3>
493
+ </template>
494
+ <template #body>
495
+ <p class="mb-4">
496
+ Are you sure you want to delete <strong>{{ bridgeToDelete?.name }}</strong>?
497
+ </p>
498
+ <p class="text-sm text-dimmed">
499
+ This will remove the integration and all associated message history.
500
+ </p>
501
+ <div class="flex justify-end gap-2 pt-6">
502
+ <UButton
503
+ variant="ghost"
504
+ @click="bridgeDeleteConfirm = false"
505
+ >
506
+ Cancel
507
+ </UButton>
508
+ <UButton
509
+ color="error"
510
+ @click="handleDeleteBridge"
511
+ >
512
+ Delete
513
+ </UButton>
514
+ </div>
515
+ </template>
516
+ </UModal>
517
+
518
+ <!-- Bridge Config Modal -->
519
+ <UModal v-model:open="bridgeConfigModal">
520
+ <template #header>
521
+ <div class="flex items-center gap-2">
522
+ <UIcon
523
+ :name="platformOptions.find(p => p.value === editingBridge?.platform)?.icon || 'i-lucide-plug'"
524
+ class="size-5"
525
+ />
526
+ <h3 class="text-lg font-semibold">
527
+ Configure {{ editingBridge?.name }}
528
+ </h3>
529
+ </div>
530
+ </template>
531
+ <template #body>
532
+ <div class="space-y-4">
533
+ <!-- Secret hint -->
534
+ <div
535
+ v-if="editingBridge && platformRequiredSecrets[editingBridge.platform].length"
536
+ class="flex items-start gap-2 rounded-lg bg-elevated p-3 text-sm"
537
+ >
538
+ <UIcon
539
+ name="i-lucide-info"
540
+ class="size-4 mt-0.5 text-dimmed shrink-0"
541
+ />
542
+ <span class="text-dimmed">
543
+ Requires
544
+ <template
545
+ v-for="(key, i) in platformRequiredSecrets[editingBridge.platform]"
546
+ :key="key"
547
+ >
548
+ <code class="bg-elevated px-1 py-0.5 rounded text-xs">{{ key }}</code><template v-if="i < platformRequiredSecrets[editingBridge.platform].length - 1">, </template>
549
+ </template>
550
+ in the Secrets tab.
551
+ </span>
552
+ </div>
553
+
554
+ <!-- Common: Name -->
555
+ <UFormField
556
+ label="Name"
557
+ name="name"
558
+ >
559
+ <UInput
560
+ v-model="bridgeConfigForm.name"
561
+ placeholder="Integration name"
562
+ class="w-full"
563
+ />
564
+ </UFormField>
565
+
566
+ <!-- Telegram -->
567
+ <template v-if="editingBridge?.platform === 'telegram'">
568
+ <UFormField
569
+ label="Bot Username"
570
+ name="botUsername"
571
+ hint="Without the @ prefix"
572
+ >
573
+ <UInput
574
+ v-model="bridgeConfigForm.botUsername"
575
+ placeholder="my_bot"
576
+ class="w-full"
577
+ />
578
+ </UFormField>
579
+ <UFormField
580
+ label="Allowed Chat IDs"
581
+ name="allowedChatIds"
582
+ hint="Comma-separated. Leave empty for all."
583
+ >
584
+ <UInput
585
+ v-model="bridgeConfigForm.allowedChatIds"
586
+ placeholder="123456, -100789"
587
+ class="w-full"
588
+ />
589
+ </UFormField>
590
+ </template>
591
+
592
+ <!-- Discord -->
593
+ <template v-if="editingBridge?.platform === 'discord'">
594
+ <UFormField
595
+ label="Listen Mode"
596
+ name="listenMode"
597
+ >
598
+ <USelect
599
+ v-model="bridgeConfigForm.listenMode"
600
+ :items="discordListenModeOptions"
601
+ value-key="value"
602
+ class="w-full"
603
+ />
604
+ </UFormField>
605
+ <UFormField
606
+ label="Server ID"
607
+ name="guildId"
608
+ hint="Optional. Limit to one server."
609
+ >
610
+ <UInput
611
+ v-model="bridgeConfigForm.guildId"
612
+ placeholder="Discord server ID"
613
+ class="w-full"
614
+ />
615
+ </UFormField>
616
+ <UFormField
617
+ label="Channel ID"
618
+ name="channelId"
619
+ hint="Optional. Limit to one channel (for 'all' mode)."
620
+ >
621
+ <UInput
622
+ v-model="bridgeConfigForm.channelId"
623
+ placeholder="Discord channel ID"
624
+ class="w-full"
625
+ />
626
+ </UFormField>
627
+ </template>
628
+
629
+ <!-- iMessage -->
630
+ <template v-if="editingBridge?.platform === 'imessage'">
631
+ <UFormField
632
+ label="Strategy"
633
+ name="strategy"
634
+ >
635
+ <USelect
636
+ v-model="bridgeConfigForm.strategy"
637
+ :items="imessageStrategyOptions"
638
+ value-key="value"
639
+ class="w-full"
640
+ />
641
+ </UFormField>
642
+ <div
643
+ v-if="bridgeConfigForm.strategy === 'bluebubbles' && !secretKeys.includes('BLUEBUBBLES_PASSWORD')"
644
+ class="flex items-start gap-2 rounded-lg bg-error/10 border border-error/20 p-3 text-sm"
645
+ >
646
+ <UIcon
647
+ name="i-lucide-alert-triangle"
648
+ class="size-4 mt-0.5 text-error shrink-0"
649
+ />
650
+ <span class="text-dimmed">
651
+ BlueBubbles requires secret <code class="text-xs bg-elevated px-1.5 py-0.5 rounded">BLUEBUBBLES_PASSWORD</code> in the Secrets tab.
652
+ </span>
653
+ </div>
654
+ <UFormField
655
+ v-if="bridgeConfigForm.strategy === 'bluebubbles'"
656
+ label="BlueBubbles URL"
657
+ name="blueBubblesUrl"
658
+ >
659
+ <UInput
660
+ v-model="bridgeConfigForm.blueBubblesUrl"
661
+ placeholder="http://192.168.1.100:1234"
662
+ class="w-full"
663
+ />
664
+ </UFormField>
665
+ <UFormField
666
+ label="Allowed Numbers"
667
+ name="allowedNumbers"
668
+ hint="Comma-separated. Leave empty for all."
669
+ >
670
+ <UInput
671
+ v-model="bridgeConfigForm.allowedNumbers"
672
+ placeholder="+15551234567, +15559876543"
673
+ class="w-full"
674
+ />
675
+ </UFormField>
676
+ </template>
677
+
678
+ <!-- Google Suite -->
679
+ <template v-if="editingBridge?.platform === 'google'">
680
+ <UFormField
681
+ label="Enabled Services"
682
+ name="enabledServices"
683
+ >
684
+ <div class="space-y-2">
685
+ <label
686
+ v-for="svc in googleServiceOptions"
687
+ :key="svc.value"
688
+ class="flex items-center gap-2 cursor-pointer"
689
+ >
690
+ <input
691
+ type="checkbox"
692
+ :checked="bridgeConfigForm.enabledServices.includes(svc.value)"
693
+ class="rounded"
694
+ @change="
695
+ bridgeConfigForm.enabledServices.includes(svc.value)
696
+ ? bridgeConfigForm.enabledServices = bridgeConfigForm.enabledServices.filter(s => s !== svc.value)
697
+ : bridgeConfigForm.enabledServices.push(svc.value)
698
+ "
699
+ >
700
+ <span class="text-sm">{{ svc.label }}</span>
701
+ </label>
702
+ </div>
703
+ </UFormField>
704
+ <UFormField
705
+ label="Google Account"
706
+ name="account"
707
+ hint="Email used with gogcli"
708
+ >
709
+ <UInput
710
+ v-model="bridgeConfigForm.account"
711
+ placeholder="user@gmail.com"
712
+ class="w-full"
713
+ />
714
+ </UFormField>
715
+ </template>
716
+
717
+ <!-- Email (IMAP/SMTP) -->
718
+ <template v-if="editingBridge?.platform === 'email'">
719
+ <UFormField
720
+ label="Email Address"
721
+ name="emailAddress"
722
+ >
723
+ <UInput
724
+ v-model="bridgeConfigForm.emailAddress"
725
+ placeholder="user@example.com"
726
+ class="w-full"
727
+ />
728
+ </UFormField>
729
+ <div class="grid grid-cols-2 gap-4">
730
+ <UFormField
731
+ label="IMAP Host"
732
+ name="imapHost"
733
+ >
734
+ <UInput
735
+ v-model="bridgeConfigForm.imapHost"
736
+ placeholder="imap.example.com"
737
+ class="w-full"
738
+ />
739
+ </UFormField>
740
+ <UFormField
741
+ label="IMAP Port"
742
+ name="imapPort"
743
+ >
744
+ <UInput
745
+ v-model="bridgeConfigForm.imapPort"
746
+ placeholder="993"
747
+ class="w-full"
748
+ />
749
+ </UFormField>
750
+ </div>
751
+ <div class="grid grid-cols-2 gap-4">
752
+ <UFormField
753
+ label="SMTP Host"
754
+ name="smtpHost"
755
+ >
756
+ <UInput
757
+ v-model="bridgeConfigForm.smtpHost"
758
+ placeholder="smtp.example.com"
759
+ class="w-full"
760
+ />
761
+ </UFormField>
762
+ <UFormField
763
+ label="SMTP Port"
764
+ name="smtpPort"
765
+ >
766
+ <UInput
767
+ v-model="bridgeConfigForm.smtpPort"
768
+ placeholder="587"
769
+ class="w-full"
770
+ />
771
+ </UFormField>
772
+ </div>
773
+ </template>
774
+
775
+ <!-- Save / Cancel -->
776
+ <div class="flex justify-end gap-2 pt-4">
777
+ <UButton
778
+ variant="ghost"
779
+ @click="bridgeConfigModal = false"
780
+ >
781
+ Cancel
782
+ </UButton>
783
+ <UButton
784
+ :loading="bridgeConfigSaving"
785
+ @click="handleBridgeConfigSave"
786
+ >
787
+ Save
788
+ </UButton>
789
+ </div>
790
+ </div>
791
+ </template>
792
+ </UModal>
793
+ </div>
794
+ </template>