@lovelybunch/api 1.0.75-alpha.9 → 1.0.75

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 (163) hide show
  1. package/dist/lib/jobs/job-runner.js +10 -2
  2. package/dist/lib/jobs/job-scheduler.js +21 -0
  3. package/dist/lib/mail/mail-runner.d.ts +51 -0
  4. package/dist/lib/mail/mail-runner.js +342 -0
  5. package/dist/lib/slack/slack-service.d.ts +2 -0
  6. package/dist/lib/slack/slack-service.js +3 -0
  7. package/dist/lib/storage/file-storage.d.ts +16 -16
  8. package/dist/lib/storage/file-storage.js +59 -64
  9. package/dist/lib/terminal/terminal-manager.d.ts +3 -3
  10. package/dist/lib/terminal/terminal-manager.js +10 -10
  11. package/dist/routes/api/v1/ai/route.js +39 -19
  12. package/dist/routes/api/v1/git/index.js +23 -0
  13. package/dist/routes/api/v1/mail/index.d.ts +3 -0
  14. package/dist/routes/api/v1/mail/index.js +23 -0
  15. package/dist/routes/api/v1/mail/route.d.ts +294 -0
  16. package/dist/routes/api/v1/mail/route.js +344 -0
  17. package/dist/routes/api/v1/mcp/index.js +32 -32
  18. package/dist/routes/api/v1/slack/index.d.ts +3 -0
  19. package/dist/routes/api/v1/slack/index.js +15 -0
  20. package/dist/routes/api/v1/slack/route.d.ts +124 -0
  21. package/dist/routes/api/v1/slack/route.js +192 -0
  22. package/dist/routes/api/v1/tasks/[id]/route.d.ts +117 -0
  23. package/dist/routes/api/v1/tasks/[id]/route.js +166 -0
  24. package/dist/routes/api/v1/tasks/index.d.ts +3 -0
  25. package/dist/routes/api/v1/tasks/index.js +10 -0
  26. package/dist/routes/api/v1/tasks/route.d.ts +96 -0
  27. package/dist/routes/api/v1/tasks/route.js +136 -0
  28. package/dist/routes/api/v1/terminal/[taskId]/create/index.d.ts +3 -0
  29. package/dist/routes/api/v1/terminal/[taskId]/create/index.js +5 -0
  30. package/dist/routes/api/v1/terminal/[taskId]/create/route.d.ts +10 -0
  31. package/dist/routes/api/v1/terminal/[taskId]/create/route.js +27 -0
  32. package/dist/routes/api/v1/terminal/[taskId]/destroy/index.d.ts +3 -0
  33. package/dist/routes/api/v1/terminal/[taskId]/destroy/index.js +5 -0
  34. package/dist/routes/api/v1/terminal/[taskId]/destroy/route.d.ts +10 -0
  35. package/dist/routes/api/v1/terminal/[taskId]/destroy/route.js +21 -0
  36. package/dist/routes/api/v1/terminal/[taskId]/resize/index.d.ts +3 -0
  37. package/dist/routes/api/v1/terminal/[taskId]/resize/index.js +5 -0
  38. package/dist/routes/api/v1/terminal/[taskId]/resize/route.d.ts +10 -0
  39. package/dist/routes/api/v1/terminal/[taskId]/resize/route.js +21 -0
  40. package/dist/routes/api/v1/terminal/sessions/route.js +4 -4
  41. package/dist/server-with-static.js +12 -8
  42. package/dist/server.js +12 -8
  43. package/package.json +4 -4
  44. package/static/assets/{ActivityPage-OxRci_V2.js → ActivityPage-k4I7Q53O.js} +1 -1
  45. package/static/assets/ApiKeysSettingsPage-B1YvVdmg.js +2 -0
  46. package/static/assets/{ArchitectureEditPage-D7xcH6dY.js → ArchitectureEditPage-CpowsIx2.js} +4 -4
  47. package/static/assets/{ArchitecturePage-pvnlX-NW.js → ArchitecturePage-DYxC_aMR.js} +1 -1
  48. package/static/assets/{AuthSettingsPage-Bu0CZ1rY.js → AuthSettingsPage-DtSo78Y_.js} +2 -2
  49. package/static/assets/{CallbackPage-D0lkjxCT.js → CallbackPage-bROCGapx.js} +1 -1
  50. package/static/assets/CodePage-CPCj64rX.js +2 -0
  51. package/static/assets/{CollapsibleSection-Bt_ZLnJc.js → CollapsibleSection-M5cXbl92.js} +1 -1
  52. package/static/assets/DashboardPage-B9BZZfw6.js +51 -0
  53. package/static/assets/{GitPage-TrTxZ27J.js → GitPage-BiDtdSK1.js} +2 -2
  54. package/static/assets/GitSettingsPage-THm6wDjs.js +6 -0
  55. package/static/assets/IdentityPage-BC16skg6.js +6 -0
  56. package/static/assets/{ImplementationStepsEditor-Ctx0CvbU.js → ImplementationStepsEditor-HliLQav5.js} +2 -2
  57. package/static/assets/{IntegrationsSettingsPage-C2wJVdM7.js → IntegrationsSettingsPage-CC_VKIQa.js} +1 -1
  58. package/static/assets/JobDetailPage-z1QQYvmU.js +1 -0
  59. package/static/assets/{KnowledgeDetailPage-BdTUfWqj.js → KnowledgeDetailPage-DzHXBS7Q.js} +1 -1
  60. package/static/assets/{KnowledgeEditPage-D8XK4IUf.js → KnowledgeEditPage-BwGnUH_m.js} +1 -1
  61. package/static/assets/KnowledgePage-CGIVMS02.js +3 -0
  62. package/static/assets/{LoginPage-Dqxd7cTa.js → LoginPage-VQ3lcfLV.js} +1 -1
  63. package/static/assets/MailInboxPage-DiZKqwdU.js +1 -0
  64. package/static/assets/MailProcessingModal-DIeSQBoR.js +6 -0
  65. package/static/assets/MailReadPage-C8AACmZQ.js +1 -0
  66. package/static/assets/MailSentPage-C_5yFly_.js +1 -0
  67. package/static/assets/{McpSettingsPage-10n35zXi.js → McpSettingsPage-i9YHcu1s.js} +1 -1
  68. package/static/assets/{NewKnowledgePage-BlJzzuh7.js → NewKnowledgePage-BnVY7WUD.js} +1 -1
  69. package/static/assets/{NewSkillPage-ByqN--mH.js → NewSkillPage-DwniHD6D.js} +1 -1
  70. package/static/assets/NewTaskPage-F5UX2WMc.js +90 -0
  71. package/static/assets/NotFoundPage-BbSZX_4L.js +6 -0
  72. package/static/assets/NotificationsSettingsPage-C8kjcift.js +1 -0
  73. package/static/assets/{ProjectEditPage-DKJTY2uc.js → ProjectEditPage-DUUlIEqI.js} +1 -1
  74. package/static/assets/{ProjectPage-2VblKCWz.js → ProjectPage-Unz9PQpA.js} +1 -1
  75. package/static/assets/{PromptsSettingsPage-B4mOhXuo.js → PromptsSettingsPage-DVpIuRKI.js} +1 -1
  76. package/static/assets/ResourceDetailPage-DqHZ2KYD.js +1 -0
  77. package/static/assets/{ResourcesPage-2BbjIWfF.js → ResourcesPage-BP5tuAi-.js} +1 -1
  78. package/static/assets/RoleEditPage-BgKu8S0-.js +13 -0
  79. package/static/assets/{RolePage-qXWXZ2FZ.js → RolePage-Fed52Ov5.js} +1 -1
  80. package/static/assets/{RulesSettingsPage-BtM7p8F6.js → RulesSettingsPage-BQ2O0u66.js} +3 -3
  81. package/static/assets/SchedulePage-jkxjuzBx.js +4 -0
  82. package/static/assets/SkillDetailPage-k3Q2-NFd.js +1 -0
  83. package/static/assets/{SkillEditPage-Czlo8WWT.js → SkillEditPage-urF4snjo.js} +1 -1
  84. package/static/assets/SkillsPage-DlWDhEjR.js +8 -0
  85. package/static/assets/{SkillsSettingsPage-DKtpy7qk.js → SkillsSettingsPage-BViFgckG.js} +1 -1
  86. package/static/assets/{SourceInput-BITn1Y15.js → SourceInput-CAFKTHw-.js} +1 -1
  87. package/static/assets/{TagInput-BK91_M1N.js → TagInput-C6lI-ePr.js} +1 -1
  88. package/static/assets/TaskDetailPage-DpbRHnW_.js +16 -0
  89. package/static/assets/TaskEditPage-DssRbW0h.js +1 -0
  90. package/static/assets/TasksPage-CD_eo0Bj.js +17 -0
  91. package/static/assets/TerminalPage-BG_wlccr.js +1 -0
  92. package/static/assets/TerminalSessionPage-CsK-LznK.js +8 -0
  93. package/static/assets/{UserPreferencesPage-DrgYEcxO.js → UserPreferencesPage-CWUq3efu.js} +1 -1
  94. package/static/assets/UserSettingsPage-CduI_MGS.js +1 -0
  95. package/static/assets/{UtilitiesPage-Djr4qT5L.js → UtilitiesPage-BAxokhLh.js} +1 -1
  96. package/static/assets/{alert-CsMvyYoX.js → alert-BXsc6_qu.js} +1 -1
  97. package/static/assets/{arrow-down-BZnfbld8.js → arrow-down-DmW_3gE8.js} +1 -1
  98. package/static/assets/{arrow-left-WGBYWq3h.js → arrow-left-1S-835kP.js} +1 -1
  99. package/static/assets/{arrow-up-BByVUPE7.js → arrow-up-BYism_o1.js} +1 -1
  100. package/static/assets/arrow-up-down-Dw3J0a4i.js +6 -0
  101. package/static/assets/{badge-AwLOflf5.js → badge-BUEY53dV.js} +1 -1
  102. package/static/assets/{browser-modal-BzGNFfTG.js → browser-modal-DCNdI4NT.js} +2 -2
  103. package/static/assets/{card-SN5gKnu7.js → card-BcPlIAH5.js} +1 -1
  104. package/static/assets/{chevron-left-C7uNq9l_.js → chevron-left-FMmNe7yP.js} +1 -1
  105. package/static/assets/{chevron-up-CHdIiLxL.js → chevron-up-CqM3won3.js} +1 -1
  106. package/static/assets/{chevrons-up-TXwQuoUN.js → chevrons-up-DTvCkIHc.js} +1 -1
  107. package/static/assets/{circle-alert-37E5gU9K.js → circle-alert-dseM-Ib7.js} +1 -1
  108. package/static/assets/{circle-check-big-nY4PntB5.js → circle-check-big-jKg34xC-.js} +1 -1
  109. package/static/assets/{circle-check-D02pWDME.js → circle-check-eyo6pBP1.js} +1 -1
  110. package/static/assets/{circle-play-7EXFLo4F.js → circle-play-BrY_lNiH.js} +1 -1
  111. package/static/assets/{circle-x-By4JoTHB.js → circle-x-uqmzEce1.js} +1 -1
  112. package/static/assets/{clipboard-BdymjxLO.js → clipboard-tzPFoieb.js} +1 -1
  113. package/static/assets/{clock-HDu44KTo.js → clock-Bjc06QBM.js} +1 -1
  114. package/static/assets/code-DrYqPukx.js +6 -0
  115. package/static/assets/{download-Cv2G2Eg9.js → download-Bg__QCLT.js} +1 -1
  116. package/static/assets/{external-link-DwMXcCCj.js → external-link-CNDy2UUo.js} +1 -1
  117. package/static/assets/{eye-DYnjJzdb.js → eye-DLFBnC8t.js} +1 -1
  118. package/static/assets/{folder-git-2-COeWFPHS.js → folder-git-2-DUqd0WRi.js} +1 -1
  119. package/static/assets/index-CHdBxVyk.css +2 -0
  120. package/static/assets/{index-9Tv-j_Ga.js → index-DFcWlnzl.js} +118 -103
  121. package/static/assets/{info-BmtuPMhv.js → info-D6jxZC5X.js} +1 -1
  122. package/static/assets/kiro-CX1mOsRO.js +17 -0
  123. package/static/assets/{label-TGqbNfMO.js → label-DBuh-ke5.js} +1 -1
  124. package/static/assets/{markdown-editor-ls1JPK_e.js → markdown-editor-B4YNQFT2.js} +1 -1
  125. package/static/assets/message-square-B5RWz_ff.js +6 -0
  126. package/static/assets/paperclip-4A_3MaPx.js +6 -0
  127. package/static/assets/{pause-CAWbvTiL.js → pause-BzhKXHtR.js} +1 -1
  128. package/static/assets/{play-DF_Qeu0H.js → play-CHIf-Rcz.js} +1 -1
  129. package/static/assets/{radio-group-DYTbywtK.js → radio-group-C1ct-VsJ.js} +1 -1
  130. package/static/assets/{refresh-cw-BFZxHqbC.js → refresh-cw-B3OwrDUf.js} +1 -1
  131. package/static/assets/{search-Dr90tbch.js → search-Cq1ksEdp.js} +1 -1
  132. package/static/assets/{select-Cs5qtMYV.js → select-44mcS2_G.js} +1 -1
  133. package/static/assets/{status-utils-BDOyevaX.js → status-utils-CDkPeVfP.js} +1 -1
  134. package/static/assets/{switch-4TDb6YiQ.js → switch-CIwjYvCt.js} +1 -1
  135. package/static/assets/{tabs-BrbEvF4V.js → tabs-DTV6Su-h.js} +1 -1
  136. package/static/assets/{tag-DrQkepeD.js → tag-p6yeowCW.js} +1 -1
  137. package/static/assets/{terminal-preview-uuKF9_x4.js → terminal-preview-DN38x9Jm.js} +1 -1
  138. package/static/assets/use-terminal-BXJqOeJe.js +1 -0
  139. package/static/assets/{video-DYA2WfbA.js → video-BH5ChaoS.js} +1 -1
  140. package/static/index.html +2 -2
  141. package/static/assets/ApiKeysSettingsPage-C0evI19e.js +0 -2
  142. package/static/assets/CodePage-BJ4PC5nb.js +0 -2
  143. package/static/assets/DashboardPage-BiffPdmj.js +0 -41
  144. package/static/assets/GitSettingsPage-D7q5xQd_.js +0 -6
  145. package/static/assets/IdentityPage-CY0Ak2j0.js +0 -11
  146. package/static/assets/JobDetailPage-Phx_IlKX.js +0 -1
  147. package/static/assets/KnowledgePage-Ci9G7Br-.js +0 -8
  148. package/static/assets/NewProposalPage-BP7Ttoxk.js +0 -90
  149. package/static/assets/ProposalDetailPage-m3ysyzpj.js +0 -1
  150. package/static/assets/ProposalEditPage-3XVg_paW.js +0 -1
  151. package/static/assets/ProposalsPage-B3u0aFFz.js +0 -17
  152. package/static/assets/ResourceDetailPage-somBLUpC.js +0 -1
  153. package/static/assets/RoleEditPage-CLzX7Xhi.js +0 -13
  154. package/static/assets/SchedulePage-4tFcIBSs.js +0 -4
  155. package/static/assets/SkillDetailPage-CroSdaju.js +0 -1
  156. package/static/assets/SkillsPage-CgULbcI-.js +0 -8
  157. package/static/assets/TerminalPage-8fwvnOo2.js +0 -1
  158. package/static/assets/TerminalSessionPage-BhO5U48p.js +0 -13
  159. package/static/assets/UserSettingsPage-Dj6lKLi8.js +0 -1
  160. package/static/assets/droid-CPteN3f9.js +0 -17
  161. package/static/assets/index-GFQ5RqVh.css +0 -2
  162. package/static/assets/use-terminal-BG5UXuVE.js +0 -1
  163. package/static/assets/zap-h9QOsasv.js +0 -6
