@lovelybunch/api 1.0.75-alpha.8 → 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 (188) 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 -5
  10. package/dist/lib/terminal/terminal-manager.js +10 -61
  11. package/dist/routes/api/v1/ai/route.js +361 -20
  12. package/dist/routes/api/v1/chats/[id]/index.js +2 -1
  13. package/dist/routes/api/v1/chats/[id]/route.d.ts +7 -0
  14. package/dist/routes/api/v1/chats/[id]/route.js +30 -1
  15. package/dist/routes/api/v1/context/index.js +0 -2
  16. package/dist/routes/api/v1/git/index.js +23 -0
  17. package/dist/routes/api/v1/knowledge/[filename]/index.d.ts +1 -0
  18. package/dist/routes/api/v1/knowledge/[filename]/index.js +1 -0
  19. package/dist/routes/api/v1/knowledge/[filename]/route.d.ts +3 -0
  20. package/dist/routes/api/v1/knowledge/[filename]/route.js +254 -0
  21. package/dist/routes/api/v1/knowledge/index.d.ts +1 -0
  22. package/dist/routes/api/v1/knowledge/index.js +1 -0
  23. package/dist/routes/api/v1/knowledge/route.d.ts +3 -0
  24. package/dist/routes/api/v1/knowledge/route.js +176 -0
  25. package/dist/routes/api/v1/mail/index.d.ts +3 -0
  26. package/dist/routes/api/v1/mail/index.js +23 -0
  27. package/dist/routes/api/v1/mail/route.d.ts +294 -0
  28. package/dist/routes/api/v1/mail/route.js +344 -0
  29. package/dist/routes/api/v1/mcp/index.js +109 -34
  30. package/dist/routes/api/v1/slack/index.d.ts +3 -0
  31. package/dist/routes/api/v1/slack/index.js +15 -0
  32. package/dist/routes/api/v1/slack/route.d.ts +124 -0
  33. package/dist/routes/api/v1/slack/route.js +192 -0
  34. package/dist/routes/api/v1/tasks/[id]/route.d.ts +117 -0
  35. package/dist/routes/api/v1/tasks/[id]/route.js +166 -0
  36. package/dist/routes/api/v1/tasks/index.d.ts +3 -0
  37. package/dist/routes/api/v1/tasks/index.js +10 -0
  38. package/dist/routes/api/v1/tasks/route.d.ts +96 -0
  39. package/dist/routes/api/v1/tasks/route.js +136 -0
  40. package/dist/routes/api/v1/terminal/[proposalId]/create/route.js +2 -2
  41. package/dist/routes/api/v1/terminal/[taskId]/create/index.d.ts +3 -0
  42. package/dist/routes/api/v1/terminal/[taskId]/create/index.js +5 -0
  43. package/dist/routes/api/v1/terminal/[taskId]/create/route.d.ts +10 -0
  44. package/dist/routes/api/v1/terminal/[taskId]/create/route.js +27 -0
  45. package/dist/routes/api/v1/terminal/[taskId]/destroy/index.d.ts +3 -0
  46. package/dist/routes/api/v1/terminal/[taskId]/destroy/index.js +5 -0
  47. package/dist/routes/api/v1/terminal/[taskId]/destroy/route.d.ts +10 -0
  48. package/dist/routes/api/v1/terminal/[taskId]/destroy/route.js +21 -0
  49. package/dist/routes/api/v1/terminal/[taskId]/resize/index.d.ts +3 -0
  50. package/dist/routes/api/v1/terminal/[taskId]/resize/index.js +5 -0
  51. package/dist/routes/api/v1/terminal/[taskId]/resize/route.d.ts +10 -0
  52. package/dist/routes/api/v1/terminal/[taskId]/resize/route.js +21 -0
  53. package/dist/routes/api/v1/terminal/sessions/route.js +4 -4
  54. package/dist/server-with-static.js +14 -8
  55. package/dist/server.js +14 -8
  56. package/package.json +4 -4
  57. package/static/assets/{ActivityPage-DSSML9J-.js → ActivityPage-k4I7Q53O.js} +1 -1
  58. package/static/assets/ApiKeysSettingsPage-B1YvVdmg.js +2 -0
  59. package/static/assets/{ArchitectureEditPage-CIjqkpMz.js → ArchitectureEditPage-CpowsIx2.js} +1 -1
  60. package/static/assets/{ArchitecturePage-Db__w054.js → ArchitecturePage-DYxC_aMR.js} +1 -1
  61. package/static/assets/{AuthSettingsPage-Bpooi8Z0.js → AuthSettingsPage-DtSo78Y_.js} +2 -2
  62. package/static/assets/{CallbackPage-BGLKeyjv.js → CallbackPage-bROCGapx.js} +1 -1
  63. package/static/assets/CodePage-CPCj64rX.js +2 -0
  64. package/static/assets/{CollapsibleSection-B6RO5o5R.js → CollapsibleSection-M5cXbl92.js} +1 -1
  65. package/static/assets/DashboardPage-B9BZZfw6.js +51 -0
  66. package/static/assets/{GitPage-DxjLaRWe.js → GitPage-BiDtdSK1.js} +2 -2
  67. package/static/assets/GitSettingsPage-THm6wDjs.js +6 -0
  68. package/static/assets/IdentityPage-BC16skg6.js +6 -0
  69. package/static/assets/{ImplementationStepsEditor-DWjDyZzP.js → ImplementationStepsEditor-HliLQav5.js} +2 -2
  70. package/static/assets/IntegrationsSettingsPage-CC_VKIQa.js +1 -0
  71. package/static/assets/JobDetailPage-z1QQYvmU.js +1 -0
  72. package/static/assets/KnowledgeDetailPage-DzHXBS7Q.js +1 -0
  73. package/static/assets/KnowledgeEditPage-BwGnUH_m.js +1 -0
  74. package/static/assets/KnowledgePage-CGIVMS02.js +3 -0
  75. package/static/assets/{LoginPage-DptfKsWo.js → LoginPage-VQ3lcfLV.js} +1 -1
  76. package/static/assets/MailInboxPage-DiZKqwdU.js +1 -0
  77. package/static/assets/MailProcessingModal-DIeSQBoR.js +6 -0
  78. package/static/assets/MailReadPage-C8AACmZQ.js +1 -0
  79. package/static/assets/MailSentPage-C_5yFly_.js +1 -0
  80. package/static/assets/McpSettingsPage-i9YHcu1s.js +1 -0
  81. package/static/assets/NewKnowledgePage-BnVY7WUD.js +9 -0
  82. package/static/assets/{NewSkillPage-Cwy2MSr9.js → NewSkillPage-DwniHD6D.js} +1 -1
  83. package/static/assets/NewTaskPage-F5UX2WMc.js +90 -0
  84. package/static/assets/NotFoundPage-BbSZX_4L.js +6 -0
  85. package/static/assets/NotificationsSettingsPage-C8kjcift.js +1 -0
  86. package/static/assets/ProjectEditPage-DUUlIEqI.js +11 -0
  87. package/static/assets/{ProjectPage-DgUr4bVU.js → ProjectPage-Unz9PQpA.js} +1 -1
  88. package/static/assets/PromptsSettingsPage-DVpIuRKI.js +1 -0
  89. package/static/assets/ResourceDetailPage-DqHZ2KYD.js +1 -0
  90. package/static/assets/ResourcesPage-BP5tuAi-.js +41 -0
  91. package/static/assets/RoleEditPage-BgKu8S0-.js +13 -0
  92. package/static/assets/{RolePage-Sc-GFiL2.js → RolePage-Fed52Ov5.js} +1 -1
  93. package/static/assets/{RulesSettingsPage-DdMCzh9j.js → RulesSettingsPage-BQ2O0u66.js} +2 -2
  94. package/static/assets/SchedulePage-jkxjuzBx.js +4 -0
  95. package/static/assets/SkillDetailPage-k3Q2-NFd.js +1 -0
  96. package/static/assets/{SkillEditPage-BDd2CtAS.js → SkillEditPage-urF4snjo.js} +1 -1
  97. package/static/assets/SkillsPage-DlWDhEjR.js +8 -0
  98. package/static/assets/{SkillsSettingsPage-1N0JQOYc.js → SkillsSettingsPage-BViFgckG.js} +1 -1
  99. package/static/assets/SourceInput-CAFKTHw-.js +1 -0
  100. package/static/assets/{TagInput-D_SdcypZ.js → TagInput-C6lI-ePr.js} +1 -1
  101. package/static/assets/TaskDetailPage-DpbRHnW_.js +16 -0
  102. package/static/assets/TaskEditPage-DssRbW0h.js +1 -0
  103. package/static/assets/TasksPage-CD_eo0Bj.js +17 -0
  104. package/static/assets/TerminalPage-BG_wlccr.js +1 -0
  105. package/static/assets/TerminalSessionPage-CsK-LznK.js +8 -0
  106. package/static/assets/UserPreferencesPage-CWUq3efu.js +1 -0
  107. package/static/assets/UserSettingsPage-CduI_MGS.js +1 -0
  108. package/static/assets/UtilitiesPage-BAxokhLh.js +1 -0
  109. package/static/assets/{alert-BD5jo3SI.js → alert-BXsc6_qu.js} +1 -1
  110. package/static/assets/{arrow-down-BxcoVp6S.js → arrow-down-DmW_3gE8.js} +1 -1
  111. package/static/assets/{arrow-left-CdM_IPng.js → arrow-left-1S-835kP.js} +1 -1
  112. package/static/assets/{arrow-up-BOJ6ob9X.js → arrow-up-BYism_o1.js} +1 -1
  113. package/static/assets/arrow-up-down-Dw3J0a4i.js +6 -0
  114. package/static/assets/{badge-DEiQk9C9.js → badge-BUEY53dV.js} +1 -1
  115. package/static/assets/{browser-modal-Dp1eMxt6.js → browser-modal-DCNdI4NT.js} +2 -2
  116. package/static/assets/{card-BCFxXzRk.js → card-BcPlIAH5.js} +1 -1
  117. package/static/assets/{chevron-left-C25izNzZ.js → chevron-left-FMmNe7yP.js} +1 -1
  118. package/static/assets/{plus-iamYJu5V.js → chevron-up-CqM3won3.js} +2 -2
  119. package/static/assets/{chevrons-up-DqbWMOjv.js → chevrons-up-DTvCkIHc.js} +1 -1
  120. package/static/assets/{circle-alert-CMRMPnbY.js → circle-alert-dseM-Ib7.js} +1 -1
  121. package/static/assets/{circle-check-big-NI18oHuP.js → circle-check-big-jKg34xC-.js} +1 -1
  122. package/static/assets/{circle-check-D5wZZPvj.js → circle-check-eyo6pBP1.js} +1 -1
  123. package/static/assets/{circle-play-BhVU869u.js → circle-play-BrY_lNiH.js} +1 -1
  124. package/static/assets/{circle-x-BXDB-G_q.js → circle-x-uqmzEce1.js} +1 -1
  125. package/static/assets/{clipboard-DC2xmNVx.js → clipboard-tzPFoieb.js} +1 -1
  126. package/static/assets/{clock-CeCp7Pz1.js → clock-Bjc06QBM.js} +1 -1
  127. package/static/assets/code-DrYqPukx.js +6 -0
  128. package/static/assets/{download-ZF_XbTIA.js → download-Bg__QCLT.js} +1 -1
  129. package/static/assets/{external-link-CYBz87-P.js → external-link-CNDy2UUo.js} +1 -1
  130. package/static/assets/{eye-BT8MAvKY.js → eye-DLFBnC8t.js} +1 -1
  131. package/static/assets/{folder-git-2-BE9AIPnj.js → folder-git-2-DUqd0WRi.js} +1 -1
  132. package/static/assets/index-CHdBxVyk.css +2 -0
  133. package/static/assets/index-DFcWlnzl.js +487 -0
  134. package/static/assets/{info-DunFSp-x.js → info-D6jxZC5X.js} +1 -1
  135. package/static/assets/kiro-CX1mOsRO.js +17 -0
  136. package/static/assets/{label-vYhfrPMD.js → label-DBuh-ke5.js} +1 -1
  137. package/static/assets/{markdown-editor-BzZ8tCto.js → markdown-editor-B4YNQFT2.js} +1 -1
  138. package/static/assets/message-square-B5RWz_ff.js +6 -0
  139. package/static/assets/paperclip-4A_3MaPx.js +6 -0
  140. package/static/assets/{pause-BHonpdnw.js → pause-BzhKXHtR.js} +1 -1
  141. package/static/assets/{play-CCo7tau2.js → play-CHIf-Rcz.js} +1 -1
  142. package/static/assets/{radio-group-Db-pBuyW.js → radio-group-C1ct-VsJ.js} +1 -1
  143. package/static/assets/{refresh-cw-Bg7vQzOw.js → refresh-cw-B3OwrDUf.js} +1 -1
  144. package/static/assets/{search-CH2zaibZ.js → search-Cq1ksEdp.js} +1 -1
  145. package/static/assets/select-44mcS2_G.js +1 -0
  146. package/static/assets/{status-utils-BDOyevaX.js → status-utils-CDkPeVfP.js} +1 -1
  147. package/static/assets/{switch-CH-VOgPo.js → switch-CIwjYvCt.js} +1 -1
  148. package/static/assets/{tabs-XeRAjZYR.js → tabs-DTV6Su-h.js} +1 -1
  149. package/static/assets/{tag-CRP5nL5-.js → tag-p6yeowCW.js} +1 -1
  150. package/static/assets/{terminal-preview-DMJMuORo.js → terminal-preview-DN38x9Jm.js} +1 -1
  151. package/static/assets/use-terminal-BXJqOeJe.js +1 -0
  152. package/static/assets/video-BH5ChaoS.js +36 -0
  153. package/static/index.html +2 -2
  154. package/static/assets/ApiKeysSettingsPage-Chw9PNL5.js +0 -2
  155. package/static/assets/CodePage-CrokcH-S.js +0 -2
  156. package/static/assets/DashboardPage-BaSQQ8Nv.js +0 -41
  157. package/static/assets/GitSettingsPage-tKBXYAFm.js +0 -6
  158. package/static/assets/IdentityPage-D2yBjeYn.js +0 -11
  159. package/static/assets/IntegrationsSettingsPage-Bx8-0Ig4.js +0 -1
  160. package/static/assets/JobDetailPage-BQmTHled.js +0 -1
  161. package/static/assets/KnowledgeDetailPage-QMU2bC3L.js +0 -1
  162. package/static/assets/KnowledgeEditPage-DbMJVcLc.js +0 -1
  163. package/static/assets/KnowledgePage-aU1GxZSZ.js +0 -8
  164. package/static/assets/McpSettingsPage-C3WxFwRB.js +0 -1
  165. package/static/assets/NewKnowledgePage-Cbiswrw_.js +0 -9
  166. package/static/assets/NewProposalPage-B_sDMBTK.js +0 -90
  167. package/static/assets/ProjectEditPage-BznWiBBc.js +0 -11
  168. package/static/assets/PromptsSettingsPage-CY0-870a.js +0 -1
  169. package/static/assets/ProposalDetailPage-K4iMXHEg.js +0 -1
  170. package/static/assets/ProposalEditPage-jZOtCMqP.js +0 -1
  171. package/static/assets/ProposalsPage-C7n4-G05.js +0 -17
  172. package/static/assets/ResourcesPage-vB5-XkUv.js +0 -71
  173. package/static/assets/RoleEditPage-Cu7ZB3yj.js +0 -13
  174. package/static/assets/SchedulePage-Bkkf2wA0.js +0 -4
  175. package/static/assets/SkillDetailPage-5sDxf3Of.js +0 -1
  176. package/static/assets/SkillsPage-D2G7EfK8.js +0 -8
  177. package/static/assets/SourceInput-DlC0zwva.js +0 -1
  178. package/static/assets/TerminalPage--KZ7azvP.js +0 -1
  179. package/static/assets/TerminalSessionPage-ClvxK9ia.js +0 -13
  180. package/static/assets/UserPreferencesPage-CheOH7jZ.js +0 -1
  181. package/static/assets/UserSettingsPage-C8STDvfQ.js +0 -1
  182. package/static/assets/UtilitiesPage-9rTxR2md.js +0 -1
  183. package/static/assets/calendar-Cx5r9R7A.js +0 -6
  184. package/static/assets/droid-DqWsM2dp.js +0 -17
  185. package/static/assets/index-DVTgTsDa.css +0 -2
  186. package/static/assets/index-hqVgTgRB.js +0 -462
  187. package/static/assets/use-terminal-DuGZuvd2.js +0 -1
  188. package/static/assets/zap-BlzMp7dY.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 } 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,14 +78,15 @@ 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,
