@lovelybunch/api 1.0.75-alpha.1 → 1.0.75-alpha.11

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 (347) hide show
  1. package/dist/lib/auth/auth-manager.d.ts +5 -0
  2. package/dist/lib/auth/auth-manager.js +9 -0
  3. package/dist/lib/jobs/job-scheduler.js +21 -0
  4. package/dist/lib/mcp-client.d.ts +39 -0
  5. package/dist/lib/mcp-client.js +131 -0
  6. package/dist/lib/slack/slack-service.d.ts +2 -0
  7. package/dist/lib/slack/slack-service.js +3 -0
  8. package/dist/lib/storage/file-storage.d.ts +16 -16
  9. package/dist/lib/storage/file-storage.js +84 -79
  10. package/dist/lib/terminal/terminal-manager.d.ts +3 -5
  11. package/dist/lib/terminal/terminal-manager.js +19 -63
  12. package/dist/middleware/auth.js +36 -0
  13. package/dist/routes/api/v1/ai/index.js +0 -2
  14. package/dist/routes/api/v1/ai/route.js +445 -259
  15. package/dist/routes/api/v1/ai/tools.js +49 -232
  16. package/dist/routes/api/v1/chats/[id]/index.js +2 -1
  17. package/dist/routes/api/v1/chats/[id]/route.d.ts +7 -0
  18. package/dist/routes/api/v1/chats/[id]/route.js +30 -1
  19. package/dist/routes/api/v1/context/index.js +0 -2
  20. package/dist/routes/api/v1/events/route.js +1 -1
  21. package/dist/routes/api/v1/events/status/route.d.ts +1 -1
  22. package/dist/routes/api/v1/git/index.js +23 -0
  23. package/dist/routes/api/v1/jobs/[id]/run/route.d.ts +2 -2
  24. package/dist/routes/api/v1/jobs/[id]/runs/[runId]/route.d.ts +2 -2
  25. package/dist/routes/api/v1/jobs/status/route.d.ts +1 -1
  26. package/dist/routes/api/v1/knowledge/[filename]/index.d.ts +1 -0
  27. package/dist/routes/api/v1/knowledge/[filename]/index.js +1 -0
  28. package/dist/routes/api/v1/knowledge/[filename]/route.d.ts +3 -0
  29. package/dist/routes/api/v1/knowledge/[filename]/route.js +254 -0
  30. package/dist/routes/api/v1/knowledge/index.d.ts +1 -0
  31. package/dist/routes/api/v1/knowledge/index.js +1 -0
  32. package/dist/routes/api/v1/knowledge/route.d.ts +3 -0
  33. package/dist/routes/api/v1/knowledge/route.js +176 -0
  34. package/dist/routes/api/v1/mcp/index.js +109 -34
  35. package/dist/routes/api/v1/proposals/[id]/route.d.ts +2 -16
  36. package/dist/routes/api/v1/proposals/[id]/route.js +10 -1
  37. package/dist/routes/api/v1/proposals/route.d.ts +2 -16
  38. package/dist/routes/api/v1/proposals/route.js +11 -8
  39. package/dist/routes/api/v1/skills/[id]/index.d.ts +1 -0
  40. package/dist/routes/api/v1/skills/[id]/index.js +1 -0
  41. package/dist/routes/api/v1/skills/[id]/route.d.ts +3 -0
  42. package/dist/routes/api/v1/skills/[id]/route.js +199 -0
  43. package/dist/routes/api/v1/skills/index.d.ts +1 -0
  44. package/dist/routes/api/v1/skills/index.js +1 -0
  45. package/dist/routes/api/v1/skills/route.d.ts +3 -0
  46. package/dist/routes/api/v1/skills/route.js +329 -0
  47. package/dist/routes/api/v1/slack/index.d.ts +3 -0
  48. package/dist/routes/api/v1/slack/index.js +15 -0
  49. package/dist/routes/api/v1/slack/route.d.ts +124 -0
  50. package/dist/routes/api/v1/slack/route.js +192 -0
  51. package/dist/routes/api/v1/tasks/[id]/route.d.ts +351 -0
  52. package/dist/routes/api/v1/tasks/[id]/route.js +166 -0
  53. package/dist/routes/api/v1/tasks/index.d.ts +3 -0
  54. package/dist/routes/api/v1/tasks/index.js +10 -0
  55. package/dist/routes/api/v1/tasks/route.d.ts +329 -0
  56. package/dist/routes/api/v1/tasks/route.js +135 -0
  57. package/dist/routes/api/v1/terminal/[taskId]/create/index.d.ts +3 -0
  58. package/dist/routes/api/v1/terminal/[taskId]/create/index.js +5 -0
  59. package/dist/routes/api/v1/terminal/[taskId]/create/route.d.ts +10 -0
  60. package/dist/routes/api/v1/terminal/[taskId]/create/route.js +27 -0
  61. package/dist/routes/api/v1/terminal/[taskId]/destroy/index.d.ts +3 -0
  62. package/dist/routes/api/v1/terminal/[taskId]/destroy/index.js +5 -0
  63. package/dist/routes/api/v1/terminal/[taskId]/destroy/route.d.ts +10 -0
  64. package/dist/routes/api/v1/terminal/[taskId]/destroy/route.js +21 -0
  65. package/dist/routes/api/v1/terminal/[taskId]/resize/index.d.ts +3 -0
  66. package/dist/routes/api/v1/terminal/[taskId]/resize/index.js +5 -0
  67. package/dist/routes/api/v1/terminal/[taskId]/resize/route.d.ts +10 -0
  68. package/dist/routes/api/v1/terminal/[taskId]/resize/route.js +21 -0
  69. package/dist/routes/api/v1/terminal/sessions/route.js +4 -4
  70. package/dist/server-with-static.js +20 -14
  71. package/dist/server.js +17 -13
  72. package/package.json +8 -4
  73. package/static/assets/{ActivityPage-BYrDJlH6.js → ActivityPage-D2Zn5d46.js} +1 -1
  74. package/static/assets/ApiKeysSettingsPage-0lTMGFnh.js +2 -0
  75. package/static/assets/{ArchitectureEditPage-Bw2d_hmk.js → ArchitectureEditPage-D_zjOlNp.js} +4 -4
  76. package/static/assets/{ArchitecturePage-36wO0UD7.js → ArchitecturePage-Dl9wMPRA.js} +1 -1
  77. package/static/assets/{AuthSettingsPage-CKifiWsx.js → AuthSettingsPage-DN-0d5JC.js} +2 -2
  78. package/static/assets/{CallbackPage-Ck0dddEW.js → CallbackPage-pSUHwS6c.js} +1 -1
  79. package/static/assets/CodePage-BmEgabxr.js +2 -0
  80. package/static/assets/{CollapsibleSection-BKY-lfsm.js → CollapsibleSection-C1zNDYCh.js} +1 -1
  81. package/static/assets/DashboardPage-CdFJwMmF.js +41 -0
  82. package/static/assets/{GitPage-BgCxzm-C.js → GitPage-ANlhUZHS.js} +2 -2
  83. package/static/assets/GitSettingsPage-DNxK8DVa.js +6 -0
  84. package/static/assets/IdentityPage-9pFdjcFE.js +11 -0
  85. package/static/assets/{ImplementationStepsEditor-iqrCqyOb.js → ImplementationStepsEditor-DEHSnp5F.js} +2 -2
  86. package/static/assets/IntegrationsSettingsPage-CwkwL5dd.js +1 -0
  87. package/static/assets/JobDetailPage-BLlAzyE-.js +1 -0
  88. package/static/assets/KnowledgeDetailPage-CFJNJhhN.js +1 -0
  89. package/static/assets/KnowledgeEditPage-DVtiPXb_.js +1 -0
  90. package/static/assets/KnowledgePage-CuTDH9Bh.js +8 -0
  91. package/static/assets/{LoginPage-DqbNxfY6.js → LoginPage-3DBi_hwv.js} +1 -1
  92. package/static/assets/McpSettingsPage-BxHz335r.js +1 -0
  93. package/static/assets/NewKnowledgePage-9sB6TdTV.js +9 -0
  94. package/static/assets/NewSkillPage-BYBe6r4d.js +1 -0
  95. package/static/assets/NewTaskPage-BE5Yj7RD.js +90 -0
  96. package/static/assets/NotificationsSettingsPage-CPtkulC9.js +1 -0
  97. package/static/assets/ProjectEditPage-D9VtPWSD.js +11 -0
  98. package/static/assets/ProjectPage-Bk8hmnzz.js +1 -0
  99. package/static/assets/PromptsSettingsPage-B-Li6zb3.js +1 -0
  100. package/static/assets/ResourceDetailPage-Bn4NqBh7.js +1 -0
  101. package/static/assets/ResourcesPage-CbaDzx36.js +41 -0
  102. package/static/assets/{RoleEditPage-DhVneoNR.js → RoleEditPage-BljkqDbs.js} +1 -1
  103. package/static/assets/{RolePage-BOI2T8QG.js → RolePage-CDuVbr3S.js} +1 -1
  104. package/static/assets/{RulesSettingsPage-VsteFA-j.js → RulesSettingsPage-DtUPyjeR.js} +3 -3
  105. package/static/assets/SchedulePage-DEsE75St.js +4 -0
  106. package/static/assets/SkillDetailPage-BcISA93H.js +1 -0
  107. package/static/assets/SkillEditPage-BTEUvSu8.js +1 -0
  108. package/static/assets/SkillsPage-C6L7hMMN.js +8 -0
  109. package/static/assets/SkillsSettingsPage-Blc14fBy.js +1 -0
  110. package/static/assets/SourceInput-BtfMG5Wi.js +1 -0
  111. package/static/assets/{TagInput-BWLBdW8h.js → TagInput-DilIgbMg.js} +1 -1
  112. package/static/assets/TaskDetailPage-DEx9t61F.js +1 -0
  113. package/static/assets/TaskEditPage-tdpsj4yx.js +1 -0
  114. package/static/assets/TasksPage-DmLPtmET.js +17 -0
  115. package/static/assets/TerminalPage-A9Y67fNY.js +1 -0
  116. package/static/assets/TerminalSessionPage-CDqHiRaw.js +8 -0
  117. package/static/assets/UserPreferencesPage-DxUovKgK.js +1 -0
  118. package/static/assets/UserSettingsPage-1tv40FUQ.js +1 -0
  119. package/static/assets/UtilitiesPage-CrIhyr9_.js +1 -0
  120. package/static/assets/{alert-C7sSXJf0.js → alert-CXesMmyn.js} +1 -1
  121. package/static/assets/{arrow-down-DNa4SyO2.js → arrow-down-D9etuMoO.js} +1 -1
  122. package/static/assets/{arrow-left-DkoECaEJ.js → arrow-left-DkTfMrSs.js} +1 -1
  123. package/static/assets/{arrow-up-DQlu6uQE.js → arrow-up-DFr-vJJy.js} +1 -1
  124. package/static/assets/{badge-2ZOe5ynf.js → badge-HE5_fZGv.js} +1 -1
  125. package/static/assets/{browser-modal-DUCXGaha.js → browser-modal-88xCtQmC.js} +2 -2
  126. package/static/assets/{card-By4vbQ_f.js → card-B9S2Vx-U.js} +1 -1
  127. package/static/assets/{chevron-left-CJfNRqcH.js → chevron-left-B5rTh5xo.js} +1 -1
  128. package/static/assets/{plus-D0SUNNMH.js → chevron-up-CtmGm2DE.js} +2 -2
  129. package/static/assets/{chevrons-up-DoBrp0tt.js → chevrons-up-GjZHuxUC.js} +1 -1
  130. package/static/assets/{circle-alert-B4JJ0jKl.js → circle-alert-ZaSVIm5w.js} +1 -1
  131. package/static/assets/{circle-check-DC5Ek4MP.js → circle-check-OAMs0qqg.js} +1 -1
  132. package/static/assets/{circle-check-big-Dw4YJZos.js → circle-check-big-Csdz5GpZ.js} +1 -1
  133. package/static/assets/{circle-play-D9VS6Vdc.js → circle-play-DJyQPZbX.js} +1 -1
  134. package/static/assets/{circle-x-BReHgv4g.js → circle-x-DTr1fuxL.js} +1 -1
  135. package/static/assets/{clipboard-CuF9OlXN.js → clipboard-CwF3EWpN.js} +1 -1
  136. package/static/assets/{clock-CDTi2Cen.js → clock-e7nPzZrg.js} +1 -1
  137. package/static/assets/{download-DHIAgGlY.js → download-CmRC-PIa.js} +1 -1
  138. package/static/assets/droid-GYYyVzN-.js +18 -0
  139. package/static/assets/external-link-Bd24IGgw.js +6 -0
  140. package/static/assets/{eye-Ch7ecV9Z.js → eye-3OOczSrt.js} +1 -1
  141. package/static/assets/{folder-git-2-BYI_osdA.js → folder-git-2-C56Y-a-e.js} +1 -1
  142. package/static/assets/index-C_PmFIdi.css +2 -0
  143. package/static/assets/index-DzkC23id.js +477 -0
  144. package/static/assets/info-DOwvZM1c.js +6 -0
  145. package/static/assets/{label-BUv8Ltyw.js → label-BuTjh35X.js} +1 -1
  146. package/static/assets/{markdown-editor-BP8Xkecg.js → markdown-editor-DjkUR4bk.js} +1 -1
  147. package/static/assets/message-square-BKOo6mJX.js +6 -0
  148. package/static/assets/{pause-B0clczfE.js → pause-DTfqRkj4.js} +1 -1
  149. package/static/assets/{play-BHUpJCX1.js → play-CsdqpNIM.js} +1 -1
  150. package/static/assets/{radio-group-CSBH8ca-.js → radio-group-CkPIdZF9.js} +1 -1
  151. package/static/assets/{refresh-cw-C-yGwsHL.js → refresh-cw-5otO2hn8.js} +1 -1
  152. package/static/assets/{search-DFtqbVgP.js → search-B9lSaTJ3.js} +1 -1
  153. package/static/assets/select-BCvXvaCZ.js +1 -0
  154. package/static/assets/status-utils-CDkPeVfP.js +1 -0
  155. package/static/assets/{switch-WtOd8h5Z.js → switch-ME5yEkkm.js} +1 -1
  156. package/static/assets/{tabs-D93ZjKR7.js → tabs-CzKrO1bf.js} +1 -1
  157. package/static/assets/{tag-EEDDoCc_.js → tag-BCm1ofRX.js} +1 -1
  158. package/static/assets/{terminal-preview-sns5QTN_.js → terminal-preview-6VAQZGAD.js} +1 -1
  159. package/static/assets/use-terminal-D1ZnDkIm.js +1 -0
  160. package/static/assets/video-Yeqgj72x.js +36 -0
  161. package/static/assets/{zap-BYFYWzmj.js → zap-BQdeicHZ.js} +1 -1
  162. package/static/index.html +2 -2
  163. package/dist/lib/auth/auth-manager.d.ts.map +0 -1
  164. package/dist/lib/auth/auth-manager.js.map +0 -1
  165. package/dist/lib/gait-path.d.ts.map +0 -1
  166. package/dist/lib/gait-path.js.map +0 -1
  167. package/dist/lib/git-settings.d.ts.map +0 -1
  168. package/dist/lib/git-settings.js.map +0 -1
  169. package/dist/lib/git.d.ts.map +0 -1
  170. package/dist/lib/git.js.map +0 -1
  171. package/dist/lib/jobs/global-job-scheduler.d.ts.map +0 -1
  172. package/dist/lib/jobs/global-job-scheduler.js.map +0 -1
  173. package/dist/lib/jobs/job-runner.d.ts.map +0 -1
  174. package/dist/lib/jobs/job-runner.js.map +0 -1
  175. package/dist/lib/jobs/job-scheduler.d.ts.map +0 -1
  176. package/dist/lib/jobs/job-scheduler.js.map +0 -1
  177. package/dist/lib/jobs/job-store.d.ts.map +0 -1
  178. package/dist/lib/jobs/job-store.js.map +0 -1
  179. package/dist/lib/project-paths.d.ts.map +0 -1
  180. package/dist/lib/project-paths.js.map +0 -1
  181. package/dist/lib/storage/file-storage.d.ts.map +0 -1
  182. package/dist/lib/storage/file-storage.js.map +0 -1
  183. package/dist/lib/symlinks/symlink-manager.d.ts.map +0 -1
  184. package/dist/lib/symlinks/symlink-manager.js.map +0 -1
  185. package/dist/lib/symlinks/types.d.ts.map +0 -1
  186. package/dist/lib/symlinks/types.js.map +0 -1
  187. package/dist/lib/terminal/context-helper.d.ts.map +0 -1
  188. package/dist/lib/terminal/context-helper.js.map +0 -1
  189. package/dist/lib/terminal/global-manager.d.ts.map +0 -1
  190. package/dist/lib/terminal/global-manager.js.map +0 -1
  191. package/dist/lib/terminal/shell-utils.d.ts.map +0 -1
  192. package/dist/lib/terminal/shell-utils.js.map +0 -1
  193. package/dist/lib/terminal/terminal-manager.d.ts.map +0 -1
  194. package/dist/lib/terminal/terminal-manager.js.map +0 -1
  195. package/dist/lib/user-preferences.d.ts.map +0 -1
  196. package/dist/lib/user-preferences.js.map +0 -1
  197. package/dist/middleware/auth.d.ts.map +0 -1
  198. package/dist/middleware/auth.js.map +0 -1
  199. package/dist/routes/api/v1/agents/[id]/index.d.ts.map +0 -1
  200. package/dist/routes/api/v1/agents/[id]/index.js.map +0 -1
  201. package/dist/routes/api/v1/agents/[id]/route.d.ts.map +0 -1
  202. package/dist/routes/api/v1/agents/[id]/route.js.map +0 -1
  203. package/dist/routes/api/v1/agents/index.d.ts.map +0 -1
  204. package/dist/routes/api/v1/agents/index.js.map +0 -1
  205. package/dist/routes/api/v1/agents/route.d.ts.map +0 -1
  206. package/dist/routes/api/v1/agents/route.js.map +0 -1
  207. package/dist/routes/api/v1/ai/index.d.ts.map +0 -1
  208. package/dist/routes/api/v1/ai/index.js.map +0 -1
  209. package/dist/routes/api/v1/ai/route.d.ts.map +0 -1
  210. package/dist/routes/api/v1/ai/route.js.map +0 -1
  211. package/dist/routes/api/v1/api-keys/index.d.ts.map +0 -1
  212. package/dist/routes/api/v1/api-keys/index.js.map +0 -1
  213. package/dist/routes/api/v1/api-keys/route.d.ts.map +0 -1
  214. package/dist/routes/api/v1/api-keys/route.js.map +0 -1
  215. package/dist/routes/api/v1/auth/index.d.ts.map +0 -1
  216. package/dist/routes/api/v1/auth/index.js.map +0 -1
  217. package/dist/routes/api/v1/auth/route.d.ts.map +0 -1
  218. package/dist/routes/api/v1/auth/route.js.map +0 -1
  219. package/dist/routes/api/v1/auth-settings/index.d.ts.map +0 -1
  220. package/dist/routes/api/v1/auth-settings/index.js.map +0 -1
  221. package/dist/routes/api/v1/auth-settings/route.d.ts.map +0 -1
  222. package/dist/routes/api/v1/auth-settings/route.js.map +0 -1
  223. package/dist/routes/api/v1/chats/[id]/index.d.ts.map +0 -1
  224. package/dist/routes/api/v1/chats/[id]/index.js.map +0 -1
  225. package/dist/routes/api/v1/chats/[id]/route.d.ts.map +0 -1
  226. package/dist/routes/api/v1/chats/[id]/route.js.map +0 -1
  227. package/dist/routes/api/v1/chats/index.d.ts.map +0 -1
  228. package/dist/routes/api/v1/chats/index.js.map +0 -1
  229. package/dist/routes/api/v1/chats/route.d.ts.map +0 -1
  230. package/dist/routes/api/v1/chats/route.js.map +0 -1
  231. package/dist/routes/api/v1/config/index.d.ts.map +0 -1
  232. package/dist/routes/api/v1/config/index.js.map +0 -1
  233. package/dist/routes/api/v1/config/route.d.ts.map +0 -1
  234. package/dist/routes/api/v1/config/route.js.map +0 -1
  235. package/dist/routes/api/v1/context/architecture/route.d.ts.map +0 -1
  236. package/dist/routes/api/v1/context/architecture/route.js.map +0 -1
  237. package/dist/routes/api/v1/context/index.d.ts.map +0 -1
  238. package/dist/routes/api/v1/context/index.js.map +0 -1
  239. package/dist/routes/api/v1/context/knowledge/[filename]/index.d.ts.map +0 -1
  240. package/dist/routes/api/v1/context/knowledge/[filename]/index.js.map +0 -1
  241. package/dist/routes/api/v1/context/knowledge/[filename]/route.d.ts.map +0 -1
  242. package/dist/routes/api/v1/context/knowledge/[filename]/route.js.map +0 -1
  243. package/dist/routes/api/v1/context/knowledge/index.d.ts.map +0 -1
  244. package/dist/routes/api/v1/context/knowledge/index.js.map +0 -1
  245. package/dist/routes/api/v1/context/knowledge/route.d.ts.map +0 -1
  246. package/dist/routes/api/v1/context/knowledge/route.js.map +0 -1
  247. package/dist/routes/api/v1/context/project/route.d.ts.map +0 -1
  248. package/dist/routes/api/v1/context/project/route.js.map +0 -1
  249. package/dist/routes/api/v1/git/index.d.ts.map +0 -1
  250. package/dist/routes/api/v1/git/index.js.map +0 -1
  251. package/dist/routes/api/v1/jobs/[id]/route.d.ts.map +0 -1
  252. package/dist/routes/api/v1/jobs/[id]/route.js.map +0 -1
  253. package/dist/routes/api/v1/jobs/[id]/run/route.d.ts.map +0 -1
  254. package/dist/routes/api/v1/jobs/[id]/run/route.js.map +0 -1
  255. package/dist/routes/api/v1/jobs/index.d.ts.map +0 -1
  256. package/dist/routes/api/v1/jobs/index.js.map +0 -1
  257. package/dist/routes/api/v1/jobs/route.d.ts.map +0 -1
  258. package/dist/routes/api/v1/jobs/route.js.map +0 -1
  259. package/dist/routes/api/v1/jobs/status/route.d.ts.map +0 -1
  260. package/dist/routes/api/v1/jobs/status/route.js.map +0 -1
  261. package/dist/routes/api/v1/mcp/index.d.ts.map +0 -1
  262. package/dist/routes/api/v1/mcp/index.js.map +0 -1
  263. package/dist/routes/api/v1/mcp/route.d.ts.map +0 -1
  264. package/dist/routes/api/v1/mcp/route.js.map +0 -1
  265. package/dist/routes/api/v1/proposals/[id]/route.d.ts.map +0 -1
  266. package/dist/routes/api/v1/proposals/[id]/route.js.map +0 -1
  267. package/dist/routes/api/v1/proposals/index.d.ts.map +0 -1
  268. package/dist/routes/api/v1/proposals/index.js.map +0 -1
  269. package/dist/routes/api/v1/proposals/route.d.ts.map +0 -1
  270. package/dist/routes/api/v1/proposals/route.js.map +0 -1
  271. package/dist/routes/api/v1/resources/[id]/index.d.ts.map +0 -1
  272. package/dist/routes/api/v1/resources/[id]/index.js.map +0 -1
  273. package/dist/routes/api/v1/resources/[id]/route.js.map +0 -1
  274. package/dist/routes/api/v1/resources/[id]/thumbnail/index.d.ts.map +0 -1
  275. package/dist/routes/api/v1/resources/[id]/thumbnail/index.js.map +0 -1
  276. package/dist/routes/api/v1/resources/[id]/thumbnail/route.js.map +0 -1
  277. package/dist/routes/api/v1/resources/index.d.ts.map +0 -1
  278. package/dist/routes/api/v1/resources/index.js.map +0 -1
  279. package/dist/routes/api/v1/resources/route.d.ts.map +0 -1
  280. package/dist/routes/api/v1/resources/route.js.map +0 -1
  281. package/dist/routes/api/v1/symlinks/index.d.ts.map +0 -1
  282. package/dist/routes/api/v1/symlinks/index.js.map +0 -1
  283. package/dist/routes/api/v1/symlinks/route.d.ts.map +0 -1
  284. package/dist/routes/api/v1/symlinks/route.js.map +0 -1
  285. package/dist/routes/api/v1/terminal/[proposalId]/create/index.d.ts.map +0 -1
  286. package/dist/routes/api/v1/terminal/[proposalId]/create/index.js.map +0 -1
  287. package/dist/routes/api/v1/terminal/[proposalId]/create/route.d.ts.map +0 -1
  288. package/dist/routes/api/v1/terminal/[proposalId]/create/route.js.map +0 -1
  289. package/dist/routes/api/v1/terminal/[proposalId]/destroy/index.d.ts.map +0 -1
  290. package/dist/routes/api/v1/terminal/[proposalId]/destroy/index.js.map +0 -1
  291. package/dist/routes/api/v1/terminal/[proposalId]/destroy/route.d.ts.map +0 -1
  292. package/dist/routes/api/v1/terminal/[proposalId]/destroy/route.js.map +0 -1
  293. package/dist/routes/api/v1/terminal/[proposalId]/resize/index.d.ts.map +0 -1
  294. package/dist/routes/api/v1/terminal/[proposalId]/resize/index.js.map +0 -1
  295. package/dist/routes/api/v1/terminal/[proposalId]/resize/route.d.ts.map +0 -1
  296. package/dist/routes/api/v1/terminal/[proposalId]/resize/route.js.map +0 -1
  297. package/dist/routes/api/v1/terminal/sessions/index.d.ts.map +0 -1
  298. package/dist/routes/api/v1/terminal/sessions/index.js.map +0 -1
  299. package/dist/routes/api/v1/terminal/sessions/route.d.ts.map +0 -1
  300. package/dist/routes/api/v1/terminal/sessions/route.js.map +0 -1
  301. package/dist/routes/api/v1/user/index.d.ts.map +0 -1
  302. package/dist/routes/api/v1/user/index.js.map +0 -1
  303. package/dist/routes/api/v1/user/settings/index.d.ts.map +0 -1
  304. package/dist/routes/api/v1/user/settings/index.js.map +0 -1
  305. package/dist/routes/api/v1/user/settings/route.d.ts.map +0 -1
  306. package/dist/routes/api/v1/user/settings/route.js.map +0 -1
  307. package/dist/server-with-static.d.ts.map +0 -1
  308. package/dist/server-with-static.js.map +0 -1
  309. package/dist/server.d.ts.map +0 -1
  310. package/dist/server.js.map +0 -1
  311. package/static/assets/AgentDetailPage-D6yg4CtT.js +0 -1
  312. package/static/assets/AgentEditPage-CTnjxjX7.js +0 -1
  313. package/static/assets/AgentsPage-NdB5OB1C.js +0 -3
  314. package/static/assets/AgentsSettingsPage-CYXp908g.js +0 -6
  315. package/static/assets/ApiKeysSettingsPage-Jl6vvVmW.js +0 -7
  316. package/static/assets/CodePage-b3JR4eWW.js +0 -2
  317. package/static/assets/DashboardPage-Cv2-duAx.js +0 -41
  318. package/static/assets/GitSettingsPage-CKIWkAnw.js +0 -6
  319. package/static/assets/IdentityPage-BsZnszF-.js +0 -11
  320. package/static/assets/IntegrationsSettingsPage-C1dC_vVy.js +0 -1
  321. package/static/assets/JobDetailPage-BgGQJkND.js +0 -1
  322. package/static/assets/KnowledgeDetailPage-Dzy2V7yT.js +0 -1
  323. package/static/assets/KnowledgeEditPage-av1ALt0h.js +0 -1
  324. package/static/assets/KnowledgePage-C_UDfD9X.js +0 -8
  325. package/static/assets/McpSettingsPage-BqbErEWS.js +0 -1
  326. package/static/assets/NewAgentPage-UEVIYkt3.js +0 -1
  327. package/static/assets/NewKnowledgePage-CzYXdoDb.js +0 -9
  328. package/static/assets/NewProposalPage-DrU0ihJX.js +0 -90
  329. package/static/assets/ProjectEditPage-j4KporiC.js +0 -11
  330. package/static/assets/ProjectPage-BQNa0qA-.js +0 -1
  331. package/static/assets/PromptsSettingsPage-sYphs8Dn.js +0 -1
  332. package/static/assets/ProposalDetailPage-CHR1MmwC.js +0 -1
  333. package/static/assets/ProposalEditPage-CkcZqgax.js +0 -1
  334. package/static/assets/ProposalsPage-CUB_aLXW.js +0 -17
  335. package/static/assets/ResourcesPage-DzjwPoyS.js +0 -71
  336. package/static/assets/SchedulePage-_v4YfdHo.js +0 -4
  337. package/static/assets/SourceInput-BFxoOvqS.js +0 -1
  338. package/static/assets/TerminalPage-DtVDWX7G.js +0 -1
  339. package/static/assets/TerminalSessionPage-BUHzje8A.js +0 -13
  340. package/static/assets/UserPreferencesPage-CkXJuogz.js +0 -1
  341. package/static/assets/UserSettingsPage-Dz-R1ijS.js +0 -1
  342. package/static/assets/UtilitiesPage-CRqQYVsb.js +0 -1
  343. package/static/assets/calendar-tNgwmWmG.js +0 -6
  344. package/static/assets/droid-BvMEm3eg.js +0 -8
  345. package/static/assets/index-CCs6x1Au.js +0 -468
  346. package/static/assets/index-CzjbtPHw.css +0 -2
  347. package/static/assets/use-terminal-BW9XYY8N.js +0 -1
