@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.
- package/dist/lib/jobs/job-runner.js +10 -2
- package/dist/lib/jobs/job-scheduler.js +21 -0
- package/dist/lib/mail/mail-runner.d.ts +51 -0
- package/dist/lib/mail/mail-runner.js +342 -0
- package/dist/lib/slack/slack-service.d.ts +2 -0
- package/dist/lib/slack/slack-service.js +3 -0
- package/dist/lib/storage/file-storage.d.ts +16 -16
- package/dist/lib/storage/file-storage.js +59 -64
- package/dist/lib/terminal/terminal-manager.d.ts +3 -3
- package/dist/lib/terminal/terminal-manager.js +10 -10
- package/dist/routes/api/v1/ai/route.js +39 -19
- package/dist/routes/api/v1/git/index.js +23 -0
- package/dist/routes/api/v1/mail/index.d.ts +3 -0
- package/dist/routes/api/v1/mail/index.js +23 -0
- package/dist/routes/api/v1/mail/route.d.ts +294 -0
- package/dist/routes/api/v1/mail/route.js +344 -0
- package/dist/routes/api/v1/mcp/index.js +32 -32
- package/dist/routes/api/v1/slack/index.d.ts +3 -0
- package/dist/routes/api/v1/slack/index.js +15 -0
- package/dist/routes/api/v1/slack/route.d.ts +124 -0
- package/dist/routes/api/v1/slack/route.js +192 -0
- package/dist/routes/api/v1/tasks/[id]/route.d.ts +117 -0
- package/dist/routes/api/v1/tasks/[id]/route.js +166 -0
- package/dist/routes/api/v1/tasks/index.d.ts +3 -0
- package/dist/routes/api/v1/tasks/index.js +10 -0
- package/dist/routes/api/v1/tasks/route.d.ts +96 -0
- package/dist/routes/api/v1/tasks/route.js +136 -0
- package/dist/routes/api/v1/terminal/[taskId]/create/index.d.ts +3 -0
- package/dist/routes/api/v1/terminal/[taskId]/create/index.js +5 -0
- package/dist/routes/api/v1/terminal/[taskId]/create/route.d.ts +10 -0
- package/dist/routes/api/v1/terminal/[taskId]/create/route.js +27 -0
- package/dist/routes/api/v1/terminal/[taskId]/destroy/index.d.ts +3 -0
- package/dist/routes/api/v1/terminal/[taskId]/destroy/index.js +5 -0
- package/dist/routes/api/v1/terminal/[taskId]/destroy/route.d.ts +10 -0
- package/dist/routes/api/v1/terminal/[taskId]/destroy/route.js +21 -0
- package/dist/routes/api/v1/terminal/[taskId]/resize/index.d.ts +3 -0
- package/dist/routes/api/v1/terminal/[taskId]/resize/index.js +5 -0
- package/dist/routes/api/v1/terminal/[taskId]/resize/route.d.ts +10 -0
- package/dist/routes/api/v1/terminal/[taskId]/resize/route.js +21 -0
- package/dist/routes/api/v1/terminal/sessions/route.js +4 -4
- package/dist/server-with-static.js +12 -8
- package/dist/server.js +12 -8
- package/package.json +4 -4
- package/static/assets/{ActivityPage-OxRci_V2.js → ActivityPage-k4I7Q53O.js} +1 -1
- package/static/assets/ApiKeysSettingsPage-B1YvVdmg.js +2 -0
- package/static/assets/{ArchitectureEditPage-D7xcH6dY.js → ArchitectureEditPage-CpowsIx2.js} +4 -4
- package/static/assets/{ArchitecturePage-pvnlX-NW.js → ArchitecturePage-DYxC_aMR.js} +1 -1
- package/static/assets/{AuthSettingsPage-Bu0CZ1rY.js → AuthSettingsPage-DtSo78Y_.js} +2 -2
- package/static/assets/{CallbackPage-D0lkjxCT.js → CallbackPage-bROCGapx.js} +1 -1
- package/static/assets/CodePage-CPCj64rX.js +2 -0
- package/static/assets/{CollapsibleSection-Bt_ZLnJc.js → CollapsibleSection-M5cXbl92.js} +1 -1
- package/static/assets/DashboardPage-B9BZZfw6.js +51 -0
- package/static/assets/{GitPage-TrTxZ27J.js → GitPage-BiDtdSK1.js} +2 -2
- package/static/assets/GitSettingsPage-THm6wDjs.js +6 -0
- package/static/assets/IdentityPage-BC16skg6.js +6 -0
- package/static/assets/{ImplementationStepsEditor-Ctx0CvbU.js → ImplementationStepsEditor-HliLQav5.js} +2 -2
- package/static/assets/{IntegrationsSettingsPage-C2wJVdM7.js → IntegrationsSettingsPage-CC_VKIQa.js} +1 -1
- package/static/assets/JobDetailPage-z1QQYvmU.js +1 -0
- package/static/assets/{KnowledgeDetailPage-BdTUfWqj.js → KnowledgeDetailPage-DzHXBS7Q.js} +1 -1
- package/static/assets/{KnowledgeEditPage-D8XK4IUf.js → KnowledgeEditPage-BwGnUH_m.js} +1 -1
- package/static/assets/KnowledgePage-CGIVMS02.js +3 -0
- package/static/assets/{LoginPage-Dqxd7cTa.js → LoginPage-VQ3lcfLV.js} +1 -1
- package/static/assets/MailInboxPage-DiZKqwdU.js +1 -0
- package/static/assets/MailProcessingModal-DIeSQBoR.js +6 -0
- package/static/assets/MailReadPage-C8AACmZQ.js +1 -0
- package/static/assets/MailSentPage-C_5yFly_.js +1 -0
- package/static/assets/{McpSettingsPage-10n35zXi.js → McpSettingsPage-i9YHcu1s.js} +1 -1
- package/static/assets/{NewKnowledgePage-BlJzzuh7.js → NewKnowledgePage-BnVY7WUD.js} +1 -1
- package/static/assets/{NewSkillPage-ByqN--mH.js → NewSkillPage-DwniHD6D.js} +1 -1
- package/static/assets/NewTaskPage-F5UX2WMc.js +90 -0
- package/static/assets/NotFoundPage-BbSZX_4L.js +6 -0
- package/static/assets/NotificationsSettingsPage-C8kjcift.js +1 -0
- package/static/assets/{ProjectEditPage-DKJTY2uc.js → ProjectEditPage-DUUlIEqI.js} +1 -1
- package/static/assets/{ProjectPage-2VblKCWz.js → ProjectPage-Unz9PQpA.js} +1 -1
- package/static/assets/{PromptsSettingsPage-B4mOhXuo.js → PromptsSettingsPage-DVpIuRKI.js} +1 -1
- package/static/assets/ResourceDetailPage-DqHZ2KYD.js +1 -0
- package/static/assets/{ResourcesPage-2BbjIWfF.js → ResourcesPage-BP5tuAi-.js} +1 -1
- package/static/assets/RoleEditPage-BgKu8S0-.js +13 -0
- package/static/assets/{RolePage-qXWXZ2FZ.js → RolePage-Fed52Ov5.js} +1 -1
- package/static/assets/{RulesSettingsPage-BtM7p8F6.js → RulesSettingsPage-BQ2O0u66.js} +3 -3
- package/static/assets/SchedulePage-jkxjuzBx.js +4 -0
- package/static/assets/SkillDetailPage-k3Q2-NFd.js +1 -0
- package/static/assets/{SkillEditPage-Czlo8WWT.js → SkillEditPage-urF4snjo.js} +1 -1
- package/static/assets/SkillsPage-DlWDhEjR.js +8 -0
- package/static/assets/{SkillsSettingsPage-DKtpy7qk.js → SkillsSettingsPage-BViFgckG.js} +1 -1
- package/static/assets/{SourceInput-BITn1Y15.js → SourceInput-CAFKTHw-.js} +1 -1
- package/static/assets/{TagInput-BK91_M1N.js → TagInput-C6lI-ePr.js} +1 -1
- package/static/assets/TaskDetailPage-DpbRHnW_.js +16 -0
- package/static/assets/TaskEditPage-DssRbW0h.js +1 -0
- package/static/assets/TasksPage-CD_eo0Bj.js +17 -0
- package/static/assets/TerminalPage-BG_wlccr.js +1 -0
- package/static/assets/TerminalSessionPage-CsK-LznK.js +8 -0
- package/static/assets/{UserPreferencesPage-DrgYEcxO.js → UserPreferencesPage-CWUq3efu.js} +1 -1
- package/static/assets/UserSettingsPage-CduI_MGS.js +1 -0
- package/static/assets/{UtilitiesPage-Djr4qT5L.js → UtilitiesPage-BAxokhLh.js} +1 -1
- package/static/assets/{alert-CsMvyYoX.js → alert-BXsc6_qu.js} +1 -1
- package/static/assets/{arrow-down-BZnfbld8.js → arrow-down-DmW_3gE8.js} +1 -1
- package/static/assets/{arrow-left-WGBYWq3h.js → arrow-left-1S-835kP.js} +1 -1
- package/static/assets/{arrow-up-BByVUPE7.js → arrow-up-BYism_o1.js} +1 -1
- package/static/assets/arrow-up-down-Dw3J0a4i.js +6 -0
- package/static/assets/{badge-AwLOflf5.js → badge-BUEY53dV.js} +1 -1
- package/static/assets/{browser-modal-BzGNFfTG.js → browser-modal-DCNdI4NT.js} +2 -2
- package/static/assets/{card-SN5gKnu7.js → card-BcPlIAH5.js} +1 -1
- package/static/assets/{chevron-left-C7uNq9l_.js → chevron-left-FMmNe7yP.js} +1 -1
- package/static/assets/{chevron-up-CHdIiLxL.js → chevron-up-CqM3won3.js} +1 -1
- package/static/assets/{chevrons-up-TXwQuoUN.js → chevrons-up-DTvCkIHc.js} +1 -1
- package/static/assets/{circle-alert-37E5gU9K.js → circle-alert-dseM-Ib7.js} +1 -1
- package/static/assets/{circle-check-big-nY4PntB5.js → circle-check-big-jKg34xC-.js} +1 -1
- package/static/assets/{circle-check-D02pWDME.js → circle-check-eyo6pBP1.js} +1 -1
- package/static/assets/{circle-play-7EXFLo4F.js → circle-play-BrY_lNiH.js} +1 -1
- package/static/assets/{circle-x-By4JoTHB.js → circle-x-uqmzEce1.js} +1 -1
- package/static/assets/{clipboard-BdymjxLO.js → clipboard-tzPFoieb.js} +1 -1
- package/static/assets/{clock-HDu44KTo.js → clock-Bjc06QBM.js} +1 -1
- package/static/assets/code-DrYqPukx.js +6 -0
- package/static/assets/{download-Cv2G2Eg9.js → download-Bg__QCLT.js} +1 -1
- package/static/assets/{external-link-DwMXcCCj.js → external-link-CNDy2UUo.js} +1 -1
- package/static/assets/{eye-DYnjJzdb.js → eye-DLFBnC8t.js} +1 -1
- package/static/assets/{folder-git-2-COeWFPHS.js → folder-git-2-DUqd0WRi.js} +1 -1
- package/static/assets/index-CHdBxVyk.css +2 -0
- package/static/assets/{index-9Tv-j_Ga.js → index-DFcWlnzl.js} +118 -103
- package/static/assets/{info-BmtuPMhv.js → info-D6jxZC5X.js} +1 -1
- package/static/assets/kiro-CX1mOsRO.js +17 -0
- package/static/assets/{label-TGqbNfMO.js → label-DBuh-ke5.js} +1 -1
- package/static/assets/{markdown-editor-ls1JPK_e.js → markdown-editor-B4YNQFT2.js} +1 -1
- package/static/assets/message-square-B5RWz_ff.js +6 -0
- package/static/assets/paperclip-4A_3MaPx.js +6 -0
- package/static/assets/{pause-CAWbvTiL.js → pause-BzhKXHtR.js} +1 -1
- package/static/assets/{play-DF_Qeu0H.js → play-CHIf-Rcz.js} +1 -1
- package/static/assets/{radio-group-DYTbywtK.js → radio-group-C1ct-VsJ.js} +1 -1
- package/static/assets/{refresh-cw-BFZxHqbC.js → refresh-cw-B3OwrDUf.js} +1 -1
- package/static/assets/{search-Dr90tbch.js → search-Cq1ksEdp.js} +1 -1
- package/static/assets/{select-Cs5qtMYV.js → select-44mcS2_G.js} +1 -1
- package/static/assets/{status-utils-BDOyevaX.js → status-utils-CDkPeVfP.js} +1 -1
- package/static/assets/{switch-4TDb6YiQ.js → switch-CIwjYvCt.js} +1 -1
- package/static/assets/{tabs-BrbEvF4V.js → tabs-DTV6Su-h.js} +1 -1
- package/static/assets/{tag-DrQkepeD.js → tag-p6yeowCW.js} +1 -1
- package/static/assets/{terminal-preview-uuKF9_x4.js → terminal-preview-DN38x9Jm.js} +1 -1
- package/static/assets/use-terminal-BXJqOeJe.js +1 -0
- package/static/assets/{video-DYA2WfbA.js → video-BH5ChaoS.js} +1 -1
- package/static/index.html +2 -2
- package/static/assets/ApiKeysSettingsPage-C0evI19e.js +0 -2
- package/static/assets/CodePage-BJ4PC5nb.js +0 -2
- package/static/assets/DashboardPage-BiffPdmj.js +0 -41
- package/static/assets/GitSettingsPage-D7q5xQd_.js +0 -6
- package/static/assets/IdentityPage-CY0Ak2j0.js +0 -11
- package/static/assets/JobDetailPage-Phx_IlKX.js +0 -1
- package/static/assets/KnowledgePage-Ci9G7Br-.js +0 -8
- package/static/assets/NewProposalPage-BP7Ttoxk.js +0 -90
- package/static/assets/ProposalDetailPage-m3ysyzpj.js +0 -1
- package/static/assets/ProposalEditPage-3XVg_paW.js +0 -1
- package/static/assets/ProposalsPage-B3u0aFFz.js +0 -17
- package/static/assets/ResourceDetailPage-somBLUpC.js +0 -1
- package/static/assets/RoleEditPage-CLzX7Xhi.js +0 -13
- package/static/assets/SchedulePage-4tFcIBSs.js +0 -4
- package/static/assets/SkillDetailPage-CroSdaju.js +0 -1
- package/static/assets/SkillsPage-CgULbcI-.js +0 -8
- package/static/assets/TerminalPage-8fwvnOo2.js +0 -1
- package/static/assets/TerminalSessionPage-BhO5U48p.js +0 -13
- package/static/assets/UserSettingsPage-Dj6lKLi8.js +0 -1
- package/static/assets/droid-CPteN3f9.js +0 -17
- package/static/assets/index-GFQ5RqVh.css +0 -2
- package/static/assets/use-terminal-BG5UXuVE.js +0 -1
- 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 {
|
|
6
|
-
import {
|
|
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:
|
|
81
|
+
// Note: tasks now supports full CRUD, knowledge/project/architecture are read+write, events is read-only
|
|
82
82
|
const builtInTools = {
|
|
83
|
-
|
|
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:
|
|
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
|
-
|
|
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 === '
|
|
139
|
-
return await
|
|
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
|
-
//
|
|
167
|
-
async function
|
|
168
|
-
const { operation, id, filters,
|
|
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
|
|
172
|
+
const tasks = await listTasks(filters || {});
|
|
173
173
|
return c.json({
|
|
174
174
|
success: true,
|
|
175
|
-
data:
|
|
176
|
-
count:
|
|
177
|
-
message: `Found ${
|
|
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: '
|
|
182
|
+
return c.json({ success: false, error: 'Task ID is required for get operation' }, 400);
|
|
183
183
|
}
|
|
184
|
-
const result = await
|
|
184
|
+
const result = await getTask(id);
|
|
185
185
|
if (!result) {
|
|
186
|
-
return c.json({ success: false, error: '
|
|
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
|
|
191
|
+
message: `Retrieved task ${id}`
|
|
192
192
|
});
|
|
193
193
|
}
|
|
194
194
|
case 'create': {
|
|
195
|
-
if (!
|
|
196
|
-
return c.json({ success: false, error: '
|
|
195
|
+
if (!task) {
|
|
196
|
+
return c.json({ success: false, error: 'Task data is required for create operation' }, 400);
|
|
197
197
|
}
|
|
198
|
-
const created = await
|
|
198
|
+
const created = await createTask(task);
|
|
199
199
|
return c.json({
|
|
200
200
|
success: true,
|
|
201
201
|
data: created,
|
|
202
|
-
message: `Created
|
|
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: '
|
|
207
|
+
return c.json({ success: false, error: 'Task ID is required for update operation' }, 400);
|
|
208
208
|
}
|
|
209
|
-
const updateData = updates ||
|
|
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
|
|
213
|
+
const updated = await updateTask(id, updateData);
|
|
214
214
|
return c.json({
|
|
215
215
|
success: true,
|
|
216
216
|
data: updated,
|
|
217
|
-
message: `Updated
|
|
217
|
+
message: `Updated task ${id}`
|
|
218
218
|
});
|
|
219
219
|
}
|
|
220
220
|
case 'delete': {
|
|
221
221
|
if (!id) {
|
|
222
|
-
return c.json({ success: false, error: '
|
|
222
|
+
return c.json({ success: false, error: 'Task ID is required for delete operation' }, 400);
|
|
223
223
|
}
|
|
224
|
-
const deleted = await
|
|
224
|
+
const deleted = await deleteTask(id);
|
|
225
225
|
if (!deleted) {
|
|
226
|
-
return c.json({ success: false, error: '
|
|
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
|
|
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
|
|
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,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">)>;
|