@@ -2,8 +2,8 @@ import { Hono } from 'hono';
2
2
  import { promises as fs } from 'fs';
3
3
  import path from 'path';
4
4
  import { ZodError } from 'zod';
5
- import { listProposals, getProposal, createProposal, updateProposal, deleteProposal, getContext, updateContext, appendContext, replaceContextSection, listKnowledge, getKnowledge, createKnowledge, updateKnowledge, listEvents, } from '@lovelybunch/core';
6
- import { proposalsFullTool, knowledgeTool, normalizeKnowledgeMetadata, eventsTool, projectContextTool, architectureContextTool, roleContextTool, resourcesTool } from '@lovelybunch/mcp';
5
+ import { listTasks, getTask, createTask, updateTask, deleteTask, getContext, updateContext, appendContext, replaceContextSection, listKnowledge, getKnowledge, createKnowledge, updateKnowledge, listEvents, } from '@lovelybunch/core';
6
+ import { tasksFullTool, knowledgeTool, normalizeKnowledgeMetadata, eventsTool, projectContextTool, architectureContextTool, roleContextTool, resourcesTool } from '@lovelybunch/mcp';
7
7
  import { FileStorageAdapter } from '../../../../lib/storage/file-storage.js';
8
8
  const app = new Hono();
9
9
  const storage = new FileStorageAdapter();