87
87
  architecture_context: architectureContextTool,
88
- role_context: roleContextTool
88
+ role_context: roleContextTool,
89
+ resources: resourcesTool
89
90
  };
90
91
  return c.json({
91
92
  success: true,
@@ -105,15 +106,16 @@ app.get('/', async (c) => {
105
106
  */
106
107
  app.get('/schema', async (c) => {
107
108
  try {
108
- // 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
109
110
  const schema = {
110
111
  tools: {
111
- change_proposals: proposalsFullTool,
112
+ tasks: tasksFullTool,
112
113
  knowledge_documents: knowledgeTool,
113
114
  activity_events: eventsTool,
114
115
  project_context: projectContextTool,
115
116
  architecture_context: architectureContextTool,
116
- role_context: roleContextTool
117
+ role_context: roleContextTool,
118
+ resources: resourcesTool
117
119
  }
118
120
  };
119
121
  return c.json(schema);
@@ -133,8 +135,8 @@ app.post('/execute', async (c) => {
133
135
  if (!tool || !args) {
134
136
  return c.json({ success: false, error: 'Tool and arguments are required' }, 400);
135
137
  }
136
- if (tool === 'change_proposals') {
137
- return await executeProposalsTool(c, args);
138
+ if (tool === 'tasks') {
139
+ return await executeTasksTool(c, args);
138
140
  }
139
141
  if (tool === 'knowledge_documents') {
140
142
  return await executeKnowledgeTool(c, args);
@@ -151,6 +153,9 @@ app.post('/execute', async (c) => {
151
153
  if (tool === 'role_context') {
152
154
  return await executeRoleContextTool(c, args);
153
155
  }
156
+ if (tool === 'resources') {
157
+ return await executeResourcesTool(c, args);
158
+ }
154
159
  return c.json({ success: false, error: 'Unknown tool' }, 400);
155
160
  }
156
161
  catch (error) {
@@ -158,71 +163,71 @@ app.post('/execute', async (c) => {
158
163
  return c.json({ success: false, error: 'Tool execution failed' }, 500);
159
164
  }
160
165
  });
161
- // Proposals tool - full CRUD operations using @lovelybunch/core
162
- async function executeProposalsTool(c, args) {
163
- 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;
164
169
  try {
165
170
  switch (operation) {
166
171
  case 'list': {
167
- const proposals = await listProposals(filters || {});
172
+ const tasks = await listTasks(filters || {});
168
173
  return c.json({
169
174
  success: true,
170
- data: proposals,
171
- count: proposals.length,
172
- message: `Found ${proposals.length} proposals`
175
+ data: tasks,
176
+ count: tasks.length,
177
+ message: `Found ${tasks.length} tasks`
173
178
  });
174
179
  }
175
180
  case 'get': {
176
181
  if (!id) {
177
- 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);
178
183
  }
179
- const result = await getProposal(id);
184
+ const result = await getTask(id);
180
185
  if (!result) {
181
- return c.json({ success: false, error: 'Proposal not found' }, 404);
186
+ return c.json({ success: false, error: 'Task not found' }, 404);
182
187
  }
183
188
  return c.json({
184
189
  success: true,
185
190
  data: result,
186
- message: `Retrieved proposal ${id}`
191
+ message: `Retrieved task ${id}`
187
192
  });
188
193
  }
189
194
  case 'create': {
190
- if (!proposal) {
191
- 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);
192
197
  }
193
- const created = await createProposal(proposal);
198
+ const created = await createTask(task);
194
199
  return c.json({
195
200
  success: true,
196
201
  data: created,
197
- message: `Created proposal ${created.id}`
202
+ message: `Created task ${created.id}`
198
203
  }, 201);
199
204
  }
200
205
  case 'update': {
201
206
  if (!id) {
202
- 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);
203
208
  }
204
- const updateData = updates || proposal;
209
+ const updateData = updates || task;
205
210
  if (!updateData) {
206
211
  return c.json({ success: false, error: 'Update data is required for update operation' }, 400);
207
212
  }
208
- const updated = await updateProposal(id, updateData);
213
+ const updated = await updateTask(id, updateData);
209
214
  return c.json({
210
215
  success: true,
211
216
  data: updated,
212
- message: `Updated proposal ${id}`
217
+ message: `Updated task ${id}`
213
218
  });
214
219
  }
215
220
  case 'delete': {
216
221
  if (!id) {
217
- 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);
218
223
  }
219
- const deleted = await deleteProposal(id);
224
+ const deleted = await deleteTask(id);
220
225
  if (!deleted) {
221
- return c.json({ success: false, error: 'Proposal not found' }, 404);
226
+ return c.json({ success: false, error: 'Task not found' }, 404);
222
227
  }
223
228
  return c.json({
224
229
  success: true,
225
- message: `Deleted proposal ${id}`
230
+ message: `Deleted task ${id}`
226
231
  });
227
232
  }
228
233
  default:
@@ -244,7 +249,7 @@ async function executeProposalsTool(c, args) {
244
249
  }))
245
250
  }, 400);
246
251
  }
247
- console.error('Error executing proposals tool:', error);
252
+ console.error('Error executing tasks tool:', error);
248
253
  return c.json({ success: false, error: error.message || 'Tool execution failed' }, 500);
249
254
  }
250
255
  }
@@ -449,6 +454,76 @@ async function executeArchitectureContextTool(c, args) {
449
454
  async function executeRoleContextTool(c, args) {
450
455
  return executeContextTool(c, 'role', args);
451
456
  }
457
+ // Resources tool executor — proxies to the resource API endpoints on the same server
458
+ async function executeResourcesTool(c, args) {
459
+ const { operation, query, type_filter, resource_id, prompt, model, aspect_ratio, text, voice, duration, resolution, url, tags, description } = args;
460
+ const port = process.env.PORT ? parseInt(process.env.PORT) : 3001;
461
+ const apiBase = `http://127.0.0.1:${port}`;
462
+ try {
463
+ switch (operation) {
464
+ case 'list': {
465
+ const response = await fetch(`${apiBase}/api/v1/resources`);
466
+ const result = await response.json();
467
+ if (!result.success || !result.data) {
468
+ return c.json({ success: false, error: 'Failed to list resources' }, 500);
469
+ }
470
+ let resources = result.data;
471
+ if (type_filter) {
472
+ const prefix = type_filter.toLowerCase();
473
+ resources = resources.filter((r) => r.type?.toLowerCase().startsWith(prefix));
474
+ }
475
+ if (query) {
476
+ const q = query.toLowerCase();
477
+ resources = resources.filter((r) => r.name?.toLowerCase().includes(q) ||
478
+ r.metadata?.description?.toLowerCase().includes(q) ||
479
+ r.metadata?.tags?.some((tag) => tag.toLowerCase().includes(q)));
480
+ }
481
+ return c.json({
482
+ success: true,
483
+ data: resources.map((r) => ({
484
+ id: r.id, name: r.name, type: r.type, size: r.size,
485
+ tags: r.metadata?.tags, description: r.metadata?.description
486
+ })),
487
+ count: resources.length,
488
+ message: query ? `Found ${resources.length} resources matching "${query}"` : `Found ${resources.length} resources`
489
+ });
490
+ }
491
+ case 'get': {
492
+ if (!resource_id) {
493
+ return c.json({ success: false, error: 'resource_id is required for get operation' }, 400);
494
+ }
495
+ const response = await fetch(`${apiBase}/api/v1/resources`);
496
+ const result = await response.json();
497
+ if (!result.success || !result.data) {
498
+ return c.json({ success: false, error: 'Failed to fetch resources' }, 500);
499
+ }
500
+ const resource = result.data.find((r) => r.id === resource_id);
501
+ if (!resource) {
502
+ return c.json({ success: false, error: `Resource '${resource_id}' not found` }, 404);
503
+ }
504
+ return c.json({ success: true, data: resource, message: `Retrieved resource ${resource.name}` });
505
+ }
506
+ // For write operations, return a not-implemented message since these require
507
+ // long-running Replicate calls that are better handled via the AI route's
508
+ // tool execution (which runs within streamText's tool loop).
509
+ case 'generate_image':
510
+ case 'generate_audio':
511
+ case 'generate_video':
512
+ case 'add_from_url': {
513
+ return c.json({
514
+ success: false,
515
+ error: `The '${operation}' operation is only available through the AI assistant chat. Use the assistant sidebar to generate or add resources.`
516
+ }, 400);
517
+ }
518
+ default:
519
+ return c.json({ success: false, error: `Unknown operation: ${operation}` }, 400);
520
+ }
521
+ }
522
+ catch (error) {
523
+ console.error('Error executing resources tool:', error);
524
+ return c.json({ success: false, error: error.message || 'Resources tool execution failed' }, 500);
525
+ }
526
+ }
452
527
  /**
453
528
  * GET /api/v1/mcp/raw-config
454
529
  * Returns the raw MCP configuration for editing in settings UI
@@ -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
+ }