@lovelybunch/api 1.0.75-alpha.0 → 1.0.75-alpha.10
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/auth/auth-manager.d.ts +5 -0
- package/dist/lib/auth/auth-manager.js +9 -0
- package/dist/lib/storage/file-storage.d.ts +16 -16
- package/dist/lib/storage/file-storage.js +84 -79
- package/dist/lib/terminal/terminal-manager.d.ts +3 -5
- package/dist/lib/terminal/terminal-manager.js +19 -63
- package/dist/middleware/auth.js +36 -0
- package/dist/routes/api/v1/ai/index.js +0 -2
- package/dist/routes/api/v1/ai/route.js +445 -259
- 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/events/route.js +1 -1
- 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/mcp/index.js +109 -34
- package/dist/routes/api/v1/skills/[id]/index.d.ts +1 -0
- package/dist/routes/api/v1/skills/[id]/index.js +1 -0
- package/dist/routes/api/v1/skills/[id]/route.d.ts +3 -0
- package/dist/routes/api/v1/skills/[id]/route.js +199 -0
- package/dist/routes/api/v1/skills/index.d.ts +1 -0
- package/dist/routes/api/v1/skills/index.js +1 -0
- package/dist/routes/api/v1/skills/route.d.ts +3 -0
- package/dist/routes/api/v1/skills/route.js +329 -0
- package/dist/routes/api/v1/tasks/[id]/route.d.ts +351 -0
- package/dist/routes/api/v1/tasks/[id]/route.js +156 -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 +329 -0
- package/dist/routes/api/v1/tasks/route.js +126 -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 +18 -14
- package/dist/server.js +15 -13
- package/package.json +8 -4
- package/static/assets/{ActivityPage-Dl3u61DF.js → ActivityPage-CbmEnYhg.js} +1 -1
- package/static/assets/ApiKeysSettingsPage-DLxQIqTT.js +2 -0
- package/static/assets/{ArchitectureEditPage-CVxBD88N.js → ArchitectureEditPage-CbtzgIQv.js} +4 -4
- package/static/assets/{ArchitecturePage-GchbFR8L.js → ArchitecturePage-CcAMfFZ8.js} +1 -1
- package/static/assets/{AuthSettingsPage-B7a-i1_T.js → AuthSettingsPage-4Prb7nAt.js} +2 -2
- package/static/assets/{CallbackPage-xYgfYT1Z.js → CallbackPage-CmWv_5Nh.js} +1 -1
- package/static/assets/CodePage-COC7rcwM.js +2 -0
- package/static/assets/{CollapsibleSection-ka7CEJhS.js → CollapsibleSection-C_VVeVSc.js} +1 -1
- package/static/assets/DashboardPage-BACFVIaW.js +41 -0
- package/static/assets/{GitPage-B-aSKe9Z.js → GitPage-rFngEr_A.js} +2 -2
- package/static/assets/GitSettingsPage-CDQovOqx.js +6 -0
- package/static/assets/IdentityPage-CS4REq2E.js +11 -0
- package/static/assets/{ImplementationStepsEditor-BC8bzHNj.js → ImplementationStepsEditor-CBIgppkZ.js} +2 -2
- package/static/assets/IntegrationsSettingsPage-B7HoraBH.js +1 -0
- package/static/assets/JobDetailPage-QUhWsaWV.js +1 -0
- package/static/assets/KnowledgeDetailPage-DCJstmIr.js +1 -0
- package/static/assets/KnowledgeEditPage-EYpFPfcJ.js +1 -0
- package/static/assets/KnowledgePage-D-7skvn5.js +8 -0
- package/static/assets/{LoginPage-Dp6lQSZW.js → LoginPage-L2aoqSDT.js} +1 -1
- package/static/assets/McpSettingsPage-CLwqDjw_.js +1 -0
- package/static/assets/NewKnowledgePage-Fq_QD8um.js +9 -0
- package/static/assets/NewSkillPage-DRcgovk0.js +1 -0
- package/static/assets/NewTaskPage-CleA8rH5.js +90 -0
- package/static/assets/ProjectEditPage-GIMOKgmh.js +11 -0
- package/static/assets/ProjectPage-DlWZOqnb.js +1 -0
- package/static/assets/PromptsSettingsPage-DFagGfo-.js +1 -0
- package/static/assets/ResourceDetailPage-CnFRpDec.js +1 -0
- package/static/assets/ResourcesPage-Cw3fu0JE.js +41 -0
- package/static/assets/{RoleEditPage-Ne8Dh8Tt.js → RoleEditPage-ARXq_eCs.js} +1 -1
- package/static/assets/{RolePage-3sb7lhw8.js → RolePage--XBBIrq8.js} +1 -1
- package/static/assets/{RulesSettingsPage-CEWEvNFC.js → RulesSettingsPage-DEqaRH96.js} +3 -3
- package/static/assets/SchedulePage-C_B2k9P6.js +4 -0
- package/static/assets/SkillDetailPage-Dr6xyKAX.js +1 -0
- package/static/assets/SkillEditPage-BsHXmfEZ.js +1 -0
- package/static/assets/SkillsPage-BrDdAAPx.js +8 -0
- package/static/assets/SkillsSettingsPage-Cvi7xaDE.js +1 -0
- package/static/assets/SourceInput-DxF_GGj8.js +1 -0
- package/static/assets/{TagInput-DRSgjTau.js → TagInput-DYvHbVZq.js} +1 -1
- package/static/assets/TaskDetailPage-DzcD6t03.js +1 -0
- package/static/assets/TaskEditPage-C7a6FOeJ.js +1 -0
- package/static/assets/TasksPage-ChWRSO_S.js +17 -0
- package/static/assets/TerminalPage-CoPwn8cU.js +1 -0
- package/static/assets/TerminalSessionPage-BQBZrOJa.js +13 -0
- package/static/assets/UserPreferencesPage-DjtU7veO.js +1 -0
- package/static/assets/UserSettingsPage-CfU8boJQ.js +1 -0
- package/static/assets/UtilitiesPage-sP1Crg-X.js +1 -0
- package/static/assets/{alert-CBWqAyb9.js → alert-BqZa-crG.js} +1 -1
- package/static/assets/{arrow-down-PY3QZW33.js → arrow-down-3faV_GyO.js} +1 -1
- package/static/assets/{arrow-left-JpEq5x30.js → arrow-left-FD3wQmzH.js} +1 -1
- package/static/assets/{arrow-up-qJ-_eNlY.js → arrow-up-BzP0YNVk.js} +1 -1
- package/static/assets/{badge-D6QJCkgl.js → badge-DRyeFib9.js} +1 -1
- package/static/assets/{browser-modal-DT5zGtM2.js → browser-modal-vnePkRfO.js} +2 -2
- package/static/assets/{card-CjY6k9qN.js → card-CuQs3dpy.js} +1 -1
- package/static/assets/{chevron-left-DiMUBSvf.js → chevron-left-QZIoYcVa.js} +1 -1
- package/static/assets/{plus-BCs8PAn6.js → chevron-up-DreyvhRd.js} +2 -2
- package/static/assets/{chevrons-up-CKVPmJ25.js → chevrons-up-CsAkc9vE.js} +1 -1
- package/static/assets/{circle-alert-Bc4Eo-aL.js → circle-alert-ewz28SE3.js} +1 -1
- package/static/assets/{circle-check-C8DZc7FJ.js → circle-check-2TuD-EHs.js} +1 -1
- package/static/assets/{circle-check-big-D_PvuS7-.js → circle-check-big-1xNuBPkR.js} +1 -1
- package/static/assets/{circle-play-Ba60SPvN.js → circle-play-C_w-qCn4.js} +1 -1
- package/static/assets/{circle-x-BYe1-ctZ.js → circle-x-B_d4wjG-.js} +1 -1
- package/static/assets/{clipboard-DZHDxSAN.js → clipboard-B6vBm1BP.js} +1 -1
- package/static/assets/{clock-E0FNqZih.js → clock-BIzEsx1g.js} +1 -1
- package/static/assets/{download-DbHXGD3a.js → download-Dv-RIvKK.js} +1 -1
- package/static/assets/droid-GYYyVzN-.js +18 -0
- package/static/assets/external-link-Cr8wjV6X.js +6 -0
- package/static/assets/{eye-CvcvqrS0.js → eye-DN958vyL.js} +1 -1
- package/static/assets/{folder-git-2-DK9b1q2x.js → folder-git-2-BproRzAR.js} +1 -1
- package/static/assets/index-Co_SJV3n.js +472 -0
- package/static/assets/index-GFQ5RqVh.css +2 -0
- package/static/assets/info-CzKk8mbR.js +6 -0
- package/static/assets/{label-DGhQh35t.js → label-h5GIKGcJ.js} +1 -1
- package/static/assets/{markdown-editor-52vxb0rp.js → markdown-editor-C6il4XWv.js} +1 -1
- package/static/assets/{pause-B7dyLcuH.js → pause-BDsjEmXM.js} +1 -1
- package/static/assets/{play-C3zkOZiK.js → play-CGsVQUJG.js} +1 -1
- package/static/assets/{radio-group-BseQ4OVV.js → radio-group-Bsd75ahK.js} +1 -1
- package/static/assets/{refresh-cw-ucF4I6xx.js → refresh-cw-qE1iNkL_.js} +1 -1
- package/static/assets/{search-TqAjHy3_.js → search-dvi0J4Dr.js} +1 -1
- package/static/assets/select-DylRS99W.js +1 -0
- package/static/assets/status-utils-CDkPeVfP.js +1 -0
- package/static/assets/{switch-B6px80Oh.js → switch-CsB3wpq9.js} +1 -1
- package/static/assets/{tabs-BHSWuVOa.js → tabs-Bw_4k2Rs.js} +1 -1
- package/static/assets/{tag-DjI_1POr.js → tag-Dh5PraRd.js} +1 -1
- package/static/assets/{terminal-preview-C0DTE3G7.js → terminal-preview-CfOb7xMx.js} +1 -1
- package/static/assets/use-terminal-T_tdJTCU.js +1 -0
- package/static/assets/video-bO6uuAjA.js +36 -0
- package/static/assets/{zap-DruahTJJ.js → zap-DHZ91NcK.js} +1 -1
- package/static/index.html +2 -2
- package/static/assets/AgentDetailPage-BJD22FSv.js +0 -1
- package/static/assets/AgentEditPage-ZYd0Rode.js +0 -1
- package/static/assets/AgentsPage-CUuxxQ2o.js +0 -3
- package/static/assets/AgentsSettingsPage-Dd8MrsKx.js +0 -6
- package/static/assets/ApiKeysSettingsPage-DTZStkII.js +0 -7
- package/static/assets/CodePage-xpXX0hlR.js +0 -2
- package/static/assets/DashboardPage-DQFlhP54.js +0 -41
- package/static/assets/GitSettingsPage-vLNJs4r3.js +0 -6
- package/static/assets/IdentityPage-ZAp_iARt.js +0 -11
- package/static/assets/IntegrationsSettingsPage-CqWZ8GUI.js +0 -1
- package/static/assets/JobDetailPage-BWq4XLO2.js +0 -1
- package/static/assets/KnowledgeDetailPage-C8evStGp.js +0 -1
- package/static/assets/KnowledgeEditPage-DquJprU_.js +0 -1
- package/static/assets/KnowledgePage-BBUKBhzS.js +0 -8
- package/static/assets/McpSettingsPage-BGIEripM.js +0 -1
- package/static/assets/NewAgentPage-D9hL7NY6.js +0 -1
- package/static/assets/NewKnowledgePage-CEdd8Yns.js +0 -9
- package/static/assets/NewProposalPage-B152OXnT.js +0 -90
- package/static/assets/ProjectEditPage-D0uSaGy0.js +0 -11
- package/static/assets/ProjectPage-DzWJky4Y.js +0 -1
- package/static/assets/PromptsSettingsPage-DH-4vcbF.js +0 -1
- package/static/assets/ProposalDetailPage-BI5HDp5I.js +0 -1
- package/static/assets/ProposalEditPage-D4412azZ.js +0 -1
- package/static/assets/ProposalsPage-D2gMbCBV.js +0 -17
- package/static/assets/ResourcesPage-7tbvXxDb.js +0 -71
- package/static/assets/SchedulePage-Crd-VMiL.js +0 -4
- package/static/assets/SourceInput-fvbAHpzT.js +0 -1
- package/static/assets/TerminalPage-BGZJDqvR.js +0 -1
- package/static/assets/TerminalSessionPage-DILvcnLG.js +0 -13
- package/static/assets/UserPreferencesPage-ChHrBs8H.js +0 -1
- package/static/assets/UserSettingsPage-Cv60YInV.js +0 -1
- package/static/assets/UtilitiesPage-ChLTn_u9.js +0 -1
- package/static/assets/calendar-sFw_mHQb.js +0 -6
- package/static/assets/droid-Caom7ttu.js +0 -4
- package/static/assets/index-C4LGSoHO.js +0 -468
- package/static/assets/index-CzjbtPHw.css +0 -2
- package/static/assets/use-terminal-KpWB08HL.js +0 -1
|
@@ -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 @@
|
|
|
1
|
+
export { default } from './route.js';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default } from './route.js';
|
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
import { Hono } from 'hono';
|
|
2
|
+
import { promises as fs } from 'fs';
|
|
3
|
+
import path from 'path';
|
|
4
|
+
import matter from 'gray-matter';
|
|
5
|
+
const app = new Hono();
|
|
6
|
+
function generateSkillId(name) {
|
|
7
|
+
return name
|
|
8
|
+
.toLowerCase()
|
|
9
|
+
.replace(/[^a-z0-9\s-]/g, '')
|
|
10
|
+
.replace(/\s+/g, '-')
|
|
11
|
+
.replace(/--+/g, '-')
|
|
12
|
+
.replace(/^-|-$/g, '');
|
|
13
|
+
}
|
|
14
|
+
function getSkillsPath() {
|
|
15
|
+
let basePath;
|
|
16
|
+
if (process.env.NODE_ENV === 'development' && process.env.GAIT_DEV_ROOT) {
|
|
17
|
+
basePath = process.env.GAIT_DEV_ROOT;
|
|
18
|
+
}
|
|
19
|
+
else if (process.env.GAIT_DATA_PATH) {
|
|
20
|
+
basePath = path.resolve(process.env.GAIT_DATA_PATH, '.nut');
|
|
21
|
+
}
|
|
22
|
+
else {
|
|
23
|
+
basePath = path.resolve(process.cwd(), '.nut');
|
|
24
|
+
}
|
|
25
|
+
return path.join(basePath, 'skills');
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* GET /api/v1/skills/:id
|
|
29
|
+
* Load a specific skill document
|
|
30
|
+
*/
|
|
31
|
+
app.get('/', async (c) => {
|
|
32
|
+
try {
|
|
33
|
+
const id = c.req.param('id');
|
|
34
|
+
const skillsPath = getSkillsPath();
|
|
35
|
+
const skillFile = path.join(skillsPath, id, 'SKILL.md');
|
|
36
|
+
const fileContent = await fs.readFile(skillFile, 'utf-8');
|
|
37
|
+
const { data, content } = matter(fileContent);
|
|
38
|
+
const nestedMeta = typeof data.metadata === 'object' ? data.metadata : undefined;
|
|
39
|
+
const document = {
|
|
40
|
+
id,
|
|
41
|
+
name: data.name || id,
|
|
42
|
+
description: data.description || '',
|
|
43
|
+
license: data.license,
|
|
44
|
+
compatibility: data.compatibility,
|
|
45
|
+
allowedTools: data['allowed-tools'] || data.allowedTools,
|
|
46
|
+
metadata: {
|
|
47
|
+
name: data.name || id,
|
|
48
|
+
description: data.description || '',
|
|
49
|
+
license: data.license,
|
|
50
|
+
compatibility: data.compatibility,
|
|
51
|
+
allowedTools: data['allowed-tools'] || data.allowedTools,
|
|
52
|
+
...(nestedMeta || {}),
|
|
53
|
+
metadata: nestedMeta,
|
|
54
|
+
},
|
|
55
|
+
content,
|
|
56
|
+
};
|
|
57
|
+
return c.json({
|
|
58
|
+
success: true,
|
|
59
|
+
document
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
catch (error) {
|
|
63
|
+
if (error.code === 'ENOENT') {
|
|
64
|
+
return c.json({ success: false, error: 'Skill document not found' }, 404);
|
|
65
|
+
}
|
|
66
|
+
console.error('Error loading skill document:', error);
|
|
67
|
+
return c.json({ success: false, error: 'Failed to load skill document' }, 500);
|
|
68
|
+
}
|
|
69
|
+
});
|
|
70
|
+
/**
|
|
71
|
+
* PUT /api/v1/skills/:id
|
|
72
|
+
* Update a specific skill document
|
|
73
|
+
*/
|
|
74
|
+
app.put('/', async (c) => {
|
|
75
|
+
try {
|
|
76
|
+
const id = c.req.param('id');
|
|
77
|
+
const body = await c.req.json();
|
|
78
|
+
const skillsPath = getSkillsPath();
|
|
79
|
+
const skillDir = path.join(skillsPath, id);
|
|
80
|
+
const skillFile = path.join(skillDir, 'SKILL.md');
|
|
81
|
+
// Check if skill exists
|
|
82
|
+
try {
|
|
83
|
+
await fs.access(skillFile);
|
|
84
|
+
}
|
|
85
|
+
catch {
|
|
86
|
+
return c.json({ success: false, error: 'Skill document not found' }, 404);
|
|
87
|
+
}
|
|
88
|
+
// Read current content
|
|
89
|
+
const currentContent = await fs.readFile(skillFile, 'utf-8');
|
|
90
|
+
const { data: currentData, content: currentMarkdown } = matter(currentContent);
|
|
91
|
+
// Merge updates
|
|
92
|
+
const updatedContent = body.content !== undefined ? body.content : currentMarkdown;
|
|
93
|
+
const updatedDescription = body.description !== undefined ? body.description : (currentData.description || '');
|
|
94
|
+
const updatedLicense = body.license !== undefined ? body.license : currentData.license;
|
|
95
|
+
const updatedCompatibility = body.compatibility !== undefined ? body.compatibility : currentData.compatibility;
|
|
96
|
+
const updatedAllowedTools = body.allowedTools !== undefined ? body.allowedTools : (currentData['allowed-tools'] || currentData.allowedTools);
|
|
97
|
+
// Merge metadata
|
|
98
|
+
const currentMeta = typeof currentData.metadata === 'object' && currentData.metadata !== null ? currentData.metadata : {};
|
|
99
|
+
const updatedMeta = body.metadata
|
|
100
|
+
? { ...currentMeta, ...body.metadata }
|
|
101
|
+
: currentMeta;
|
|
102
|
+
// Handle name change (directory rename)
|
|
103
|
+
let newId = id;
|
|
104
|
+
let newDir = skillDir;
|
|
105
|
+
if (body.name && body.name !== currentData.name) {
|
|
106
|
+
newId = generateSkillId(body.name);
|
|
107
|
+
newDir = path.join(skillsPath, newId);
|
|
108
|
+
if (newId !== id) {
|
|
109
|
+
try {
|
|
110
|
+
await fs.access(path.join(newDir, 'SKILL.md'));
|
|
111
|
+
return c.json({ success: false, error: 'A skill with this name already exists' }, 409);
|
|
112
|
+
}
|
|
113
|
+
catch {
|
|
114
|
+
// Doesn't exist, proceed with rename
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
// Build updated frontmatter
|
|
119
|
+
const frontmatter = {
|
|
120
|
+
name: newId,
|
|
121
|
+
description: updatedDescription,
|
|
122
|
+
};
|
|
123
|
+
if (updatedLicense)
|
|
124
|
+
frontmatter.license = updatedLicense;
|
|
125
|
+
if (updatedCompatibility)
|
|
126
|
+
frontmatter.compatibility = updatedCompatibility;
|
|
127
|
+
if (updatedAllowedTools)
|
|
128
|
+
frontmatter['allowed-tools'] = updatedAllowedTools;
|
|
129
|
+
// Clean metadata
|
|
130
|
+
const cleanMeta = {};
|
|
131
|
+
for (const [key, value] of Object.entries(updatedMeta)) {
|
|
132
|
+
if (value !== undefined && value !== null) {
|
|
133
|
+
cleanMeta[key] = value;
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
if (Object.keys(cleanMeta).length > 0) {
|
|
137
|
+
frontmatter.metadata = cleanMeta;
|
|
138
|
+
}
|
|
139
|
+
const fileContent = matter.stringify(updatedContent, frontmatter);
|
|
140
|
+
if (newId !== id) {
|
|
141
|
+
// Create new directory and write file
|
|
142
|
+
await fs.mkdir(newDir, { recursive: true });
|
|
143
|
+
await fs.writeFile(path.join(newDir, 'SKILL.md'), fileContent, 'utf-8');
|
|
144
|
+
// Remove old directory
|
|
145
|
+
await fs.rm(skillDir, { recursive: true, force: true });
|
|
146
|
+
}
|
|
147
|
+
else {
|
|
148
|
+
await fs.writeFile(skillFile, fileContent, 'utf-8');
|
|
149
|
+
}
|
|
150
|
+
return c.json({
|
|
151
|
+
success: true,
|
|
152
|
+
document: {
|
|
153
|
+
id: newId,
|
|
154
|
+
name: newId,
|
|
155
|
+
description: updatedDescription,
|
|
156
|
+
metadata: {
|
|
157
|
+
name: newId,
|
|
158
|
+
description: updatedDescription,
|
|
159
|
+
...frontmatter,
|
|
160
|
+
...(typeof cleanMeta === 'object' ? cleanMeta : {}),
|
|
161
|
+
},
|
|
162
|
+
content: updatedContent
|
|
163
|
+
}
|
|
164
|
+
});
|
|
165
|
+
}
|
|
166
|
+
catch (error) {
|
|
167
|
+
console.error('Error updating skill document:', error);
|
|
168
|
+
return c.json({ success: false, error: 'Failed to update skill document' }, 500);
|
|
169
|
+
}
|
|
170
|
+
});
|
|
171
|
+
/**
|
|
172
|
+
* DELETE /api/v1/skills/:id
|
|
173
|
+
* Delete a specific skill document (removes entire skill directory)
|
|
174
|
+
*/
|
|
175
|
+
app.delete('/', async (c) => {
|
|
176
|
+
try {
|
|
177
|
+
const id = c.req.param('id');
|
|
178
|
+
const skillsPath = getSkillsPath();
|
|
179
|
+
const skillDir = path.join(skillsPath, id);
|
|
180
|
+
// Check if skill exists
|
|
181
|
+
try {
|
|
182
|
+
await fs.access(path.join(skillDir, 'SKILL.md'));
|
|
183
|
+
}
|
|
184
|
+
catch {
|
|
185
|
+
return c.json({ success: false, error: 'Skill document not found' }, 404);
|
|
186
|
+
}
|
|
187
|
+
// Remove entire skill directory
|
|
188
|
+
await fs.rm(skillDir, { recursive: true, force: true });
|
|
189
|
+
return c.json({
|
|
190
|
+
success: true,
|
|
191
|
+
message: 'Skill document deleted successfully'
|
|
192
|
+
});
|
|
193
|
+
}
|
|
194
|
+
catch (error) {
|
|
195
|
+
console.error('Error deleting skill document:', error);
|
|
196
|
+
return c.json({ success: false, error: 'Failed to delete skill document' }, 500);
|
|
197
|
+
}
|
|
198
|
+
});
|
|
199
|
+
export default app;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default } from './route.js';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default } from './route.js';
|