@@ -78,9 +78,9 @@ app.get('/', async (c) => {
78
78
  }
79
79
  const names = Object.keys(externalServers);
80
80
  // Add built-in tools (include full JSON schema for parameters)
81
- // Note: proposals now supports full CRUD, knowledge/project/architecture are read+write, events is read-only
81
+ // Note: tasks now supports full CRUD, knowledge/project/architecture are read+write, events is read-only
82
82
  const builtInTools = {
83
- change_proposals: proposalsFullTool,
83
+ tasks: tasksFullTool,
84
84
  knowledge_documents: knowledgeTool,
85
85
  activity_events: eventsTool,
86
86
  project_context: projectContextTool,
@@ -106,10 +106,10 @@ app.get('/', async (c) => {
106
106
  */
107
107
  app.get('/schema', async (c) => {
108
108
  try {
109
- // Note: proposals now supports full CRUD, knowledge/project/architecture are read+write, events is read-only
109
+ // Note: tasks now supports full CRUD, knowledge/project/architecture are read+write, events is read-only
110
110
  const schema = {
111
111
  tools: {
112
- change_proposals: proposalsFullTool,
112
+ tasks: tasksFullTool,
113
113
  knowledge_documents: knowledgeTool,
114
114
  activity_events: eventsTool,
115
115
  project_context: projectContextTool,
@@ -135,8 +135,8 @@ app.post('/execute', async (c) => {
135
135
  if (!tool || !args) {
136
136
  return c.json({ success: false, error: 'Tool and arguments are required' }, 400);
137
137
  }
138
- if (tool === 'change_proposals') {
139
- return await executeProposalsTool(c, args);
138
+ if (tool === 'tasks') {
139
+ return await executeTasksTool(c, args);
140
140
  }
141
141
  if (tool === 'knowledge_documents') {
142
142
  return await executeKnowledgeTool(c, args);
@@ -163,71 +163,71 @@ app.post('/execute', async (c) => {
163
163
  return c.json({ success: false, error: 'Tool execution failed' }, 500);
164
164
  }
165
165
  });
166
- // Proposals tool - full CRUD operations using @lovelybunch/core
167
- async function executeProposalsTool(c, args) {
168
- const { operation, id, filters, proposal, updates } = args;
166
+ // Tasks tool - full CRUD operations using @lovelybunch/core
167
+ async function executeTasksTool(c, args) {
168
+ const { operation, id, filters, task, updates } = args;
169
169
  try {
170
170
  switch (operation) {
171
171
  case 'list': {
172
- const proposals = await listProposals(filters || {});
172
+ const tasks = await listTasks(filters || {});
173
173
  return c.json({
174
174
  success: true,
175
- data: proposals,
176
- count: proposals.length,
177
- message: `Found ${proposals.length} proposals`
175
+ data: tasks,
176
+ count: tasks.length,
177
+ message: `Found ${tasks.length} tasks`
178
178
  });
179
179
  }
180
180
  case 'get': {
181
181
  if (!id) {
182
- return c.json({ success: false, error: 'Proposal ID is required for get operation' }, 400);
182
+ return c.json({ success: false, error: 'Task ID is required for get operation' }, 400);
183
183
  }
184
- const result = await getProposal(id);
184
+ const result = await getTask(id);
185
185
  if (!result) {
186
- return c.json({ success: false, error: 'Proposal not found' }, 404);
186
+ return c.json({ success: false, error: 'Task not found' }, 404);
187
187
  }
188
188
  return c.json({
189
189
  success: true,
190
190
  data: result,
191
- message: `Retrieved proposal ${id}`
191
+ message: `Retrieved task ${id}`
192
192
  });
193
193
  }
194
194
  case 'create': {
195
- if (!proposal) {
196
- return c.json({ success: false, error: 'Proposal data is required for create operation' }, 400);
195
+ if (!task) {
196
+ return c.json({ success: false, error: 'Task data is required for create operation' }, 400);
197
197
  }
198
- const created = await createProposal(proposal);
198
+ const created = await createTask(task);
199
199
  return c.json({
200
200
  success: true,
201
201
  data: created,
202
- message: `Created proposal ${created.id}`
202
+ message: `Created task ${created.id}`
203
203
  }, 201);
204
204
  }
205
205
  case 'update': {
206
206
  if (!id) {
207
- return c.json({ success: false, error: 'Proposal ID is required for update operation' }, 400);
207
+ return c.json({ success: false, error: 'Task ID is required for update operation' }, 400);
208
208
  }
209
- const updateData = updates || proposal;
209
+ const updateData = updates || task;
210
210
  if (!updateData) {
211
211
  return c.json({ success: false, error: 'Update data is required for update operation' }, 400);
212
212
  }
213
- const updated = await updateProposal(id, updateData);
213
+ const updated = await updateTask(id, updateData);
214
214
  return c.json({
215
215
  success: true,
216
216
  data: updated,
217
- message: `Updated proposal ${id}`
217
+ message: `Updated task ${id}`
218
218
  });
219
219
  }
220
220
  case 'delete': {
221
221
  if (!id) {
222
- return c.json({ success: false, error: 'Proposal ID is required for delete operation' }, 400);
222
+ return c.json({ success: false, error: 'Task ID is required for delete operation' }, 400);
223
223
  }
224
- const deleted = await deleteProposal(id);
224
+ const deleted = await deleteTask(id);
225
225
  if (!deleted) {
226
- return c.json({ success: false, error: 'Proposal not found' }, 404);
226
+ return c.json({ success: false, error: 'Task not found' }, 404);
227
227
  }
228
228
  return c.json({
229
229
  success: true,
230
- message: `Deleted proposal ${id}`
230
+ message: `Deleted task ${id}`
231
231
  });
232
232
  }
233
233
  default:
@@ -249,7 +249,7 @@ async function executeProposalsTool(c, args) {
249
249
  }))
250
250
  }, 400);
251
251
  }
252
- console.error('Error executing proposals tool:', error);
252
+ console.error('Error executing tasks tool:', error);
253
253
  return c.json({ success: false, error: error.message || 'Tool execution failed' }, 500);
254
254
  }
255
255
  }
@@ -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
+ channelId: string;
11
+ channelName: string;
12
+ siteUrl: string;
13
+ notifications: {
14
+ proposals: {
15
+ created: boolean;
16
+ statusChange: boolean;
17
+ };
18
+ jobs: {
19
+ completed: boolean;
20
+ failed: boolean;
21
+ };
22
+ git: {
23
+ push: boolean;
24
+ merge: boolean;
25
+ };
26
+ };
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
+ channelId: string;
43
+ channelName: string;
44
+ siteUrl: string;
45
+ notifications: {
46
+ proposals: {
47
+ created: boolean;
48
+ statusChange: boolean;
49
+ };
50
+ jobs: {
51
+ completed: boolean;
52
+ failed: boolean;
53
+ };
54
+ git: {
55
+ push: boolean;
56
+ merge: boolean;
57
+ };
58
+ };
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
+ }
@@ -0,0 +1,117 @@
1
+ import { Context } from 'hono';
2
+ export declare function GET(c: Context): Promise<(Response & import("hono").TypedResponse<{
3
+ success: false;
4
+ error: {
5
+ code: string;
6
+ message: string;
7
+ };
8
+ }, 404, "json">) | (Response & import("hono").TypedResponse<{
9
+ success: true;
10
+ data: {
11
+ id: string;
12
+ title: string;
13
+ intent?: string;
14
+ content?: string;
15
+ author: {
16
+ type: import("@lovelybunch/core").AuthorType;
17
+ id: string;
18
+ name: string;
19
+ email?: string;
20
+ };
21
+ productSpecRef?: string;
22
+ planSteps: {
23
+ id: string;
24
+ description: string;
25
+ command?: string;
26
+ expectedOutcome?: string;
27
+ status: "pending" | "in-progress" | "completed" | "failed";
28
+ output?: string;
29
+ error?: string;
30
+ executedAt?: string;
31
+ }[];
32
+ status: import("@lovelybunch/core").TaskStatus;
33
+ comments?: {
34
+ id: string;
35
+ author: string;
36
+ content: string;
37
+ createdAt: string;
38
+ }[];
39
+ metadata: {
40
+ createdAt: string;
41
+ updatedAt: string;
42
+ reviewers: string[];
43
+ tags?: string[];
44
+ priority?: "low" | "medium" | "high" | "critical";
45
+ readiness?: number;
46
+ };
47
+ };
48
+ }, import("hono/utils/http-status").ContentfulStatusCode, "json">) | (Response & import("hono").TypedResponse<{
49
+ success: false;
50
+ error: {
51
+ code: string;
52
+ message: any;
53
+ };
54
+ }, 500, "json">)>;
55
+ export declare function PATCH(c: Context): Promise<(Response & import("hono").TypedResponse<{
56
+ success: true;
57
+ data: {
58
+ id: string;
59
+ title: string;
60
+ intent?: string;
61
+ content?: string;
62
+ author: {
63
+ type: import("@lovelybunch/core").AuthorType;
64
+ id: string;
65
+ name: string;
66
+ email?: string;
67
+ };
68
+ productSpecRef?: string;
69
+ planSteps: {
70
+ id: string;
71
+ description: string;
72
+ command?: string;
73
+ expectedOutcome?: string;
74
+ status: "pending" | "in-progress" | "completed" | "failed";
75
+ output?: string;
76
+ error?: string;
77
+ executedAt?: string;
78
+ }[];
79
+ status: import("@lovelybunch/core").TaskStatus;
80
+ comments?: {
81
+ id: string;
82
+ author: string;
83
+ content: string;
84
+ createdAt: string;
85
+ }[];
86
+ metadata: {
87
+ createdAt: string;
88
+ updatedAt: string;
89
+ reviewers: string[];
90
+ tags?: string[];
91
+ priority?: "low" | "medium" | "high" | "critical";
92
+ readiness?: number;
93
+ };
94
+ };
95
+ }, import("hono/utils/http-status").ContentfulStatusCode, "json">) | (Response & import("hono").TypedResponse<{
96
+ success: false;
97
+ error: {
98
+ code: string;
99
+ message: any;
100
+ };
101
+ }, 404, "json">) | (Response & import("hono").TypedResponse<{
102
+ success: false;
103
+ error: {
104
+ code: string;
105
+ message: any;
106
+ };
107
+ }, 500, "json">)>;
108
+ export declare function DELETE(c: Context): Promise<(Response & import("hono").TypedResponse<{
109
+ success: true;
110
+ message: string;
111
+ }, import("hono/utils/http-status").ContentfulStatusCode, "json">) | (Response & import("hono").TypedResponse<{
112
+ success: false;
113
+ error: {
114
+ code: string;
115
+ message: any;
116
+ };
117
+ }, 500, "json">)>;