@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.
- 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 -5
- package/dist/lib/terminal/terminal-manager.js +10 -61
- package/dist/routes/api/v1/ai/route.js +361 -20
- package/dist/routes/api/v1/chats/[id]/index.js +2 -1
- package/dist/routes/api/v1/chats/[id]/route.d.ts +7 -0
- package/dist/routes/api/v1/chats/[id]/route.js +30 -1
- package/dist/routes/api/v1/context/index.js +0 -2
- package/dist/routes/api/v1/git/index.js +23 -0
- package/dist/routes/api/v1/knowledge/[filename]/index.d.ts +1 -0
- package/dist/routes/api/v1/knowledge/[filename]/index.js +1 -0
- package/dist/routes/api/v1/knowledge/[filename]/route.d.ts +3 -0
- package/dist/routes/api/v1/knowledge/[filename]/route.js +254 -0
- package/dist/routes/api/v1/knowledge/index.d.ts +1 -0
- package/dist/routes/api/v1/knowledge/index.js +1 -0
- package/dist/routes/api/v1/knowledge/route.d.ts +3 -0
- package/dist/routes/api/v1/knowledge/route.js +176 -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 +109 -34
- 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/[proposalId]/create/route.js +2 -2
- 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 +14 -8
- package/dist/server.js +14 -8
- package/package.json +4 -4
- package/static/assets/{ActivityPage-DSSML9J-.js → ActivityPage-k4I7Q53O.js} +1 -1
- package/static/assets/ApiKeysSettingsPage-B1YvVdmg.js +2 -0
- package/static/assets/{ArchitectureEditPage-CIjqkpMz.js → ArchitectureEditPage-CpowsIx2.js} +1 -1
- package/static/assets/{ArchitecturePage-Db__w054.js → ArchitecturePage-DYxC_aMR.js} +1 -1
- package/static/assets/{AuthSettingsPage-Bpooi8Z0.js → AuthSettingsPage-DtSo78Y_.js} +2 -2
- package/static/assets/{CallbackPage-BGLKeyjv.js → CallbackPage-bROCGapx.js} +1 -1
- package/static/assets/CodePage-CPCj64rX.js +2 -0
- package/static/assets/{CollapsibleSection-B6RO5o5R.js → CollapsibleSection-M5cXbl92.js} +1 -1
- package/static/assets/DashboardPage-B9BZZfw6.js +51 -0
- package/static/assets/{GitPage-DxjLaRWe.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-DWjDyZzP.js → ImplementationStepsEditor-HliLQav5.js} +2 -2
- package/static/assets/IntegrationsSettingsPage-CC_VKIQa.js +1 -0
- package/static/assets/JobDetailPage-z1QQYvmU.js +1 -0
- package/static/assets/KnowledgeDetailPage-DzHXBS7Q.js +1 -0
- package/static/assets/KnowledgeEditPage-BwGnUH_m.js +1 -0
- package/static/assets/KnowledgePage-CGIVMS02.js +3 -0
- package/static/assets/{LoginPage-DptfKsWo.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-i9YHcu1s.js +1 -0
- package/static/assets/NewKnowledgePage-BnVY7WUD.js +9 -0
- package/static/assets/{NewSkillPage-Cwy2MSr9.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-DUUlIEqI.js +11 -0
- package/static/assets/{ProjectPage-DgUr4bVU.js → ProjectPage-Unz9PQpA.js} +1 -1
- package/static/assets/PromptsSettingsPage-DVpIuRKI.js +1 -0
- package/static/assets/ResourceDetailPage-DqHZ2KYD.js +1 -0
- package/static/assets/ResourcesPage-BP5tuAi-.js +41 -0
- package/static/assets/RoleEditPage-BgKu8S0-.js +13 -0
- package/static/assets/{RolePage-Sc-GFiL2.js → RolePage-Fed52Ov5.js} +1 -1
- package/static/assets/{RulesSettingsPage-DdMCzh9j.js → RulesSettingsPage-BQ2O0u66.js} +2 -2
- package/static/assets/SchedulePage-jkxjuzBx.js +4 -0
- package/static/assets/SkillDetailPage-k3Q2-NFd.js +1 -0
- package/static/assets/{SkillEditPage-BDd2CtAS.js → SkillEditPage-urF4snjo.js} +1 -1
- package/static/assets/SkillsPage-DlWDhEjR.js +8 -0
- package/static/assets/{SkillsSettingsPage-1N0JQOYc.js → SkillsSettingsPage-BViFgckG.js} +1 -1
- package/static/assets/SourceInput-CAFKTHw-.js +1 -0
- package/static/assets/{TagInput-D_SdcypZ.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-CWUq3efu.js +1 -0
- package/static/assets/UserSettingsPage-CduI_MGS.js +1 -0
- package/static/assets/UtilitiesPage-BAxokhLh.js +1 -0
- package/static/assets/{alert-BD5jo3SI.js → alert-BXsc6_qu.js} +1 -1
- package/static/assets/{arrow-down-BxcoVp6S.js → arrow-down-DmW_3gE8.js} +1 -1
- package/static/assets/{arrow-left-CdM_IPng.js → arrow-left-1S-835kP.js} +1 -1
- package/static/assets/{arrow-up-BOJ6ob9X.js → arrow-up-BYism_o1.js} +1 -1
- package/static/assets/arrow-up-down-Dw3J0a4i.js +6 -0
- package/static/assets/{badge-DEiQk9C9.js → badge-BUEY53dV.js} +1 -1
- package/static/assets/{browser-modal-Dp1eMxt6.js → browser-modal-DCNdI4NT.js} +2 -2
- package/static/assets/{card-BCFxXzRk.js → card-BcPlIAH5.js} +1 -1
- package/static/assets/{chevron-left-C25izNzZ.js → chevron-left-FMmNe7yP.js} +1 -1
- package/static/assets/{plus-iamYJu5V.js → chevron-up-CqM3won3.js} +2 -2
- package/static/assets/{chevrons-up-DqbWMOjv.js → chevrons-up-DTvCkIHc.js} +1 -1
- package/static/assets/{circle-alert-CMRMPnbY.js → circle-alert-dseM-Ib7.js} +1 -1
- package/static/assets/{circle-check-big-NI18oHuP.js → circle-check-big-jKg34xC-.js} +1 -1
- package/static/assets/{circle-check-D5wZZPvj.js → circle-check-eyo6pBP1.js} +1 -1
- package/static/assets/{circle-play-BhVU869u.js → circle-play-BrY_lNiH.js} +1 -1
- package/static/assets/{circle-x-BXDB-G_q.js → circle-x-uqmzEce1.js} +1 -1
- package/static/assets/{clipboard-DC2xmNVx.js → clipboard-tzPFoieb.js} +1 -1
- package/static/assets/{clock-CeCp7Pz1.js → clock-Bjc06QBM.js} +1 -1
- package/static/assets/code-DrYqPukx.js +6 -0
- package/static/assets/{download-ZF_XbTIA.js → download-Bg__QCLT.js} +1 -1
- package/static/assets/{external-link-CYBz87-P.js → external-link-CNDy2UUo.js} +1 -1
- package/static/assets/{eye-BT8MAvKY.js → eye-DLFBnC8t.js} +1 -1
- package/static/assets/{folder-git-2-BE9AIPnj.js → folder-git-2-DUqd0WRi.js} +1 -1
- package/static/assets/index-CHdBxVyk.css +2 -0
- package/static/assets/index-DFcWlnzl.js +487 -0
- package/static/assets/{info-DunFSp-x.js → info-D6jxZC5X.js} +1 -1
- package/static/assets/kiro-CX1mOsRO.js +17 -0
- package/static/assets/{label-vYhfrPMD.js → label-DBuh-ke5.js} +1 -1
- package/static/assets/{markdown-editor-BzZ8tCto.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-BHonpdnw.js → pause-BzhKXHtR.js} +1 -1
- package/static/assets/{play-CCo7tau2.js → play-CHIf-Rcz.js} +1 -1
- package/static/assets/{radio-group-Db-pBuyW.js → radio-group-C1ct-VsJ.js} +1 -1
- package/static/assets/{refresh-cw-Bg7vQzOw.js → refresh-cw-B3OwrDUf.js} +1 -1
- package/static/assets/{search-CH2zaibZ.js → search-Cq1ksEdp.js} +1 -1
- package/static/assets/select-44mcS2_G.js +1 -0
- package/static/assets/{status-utils-BDOyevaX.js → status-utils-CDkPeVfP.js} +1 -1
- package/static/assets/{switch-CH-VOgPo.js → switch-CIwjYvCt.js} +1 -1
- package/static/assets/{tabs-XeRAjZYR.js → tabs-DTV6Su-h.js} +1 -1
- package/static/assets/{tag-CRP5nL5-.js → tag-p6yeowCW.js} +1 -1
- package/static/assets/{terminal-preview-DMJMuORo.js → terminal-preview-DN38x9Jm.js} +1 -1
- package/static/assets/use-terminal-BXJqOeJe.js +1 -0
- package/static/assets/video-BH5ChaoS.js +36 -0
- package/static/index.html +2 -2
- package/static/assets/ApiKeysSettingsPage-Chw9PNL5.js +0 -2
- package/static/assets/CodePage-CrokcH-S.js +0 -2
- package/static/assets/DashboardPage-BaSQQ8Nv.js +0 -41
- package/static/assets/GitSettingsPage-tKBXYAFm.js +0 -6
- package/static/assets/IdentityPage-D2yBjeYn.js +0 -11
- package/static/assets/IntegrationsSettingsPage-Bx8-0Ig4.js +0 -1
- package/static/assets/JobDetailPage-BQmTHled.js +0 -1
- package/static/assets/KnowledgeDetailPage-QMU2bC3L.js +0 -1
- package/static/assets/KnowledgeEditPage-DbMJVcLc.js +0 -1
- package/static/assets/KnowledgePage-aU1GxZSZ.js +0 -8
- package/static/assets/McpSettingsPage-C3WxFwRB.js +0 -1
- package/static/assets/NewKnowledgePage-Cbiswrw_.js +0 -9
- package/static/assets/NewProposalPage-B_sDMBTK.js +0 -90
- package/static/assets/ProjectEditPage-BznWiBBc.js +0 -11
- package/static/assets/PromptsSettingsPage-CY0-870a.js +0 -1
- package/static/assets/ProposalDetailPage-K4iMXHEg.js +0 -1
- package/static/assets/ProposalEditPage-jZOtCMqP.js +0 -1
- package/static/assets/ProposalsPage-C7n4-G05.js +0 -17
- package/static/assets/ResourcesPage-vB5-XkUv.js +0 -71
- package/static/assets/RoleEditPage-Cu7ZB3yj.js +0 -13
- package/static/assets/SchedulePage-Bkkf2wA0.js +0 -4
- package/static/assets/SkillDetailPage-5sDxf3Of.js +0 -1
- package/static/assets/SkillsPage-D2G7EfK8.js +0 -8
- package/static/assets/SourceInput-DlC0zwva.js +0 -1
- package/static/assets/TerminalPage--KZ7azvP.js +0 -1
- package/static/assets/TerminalSessionPage-ClvxK9ia.js +0 -13
- package/static/assets/UserPreferencesPage-CheOH7jZ.js +0 -1
- package/static/assets/UserSettingsPage-C8STDvfQ.js +0 -1
- package/static/assets/UtilitiesPage-9rTxR2md.js +0 -1
- package/static/assets/calendar-Cx5r9R7A.js +0 -6
- package/static/assets/droid-DqWsM2dp.js +0 -17
- package/static/assets/index-DVTgTsDa.css +0 -2
- package/static/assets/index-hqVgTgRB.js +0 -462
- package/static/assets/use-terminal-DuGZuvd2.js +0 -1
- 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 {
|
|
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,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:
|
|
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,
|
|
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:
|
|
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
|
-
|
|
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 === '
|
|
137
|
-
return await
|
|
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
|
-
//
|
|
162
|
-
async function
|
|
163
|
-
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;
|
|
164
169
|
try {
|
|
165
170
|
switch (operation) {
|
|
166
171
|
case 'list': {
|
|
167
|
-
const
|
|
172
|
+
const tasks = await listTasks(filters || {});
|
|
168
173
|
return c.json({
|
|
169
174
|
success: true,
|
|
170
|
-
data:
|
|
171
|
-
count:
|
|
172
|
-
message: `Found ${
|
|
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: '
|
|
182
|
+
return c.json({ success: false, error: 'Task ID is required for get operation' }, 400);
|
|
178
183
|
}
|
|
179
|
-
const result = await
|
|
184
|
+
const result = await getTask(id);
|
|
180
185
|
if (!result) {
|
|
181
|
-
return c.json({ success: false, error: '
|
|
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
|
|
191
|
+
message: `Retrieved task ${id}`
|
|
187
192
|
});
|
|
188
193
|
}
|
|
189
194
|
case 'create': {
|
|
190
|
-
if (!
|
|
191
|
-
return c.json({ success: false, error: '
|
|
195
|
+
if (!task) {
|
|
196
|
+
return c.json({ success: false, error: 'Task data is required for create operation' }, 400);
|
|
192
197
|
}
|
|
193
|
-
const created = await
|
|
198
|
+
const created = await createTask(task);
|
|
194
199
|
return c.json({
|
|
195
200
|
success: true,
|
|
196
201
|
data: created,
|
|
197
|
-
message: `Created
|
|
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: '
|
|
207
|
+
return c.json({ success: false, error: 'Task ID is required for update operation' }, 400);
|
|
203
208
|
}
|
|
204
|
-
const updateData = updates ||
|
|
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
|
|
213
|
+
const updated = await updateTask(id, updateData);
|
|
209
214
|
return c.json({
|
|
210
215
|
success: true,
|
|
211
216
|
data: updated,
|
|
212
|
-
message: `Updated
|
|
217
|
+
message: `Updated task ${id}`
|
|
213
218
|
});
|
|
214
219
|
}
|
|
215
220
|
case 'delete': {
|
|
216
221
|
if (!id) {
|
|
217
|
-
return c.json({ success: false, error: '
|
|
222
|
+
return c.json({ success: false, error: 'Task ID is required for delete operation' }, 400);
|
|
218
223
|
}
|
|
219
|
-
const deleted = await
|
|
224
|
+
const deleted = await deleteTask(id);
|
|
220
225
|
if (!deleted) {
|
|
221
|
-
return c.json({ success: false, error: '
|
|
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
|
|
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
|
|
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,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
|
+
}
|