@@ -0,0 +1,329 @@
1
+ import { Hono } from 'hono';
2
+ import { promises as fs } from 'fs';
3
+ import path from 'path';
4
+ import matter from 'gray-matter';
5
+ import AdmZip from 'adm-zip';
6
+ const app = new Hono();
7
+ const ALLOWED_ARCHIVE_HOSTS = [
8
+ 'registry.coconut.dev',
9
+ ];
10
+ const MAX_ARCHIVE_SIZE = 50 * 1024 * 1024; // 50 MB
11
+ /** Paths to skip entirely when extracting zip archives (macOS resource forks, etc.) */
12
+ const IGNORED_ZIP_PREFIXES = ['__MACOSX/', '.DS_Store'];
13
+ function isIgnoredZipEntry(entryName) {
14
+ return IGNORED_ZIP_PREFIXES.some(prefix => entryName.startsWith(prefix) || entryName === prefix);
15
+ }
16
+ /**
17
+ * Detect if all zip entries share a single wrapping directory (e.g., `pptx/...`).
18
+ * Returns the prefix (with trailing slash) to strip, or null if no wrapper.
19
+ * Ignores macOS resource fork entries (__MACOSX/) when detecting the prefix.
20
+ */
21
+ function detectWrapperPrefix(entries) {
22
+ const paths = entries
23
+ .map(e => e.entryName)
24
+ .filter(name => name !== '/' && name !== '' && !isIgnoredZipEntry(name));
25
+ if (paths.length === 0)
26
+ return null;
27
+ const prefixes = new Set(paths.map(p => {
28
+ const firstSlash = p.indexOf('/');
29
+ return firstSlash >= 0 ? p.substring(0, firstSlash + 1) : null;
30
+ }));
31
+ // If all entries share exactly one prefix directory, strip it
32
+ if (prefixes.size === 1) {
33
+ const prefix = [...prefixes][0];
34
+ if (prefix !== null)
35
+ return prefix;
36
+ }
37
+ return null;
38
+ }
39
+ /**
40
+ * Download a zip archive from a trusted URL and extract it into destDir.
41
+ * Returns true if extraction succeeded and SKILL.md exists in the output.
42
+ */
43
+ async function downloadAndExtractArchive(archiveUrl, destDir) {
44
+ // Validate URL against allow-list
45
+ let parsed;
46
+ try {
47
+ parsed = new URL(archiveUrl);
48
+ }
49
+ catch {
50
+ throw new Error('Invalid archive URL');
51
+ }
52
+ if (!ALLOWED_ARCHIVE_HOSTS.includes(parsed.hostname)) {
53
+ throw new Error(`Archive host '${parsed.hostname}' is not trusted`);
54
+ }
55
+ // Download the zip
56
+ const response = await fetch(archiveUrl, {
57
+ headers: { 'User-Agent': 'coconut-api' },
58
+ });
59
+ if (!response.ok) {
60
+ throw new Error(`Failed to download archive: ${response.status} ${response.statusText}`);
61
+ }
62
+ const contentLength = Number(response.headers.get('content-length') || '0');
63
+ if (contentLength > MAX_ARCHIVE_SIZE) {
64
+ throw new Error(`Archive too large (${contentLength} bytes, max ${MAX_ARCHIVE_SIZE})`);
65
+ }
66
+ const buffer = Buffer.from(await response.arrayBuffer());
67
+ if (buffer.length > MAX_ARCHIVE_SIZE) {
68
+ throw new Error(`Archive too large (${buffer.length} bytes, max ${MAX_ARCHIVE_SIZE})`);
69
+ }
70
+ // Extract with path-traversal protection
71
+ const zip = new AdmZip(buffer);
72
+ const entries = zip.getEntries();
73
+ const wrapperPrefix = detectWrapperPrefix(entries);
74
+ await fs.mkdir(destDir, { recursive: true });
75
+ for (const entry of entries) {
76
+ let entryName = entry.entryName;
77
+ // Skip macOS resource fork junk and other ignored entries
78
+ if (isIgnoredZipEntry(entryName))
79
+ continue;
80
+ // Strip single wrapping directory if detected (e.g., pptx/SKILL.md -> SKILL.md)
81
+ if (wrapperPrefix && entryName.startsWith(wrapperPrefix)) {
82
+ entryName = entryName.substring(wrapperPrefix.length);
83
+ }
84
+ if (!entryName || entryName === '/')
85
+ continue;
86
+ // Reject paths that attempt directory traversal
87
+ const resolved = path.resolve(destDir, entryName);
88
+ if (!resolved.startsWith(path.resolve(destDir) + path.sep) && resolved !== path.resolve(destDir)) {
89
+ console.warn(`Skipping zip entry with path traversal: ${entryName}`);
90
+ continue;
91
+ }
92
+ if (entry.isDirectory) {
93
+ await fs.mkdir(resolved, { recursive: true });
94
+ }
95
+ else {
96
+ await fs.mkdir(path.dirname(resolved), { recursive: true });
97
+ await fs.writeFile(resolved, entry.getData());
98
+ }
99
+ }
100
+ // Check if SKILL.md was extracted
101
+ try {
102
+ await fs.access(path.join(destDir, 'SKILL.md'));
103
+ return true;
104
+ }
105
+ catch {
106
+ return false;
107
+ }
108
+ }
109
+ /**
110
+ * Validate skill name per Agent Skills spec:
111
+ * - 1-64 characters
112
+ * - Lowercase letters, numbers, hyphens only
113
+ * - No leading/trailing hyphens
114
+ * - No consecutive hyphens
115
+ */
116
+ function validateSkillName(name) {
117
+ if (!name || name.length === 0)
118
+ return 'Name is required';
119
+ if (name.length > 64)
120
+ return 'Name must be 64 characters or fewer';
121
+ if (!/^[a-z0-9]([a-z0-9-]*[a-z0-9])?$/.test(name)) {
122
+ return 'Name must contain only lowercase letters, numbers, and hyphens, and must not start or end with a hyphen';
123
+ }
124
+ if (/--/.test(name))
125
+ return 'Name must not contain consecutive hyphens';
126
+ return null;
127
+ }
128
+ function generateSkillId(name) {
129
+ return name
130
+ .toLowerCase()
131
+ .replace(/[^a-z0-9\s-]/g, '')
132
+ .replace(/\s+/g, '-')
133
+ .replace(/--+/g, '-')
134
+ .replace(/^-|-$/g, '');
135
+ }
136
+ function getSkillsPath() {
137
+ let basePath;
138
+ if (process.env.NODE_ENV === 'development' && process.env.GAIT_DEV_ROOT) {
139
+ basePath = process.env.GAIT_DEV_ROOT;
140
+ }
141
+ else if (process.env.GAIT_DATA_PATH) {
142
+ basePath = path.resolve(process.env.GAIT_DATA_PATH, '.nut');
143
+ }
144
+ else {
145
+ basePath = path.resolve(process.cwd(), '.nut');
146
+ }
147
+ return path.join(basePath, 'skills');
148
+ }
149
+ /**
150
+ * GET /api/v1/skills
151
+ * Load all skill documents
152
+ */
153
+ app.get('/', async (c) => {
154
+ try {
155
+ const skillsPath = getSkillsPath();
156
+ await fs.mkdir(skillsPath, { recursive: true });
157
+ const entries = await fs.readdir(skillsPath, { withFileTypes: true });
158
+ const skills = await Promise.all(entries
159
+ .filter(entry => entry.isDirectory())
160
+ .map(async (entry) => {
161
+ const skillFile = path.join(skillsPath, entry.name, 'SKILL.md');
162
+ try {
163
+ const fileContent = await fs.readFile(skillFile, 'utf-8');
164
+ const { data, content } = matter(fileContent);
165
+ const nestedMeta = typeof data.metadata === 'object' ? data.metadata : undefined;
166
+ const doc = {
167
+ id: entry.name,
168
+ name: data.name || entry.name,
169
+ description: data.description || '',
170
+ ...(data.license ? { license: data.license } : {}),
171
+ ...(data.compatibility ? { compatibility: data.compatibility } : {}),
172
+ ...(data['allowed-tools'] || data.allowedTools ? { allowedTools: data['allowed-tools'] || data.allowedTools } : {}),
173
+ metadata: {
174
+ name: data.name || entry.name,
175
+ description: data.description || '',
176
+ ...(nestedMeta || {}),
177
+ },
178
+ content,
179
+ };
180
+ return doc;
181
+ }
182
+ catch {
183
+ // Skip directories without valid SKILL.md
184
+ return null;
185
+ }
186
+ }));
187
+ const validSkills = skills.filter((s) => s !== null);
188
+ return c.json({
189
+ success: true,
190
+ documents: validSkills.sort((a, b) => a.id.localeCompare(b.id))
191
+ });
192
+ }
193
+ catch (error) {
194
+ console.error('Error loading skill documents:', error);
195
+ return c.json({
196
+ success: false,
197
+ error: 'Failed to load skill documents',
198
+ documents: []
199
+ }, 500);
200
+ }
201
+ });
202
+ /**
203
+ * POST /api/v1/skills
204
+ * Create a new skill document
205
+ */
206
+ app.post('/', async (c) => {
207
+ try {
208
+ const body = await c.req.json();
209
+ if (!body.name || !body.description) {
210
+ return c.json({ success: false, error: 'Name and description are required' }, 400);
211
+ }
212
+ const skillId = generateSkillId(body.name);
213
+ const nameError = validateSkillName(skillId);
214
+ if (nameError) {
215
+ return c.json({ success: false, error: nameError }, 400);
216
+ }
217
+ const skillsPath = getSkillsPath();
218
+ const skillDir = path.join(skillsPath, skillId);
219
+ // Check if skill directory already exists
220
+ try {
221
+ await fs.access(path.join(skillDir, 'SKILL.md'));
222
+ return c.json({ success: false, error: 'A skill with this name already exists' }, 409);
223
+ }
224
+ catch {
225
+ // Doesn't exist, proceed
226
+ }
227
+ // Create skill directory
228
+ await fs.mkdir(skillDir, { recursive: true });
229
+ let finalContent = body.content || '';
230
+ if (body.archiveUrl) {
231
+ // Download and extract archive — SKILL.md comes from the zip
232
+ try {
233
+ const hasSkillMd = await downloadAndExtractArchive(body.archiveUrl, skillDir);
234
+ if (!hasSkillMd) {
235
+ // Fallback: generate SKILL.md from JSON fields if the archive didn't include one
236
+ const frontmatter = {
237
+ name: skillId,
238
+ description: body.description,
239
+ };
240
+ if (body.license)
241
+ frontmatter.license = body.license;
242
+ if (body.compatibility)
243
+ frontmatter.compatibility = body.compatibility;
244
+ if (body.allowedTools)
245
+ frontmatter['allowed-tools'] = body.allowedTools;
246
+ if (body.metadata && Object.keys(body.metadata).length > 0) {
247
+ const meta = {};
248
+ for (const [key, value] of Object.entries(body.metadata)) {
249
+ if (value !== undefined && value !== null) {
250
+ meta[key] = value;
251
+ }
252
+ }
253
+ if (Object.keys(meta).length > 0) {
254
+ frontmatter.metadata = meta;
255
+ }
256
+ }
257
+ const fileContent = matter.stringify(finalContent, frontmatter);
258
+ await fs.writeFile(path.join(skillDir, 'SKILL.md'), fileContent, 'utf-8');
259
+ }
260
+ // Read back SKILL.md content for the response
261
+ try {
262
+ const written = await fs.readFile(path.join(skillDir, 'SKILL.md'), 'utf-8');
263
+ const { data: extractedFrontmatter, content: mdContent } = matter(written);
264
+ finalContent = mdContent;
265
+ // If the extracted SKILL.md body is empty but we have registry content,
266
+ // append it as a fallback and rewrite the file
267
+ if (!mdContent.trim() && body.content?.trim()) {
268
+ const rewritten = matter.stringify(body.content, extractedFrontmatter);
269
+ await fs.writeFile(path.join(skillDir, 'SKILL.md'), rewritten, 'utf-8');
270
+ finalContent = body.content;
271
+ }
272
+ }
273
+ catch {
274
+ // best effort
275
+ }
276
+ }
277
+ catch (archiveError) {
278
+ // Clean up the directory on failure
279
+ await fs.rm(skillDir, { recursive: true, force: true }).catch(() => { });
280
+ return c.json({ success: false, error: `Archive extraction failed: ${archiveError.message}` }, 400);
281
+ }
282
+ }
283
+ else {
284
+ // No archive — build SKILL.md from JSON fields (existing behavior)
285
+ const frontmatter = {
286
+ name: skillId,
287
+ description: body.description,
288
+ };
289
+ if (body.license)
290
+ frontmatter.license = body.license;
291
+ if (body.compatibility)
292
+ frontmatter.compatibility = body.compatibility;
293
+ if (body.allowedTools)
294
+ frontmatter['allowed-tools'] = body.allowedTools;
295
+ if (body.metadata && Object.keys(body.metadata).length > 0) {
296
+ const meta = {};
297
+ for (const [key, value] of Object.entries(body.metadata)) {
298
+ if (value !== undefined && value !== null) {
299
+ meta[key] = value;
300
+ }
301
+ }
302
+ if (Object.keys(meta).length > 0) {
303
+ frontmatter.metadata = meta;
304
+ }
305
+ }
306
+ const fileContent = matter.stringify(finalContent, frontmatter);
307
+ await fs.writeFile(path.join(skillDir, 'SKILL.md'), fileContent, 'utf-8');
308
+ }
309
+ return c.json({
310
+ success: true,
311
+ document: {
312
+ id: skillId,
313
+ name: skillId,
314
+ description: body.description,
315
+ metadata: {
316
+ name: skillId,
317
+ description: body.description,
318
+ ...(body.metadata || {}),
319
+ },
320
+ content: finalContent
321
+ }
322
+ }, 201);
323
+ }
324
+ catch (error) {
325
+ console.error('Error creating skill document:', error);
326
+ return c.json({ success: false, error: 'Failed to create skill document' }, 500);
327
+ }
328
+ });
329
+ export default app;
@@ -0,0 +1,3 @@
1
+ import { Hono } from 'hono';
2
+ declare const slackRoutes: Hono<import("hono/types").BlankEnv, import("hono/types").BlankSchema, "/">;
3
+ export { slackRoutes };
@@ -0,0 +1,15 @@
1
+ import { Hono } from 'hono';
2
+ import { getConfig, updateConfig, testConnection, listChannels, sendTestNotification, sendExampleNotification } from './route.js';
3
+ const slackRoutes = new Hono();
4
+ // Configuration endpoints
5
+ slackRoutes.get('/config', getConfig);
6
+ slackRoutes.put('/config', updateConfig);
7
+ // Connection testing
8
+ slackRoutes.post('/test', testConnection);
9
+ // Channel listing
10
+ slackRoutes.get('/channels', listChannels);
11
+ // Test notification
12
+ slackRoutes.post('/notify', sendTestNotification);
13
+ // Example notification for specific type
14
+ slackRoutes.post('/notify/example', sendExampleNotification);
15
+ export { slackRoutes };
@@ -0,0 +1,124 @@
1
+ import { Context } from 'hono';
2
+ /**
3
+ * GET /api/v1/slack/config
4
+ * Returns the current Slack configuration (tokens masked)
5
+ */
6
+ export declare function getConfig(c: Context): Promise<(Response & import("hono").TypedResponse<{
7
+ success: true;
8
+ data: {
9
+ enabled: boolean;
10
+ notifications: {
11
+ proposals: {
12
+ created: boolean;
13
+ statusChange: boolean;
14
+ };
15
+ jobs: {
16
+ completed: boolean;
17
+ failed: boolean;
18
+ };
19
+ git: {
20
+ push: boolean;
21
+ merge: boolean;
22
+ };
23
+ };
24
+ channelId: string;
25
+ channelName: string;
26
+ siteUrl: string;
27
+ hasBotToken: boolean;
28
+ hasSigningSecret: boolean;
29
+ };
30
+ }, import("hono/utils/http-status").ContentfulStatusCode, "json">) | (Response & import("hono").TypedResponse<{
31
+ success: false;
32
+ error: any;
33
+ }, 500, "json">)>;
34
+ /**
35
+ * PUT /api/v1/slack/config
36
+ * Updates Slack configuration
37
+ */
38
+ export declare function updateConfig(c: Context): Promise<(Response & import("hono").TypedResponse<{
39
+ success: true;
40
+ data: {
41
+ enabled: boolean;
42
+ notifications: {
43
+ proposals: {
44
+ created: boolean;
45
+ statusChange: boolean;
46
+ };
47
+ jobs: {
48
+ completed: boolean;
49
+ failed: boolean;
50
+ };
51
+ git: {
52
+ push: boolean;
53
+ merge: boolean;
54
+ };
55
+ };
56
+ channelId: string;
57
+ channelName: string;
58
+ siteUrl: string;
59
+ hasBotToken: boolean;
60
+ hasSigningSecret: boolean;
61
+ };
62
+ }, import("hono/utils/http-status").ContentfulStatusCode, "json">) | (Response & import("hono").TypedResponse<{
63
+ success: false;
64
+ error: any;
65
+ }, 500, "json">)>;
66
+ /**
67
+ * POST /api/v1/slack/test
68
+ * Tests the Slack connection using the configured bot token
69
+ */
70
+ export declare function testConnection(c: Context): Promise<(Response & import("hono").TypedResponse<{
71
+ success: true;
72
+ message: string;
73
+ teamName: string;
74
+ }, import("hono/utils/http-status").ContentfulStatusCode, "json">) | (Response & import("hono").TypedResponse<{
75
+ success: false;
76
+ error: string;
77
+ }, 400, "json">) | (Response & import("hono").TypedResponse<{
78
+ success: false;
79
+ error: any;
80
+ }, 500, "json">)>;
81
+ /**
82
+ * GET /api/v1/slack/channels
83
+ * Lists available Slack channels the bot can post to
84
+ */
85
+ export declare function listChannels(c: Context): Promise<(Response & import("hono").TypedResponse<{
86
+ success: true;
87
+ data: {
88
+ id: string;
89
+ name: string;
90
+ isPrivate: boolean;
91
+ isMember: boolean;
92
+ }[];
93
+ }, import("hono/utils/http-status").ContentfulStatusCode, "json">) | (Response & import("hono").TypedResponse<{
94
+ success: false;
95
+ error: any;
96
+ }, 500, "json">)>;
97
+ /**
98
+ * POST /api/v1/slack/notify
99
+ * Sends a test notification to the configured channel
100
+ */
101
+ export declare function sendTestNotification(c: Context): Promise<(Response & import("hono").TypedResponse<{
102
+ success: true;
103
+ message: string;
104
+ }, import("hono/utils/http-status").ContentfulStatusCode, "json">) | (Response & import("hono").TypedResponse<{
105
+ success: false;
106
+ error: string;
107
+ }, 400, "json">) | (Response & import("hono").TypedResponse<{
108
+ success: false;
109
+ error: any;
110
+ }, 500, "json">)>;
111
+ /**
112
+ * POST /api/v1/slack/notify/example
113
+ * Sends an example notification for a specific notification type
114
+ */
115
+ export declare function sendExampleNotification(c: Context): Promise<(Response & import("hono").TypedResponse<{
116
+ success: false;
117
+ error: string;
118
+ }, 400, "json">) | (Response & import("hono").TypedResponse<{
119
+ success: true;
120
+ message: string;
121
+ }, import("hono/utils/http-status").ContentfulStatusCode, "json">) | (Response & import("hono").TypedResponse<{
122
+ success: false;
123
+ error: any;
124
+ }, 500, "json">)>;
@@ -0,0 +1,192 @@
1
+ import { getSlackService } from '../../../../lib/slack/slack-service.js';
2
+ const VALID_NOTIFICATION_TYPES = [
3
+ 'proposal.created',
4
+ 'proposal.statusChange',
5
+ 'job.completed',
6
+ 'job.failed',
7
+ 'git.push',
8
+ 'git.merge',
9
+ ];
10
+ /**
11
+ * GET /api/v1/slack/config
12
+ * Returns the current Slack configuration (tokens masked)
13
+ */
14
+ export async function getConfig(c) {
15
+ try {
16
+ const slackService = getSlackService();
17
+ const config = await slackService.getConfigForDisplay();
18
+ return c.json({
19
+ success: true,
20
+ data: config,
21
+ });
22
+ }
23
+ catch (error) {
24
+ console.error('[slack/config] GET error:', error);
25
+ return c.json({
26
+ success: false,
27
+ error: error.message || 'Failed to load Slack configuration',
28
+ }, 500);
29
+ }
30
+ }
31
+ /**
32
+ * PUT /api/v1/slack/config
33
+ * Updates Slack configuration
34
+ */
35
+ export async function updateConfig(c) {
36
+ try {
37
+ const body = await c.req.json();
38
+ const slackService = getSlackService();
39
+ // Build the update object, only including fields that were provided
40
+ const updates = {};
41
+ if (typeof body.enabled === 'boolean') {
42
+ updates.enabled = body.enabled;
43
+ }
44
+ if (typeof body.botToken === 'string') {
45
+ updates.botToken = body.botToken;
46
+ }
47
+ if (typeof body.signingSecret === 'string') {
48
+ updates.signingSecret = body.signingSecret;
49
+ }
50
+ if (typeof body.channelId === 'string') {
51
+ updates.channelId = body.channelId;
52
+ }
53
+ if (typeof body.channelName === 'string') {
54
+ updates.channelName = body.channelName;
55
+ }
56
+ if (typeof body.siteUrl === 'string') {
57
+ updates.siteUrl = body.siteUrl;
58
+ }
59
+ if (body.notifications && typeof body.notifications === 'object') {
60
+ updates.notifications = body.notifications;
61
+ }
62
+ const updated = await slackService.saveConfig(updates);
63
+ // Return the display version (tokens masked)
64
+ const displayConfig = await slackService.getConfigForDisplay();
65
+ return c.json({
66
+ success: true,
67
+ data: displayConfig,
68
+ });
69
+ }
70
+ catch (error) {
71
+ console.error('[slack/config] PUT error:', error);
72
+ return c.json({
73
+ success: false,
74
+ error: error.message || 'Failed to update Slack configuration',
75
+ }, 500);
76
+ }
77
+ }
78
+ /**
79
+ * POST /api/v1/slack/test
80
+ * Tests the Slack connection using the configured bot token
81
+ */
82
+ export async function testConnection(c) {
83
+ try {
84
+ const slackService = getSlackService();
85
+ const result = await slackService.testConnection();
86
+ if (result.success) {
87
+ return c.json({
88
+ success: true,
89
+ message: `Connected to workspace: ${result.teamName}`,
90
+ teamName: result.teamName,
91
+ });
92
+ }
93
+ else {
94
+ return c.json({
95
+ success: false,
96
+ error: result.error || 'Connection test failed',
97
+ }, 400);
98
+ }
99
+ }
100
+ catch (error) {
101
+ console.error('[slack/test] POST error:', error);
102
+ return c.json({
103
+ success: false,
104
+ error: error.message || 'Failed to test Slack connection',
105
+ }, 500);
106
+ }
107
+ }
108
+ /**
109
+ * GET /api/v1/slack/channels
110
+ * Lists available Slack channels the bot can post to
111
+ */
112
+ export async function listChannels(c) {
113
+ try {
114
+ const slackService = getSlackService();
115
+ const channels = await slackService.listChannels();
116
+ return c.json({
117
+ success: true,
118
+ data: channels,
119
+ });
120
+ }
121
+ catch (error) {
122
+ console.error('[slack/channels] GET error:', error);
123
+ return c.json({
124
+ success: false,
125
+ error: error.message || 'Failed to list Slack channels',
126
+ }, 500);
127
+ }
128
+ }
129
+ /**
130
+ * POST /api/v1/slack/notify
131
+ * Sends a test notification to the configured channel
132
+ */
133
+ export async function sendTestNotification(c) {
134
+ try {
135
+ const slackService = getSlackService();
136
+ // Send a test notification
137
+ const success = await slackService.sendNotification({
138
+ type: 'proposal.created',
139
+ proposalId: 'test-notification',
140
+ intent: 'Test notification from Coconut',
141
+ author: 'System',
142
+ });
143
+ if (success) {
144
+ return c.json({
145
+ success: true,
146
+ message: 'Test notification sent successfully',
147
+ });
148
+ }
149
+ else {
150
+ return c.json({
151
+ success: false,
152
+ error: 'Failed to send notification. Check that Slack is enabled and a channel is selected.',
153
+ }, 400);
154
+ }
155
+ }
156
+ catch (error) {
157
+ console.error('[slack/notify] POST error:', error);
158
+ return c.json({
159
+ success: false,
160
+ error: error.message || 'Failed to send test notification',
161
+ }, 500);
162
+ }
163
+ }
164
+ /**
165
+ * POST /api/v1/slack/notify/example
166
+ * Sends an example notification for a specific notification type
167
+ */
168
+ export async function sendExampleNotification(c) {
169
+ try {
170
+ const body = await c.req.json().catch(() => ({}));
171
+ const notificationType = body.type;
172
+ if (!notificationType || !VALID_NOTIFICATION_TYPES.includes(notificationType)) {
173
+ return c.json({
174
+ success: false,
175
+ error: `Invalid notification type. Must be one of: ${VALID_NOTIFICATION_TYPES.join(', ')}`,
176
+ }, 400);
177
+ }
178
+ const slackService = getSlackService();
179
+ await slackService.sendExampleNotification(notificationType);
180
+ return c.json({
181
+ success: true,
182
+ message: `Example ${notificationType} notification sent`,
183
+ });
184
+ }
185
+ catch (error) {
186
+ console.error('[slack/notify/example] POST error:', error);
187
+ return c.json({
188
+ success: false,
189
+ error: error.message || 'Failed to send example notification',
190
+ }, 500);
191
+ }
192
+ }