@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.
Files changed (179) hide show
  1. package/dist/lib/auth/auth-manager.d.ts +5 -0
  2. package/dist/lib/auth/auth-manager.js +9 -0
  3. package/dist/lib/storage/file-storage.d.ts +16 -16
  4. package/dist/lib/storage/file-storage.js +84 -79
  5. package/dist/lib/terminal/terminal-manager.d.ts +3 -5
  6. package/dist/lib/terminal/terminal-manager.js +19 -63
  7. package/dist/middleware/auth.js +36 -0
  8. package/dist/routes/api/v1/ai/index.js +0 -2
  9. package/dist/routes/api/v1/ai/route.js +445 -259
  10. package/dist/routes/api/v1/chats/[id]/index.js +2 -1
  11. package/dist/routes/api/v1/chats/[id]/route.d.ts +7 -0
  12. package/dist/routes/api/v1/chats/[id]/route.js +30 -1
  13. package/dist/routes/api/v1/context/index.js +0 -2
  14. package/dist/routes/api/v1/events/route.js +1 -1
  15. package/dist/routes/api/v1/knowledge/[filename]/index.d.ts +1 -0
  16. package/dist/routes/api/v1/knowledge/[filename]/index.js +1 -0
  17. package/dist/routes/api/v1/knowledge/[filename]/route.d.ts +3 -0
  18. package/dist/routes/api/v1/knowledge/[filename]/route.js +254 -0
  19. package/dist/routes/api/v1/knowledge/index.d.ts +1 -0
  20. package/dist/routes/api/v1/knowledge/index.js +1 -0
  21. package/dist/routes/api/v1/knowledge/route.d.ts +3 -0
  22. package/dist/routes/api/v1/knowledge/route.js +176 -0
  23. package/dist/routes/api/v1/mcp/index.js +109 -34
  24. package/dist/routes/api/v1/skills/[id]/index.d.ts +1 -0
  25. package/dist/routes/api/v1/skills/[id]/index.js +1 -0
  26. package/dist/routes/api/v1/skills/[id]/route.d.ts +3 -0
  27. package/dist/routes/api/v1/skills/[id]/route.js +199 -0
  28. package/dist/routes/api/v1/skills/index.d.ts +1 -0
  29. package/dist/routes/api/v1/skills/index.js +1 -0
  30. package/dist/routes/api/v1/skills/route.d.ts +3 -0
  31. package/dist/routes/api/v1/skills/route.js +329 -0
  32. package/dist/routes/api/v1/tasks/[id]/route.d.ts +351 -0
  33. package/dist/routes/api/v1/tasks/[id]/route.js +156 -0
  34. package/dist/routes/api/v1/tasks/index.d.ts +3 -0
  35. package/dist/routes/api/v1/tasks/index.js +10 -0
  36. package/dist/routes/api/v1/tasks/route.d.ts +329 -0
  37. package/dist/routes/api/v1/tasks/route.js +126 -0
  38. package/dist/routes/api/v1/terminal/[proposalId]/create/route.js +2 -2
  39. package/dist/routes/api/v1/terminal/[taskId]/create/index.d.ts +3 -0
  40. package/dist/routes/api/v1/terminal/[taskId]/create/index.js +5 -0
  41. package/dist/routes/api/v1/terminal/[taskId]/create/route.d.ts +10 -0
  42. package/dist/routes/api/v1/terminal/[taskId]/create/route.js +27 -0
  43. package/dist/routes/api/v1/terminal/[taskId]/destroy/index.d.ts +3 -0
  44. package/dist/routes/api/v1/terminal/[taskId]/destroy/index.js +5 -0
  45. package/dist/routes/api/v1/terminal/[taskId]/destroy/route.d.ts +10 -0
  46. package/dist/routes/api/v1/terminal/[taskId]/destroy/route.js +21 -0
  47. package/dist/routes/api/v1/terminal/[taskId]/resize/index.d.ts +3 -0
  48. package/dist/routes/api/v1/terminal/[taskId]/resize/index.js +5 -0
  49. package/dist/routes/api/v1/terminal/[taskId]/resize/route.d.ts +10 -0
  50. package/dist/routes/api/v1/terminal/[taskId]/resize/route.js +21 -0
  51. package/dist/routes/api/v1/terminal/sessions/route.js +4 -4
  52. package/dist/server-with-static.js +18 -14
  53. package/dist/server.js +15 -13
  54. package/package.json +8 -4
  55. package/static/assets/{ActivityPage-Dl3u61DF.js → ActivityPage-CbmEnYhg.js} +1 -1
  56. package/static/assets/ApiKeysSettingsPage-DLxQIqTT.js +2 -0
  57. package/static/assets/{ArchitectureEditPage-CVxBD88N.js → ArchitectureEditPage-CbtzgIQv.js} +4 -4
  58. package/static/assets/{ArchitecturePage-GchbFR8L.js → ArchitecturePage-CcAMfFZ8.js} +1 -1
  59. package/static/assets/{AuthSettingsPage-B7a-i1_T.js → AuthSettingsPage-4Prb7nAt.js} +2 -2
  60. package/static/assets/{CallbackPage-xYgfYT1Z.js → CallbackPage-CmWv_5Nh.js} +1 -1
  61. package/static/assets/CodePage-COC7rcwM.js +2 -0
  62. package/static/assets/{CollapsibleSection-ka7CEJhS.js → CollapsibleSection-C_VVeVSc.js} +1 -1
  63. package/static/assets/DashboardPage-BACFVIaW.js +41 -0
  64. package/static/assets/{GitPage-B-aSKe9Z.js → GitPage-rFngEr_A.js} +2 -2
  65. package/static/assets/GitSettingsPage-CDQovOqx.js +6 -0
  66. package/static/assets/IdentityPage-CS4REq2E.js +11 -0
  67. package/static/assets/{ImplementationStepsEditor-BC8bzHNj.js → ImplementationStepsEditor-CBIgppkZ.js} +2 -2
  68. package/static/assets/IntegrationsSettingsPage-B7HoraBH.js +1 -0
  69. package/static/assets/JobDetailPage-QUhWsaWV.js +1 -0
  70. package/static/assets/KnowledgeDetailPage-DCJstmIr.js +1 -0
  71. package/static/assets/KnowledgeEditPage-EYpFPfcJ.js +1 -0
  72. package/static/assets/KnowledgePage-D-7skvn5.js +8 -0
  73. package/static/assets/{LoginPage-Dp6lQSZW.js → LoginPage-L2aoqSDT.js} +1 -1
  74. package/static/assets/McpSettingsPage-CLwqDjw_.js +1 -0
  75. package/static/assets/NewKnowledgePage-Fq_QD8um.js +9 -0
  76. package/static/assets/NewSkillPage-DRcgovk0.js +1 -0
  77. package/static/assets/NewTaskPage-CleA8rH5.js +90 -0
  78. package/static/assets/ProjectEditPage-GIMOKgmh.js +11 -0
  79. package/static/assets/ProjectPage-DlWZOqnb.js +1 -0
  80. package/static/assets/PromptsSettingsPage-DFagGfo-.js +1 -0
  81. package/static/assets/ResourceDetailPage-CnFRpDec.js +1 -0
  82. package/static/assets/ResourcesPage-Cw3fu0JE.js +41 -0
  83. package/static/assets/{RoleEditPage-Ne8Dh8Tt.js → RoleEditPage-ARXq_eCs.js} +1 -1
  84. package/static/assets/{RolePage-3sb7lhw8.js → RolePage--XBBIrq8.js} +1 -1
  85. package/static/assets/{RulesSettingsPage-CEWEvNFC.js → RulesSettingsPage-DEqaRH96.js} +3 -3
  86. package/static/assets/SchedulePage-C_B2k9P6.js +4 -0
  87. package/static/assets/SkillDetailPage-Dr6xyKAX.js +1 -0
  88. package/static/assets/SkillEditPage-BsHXmfEZ.js +1 -0
  89. package/static/assets/SkillsPage-BrDdAAPx.js +8 -0
  90. package/static/assets/SkillsSettingsPage-Cvi7xaDE.js +1 -0
  91. package/static/assets/SourceInput-DxF_GGj8.js +1 -0
  92. package/static/assets/{TagInput-DRSgjTau.js → TagInput-DYvHbVZq.js} +1 -1
  93. package/static/assets/TaskDetailPage-DzcD6t03.js +1 -0
  94. package/static/assets/TaskEditPage-C7a6FOeJ.js +1 -0
  95. package/static/assets/TasksPage-ChWRSO_S.js +17 -0
  96. package/static/assets/TerminalPage-CoPwn8cU.js +1 -0
  97. package/static/assets/TerminalSessionPage-BQBZrOJa.js +13 -0
  98. package/static/assets/UserPreferencesPage-DjtU7veO.js +1 -0
  99. package/static/assets/UserSettingsPage-CfU8boJQ.js +1 -0
  100. package/static/assets/UtilitiesPage-sP1Crg-X.js +1 -0
  101. package/static/assets/{alert-CBWqAyb9.js → alert-BqZa-crG.js} +1 -1
  102. package/static/assets/{arrow-down-PY3QZW33.js → arrow-down-3faV_GyO.js} +1 -1
  103. package/static/assets/{arrow-left-JpEq5x30.js → arrow-left-FD3wQmzH.js} +1 -1
  104. package/static/assets/{arrow-up-qJ-_eNlY.js → arrow-up-BzP0YNVk.js} +1 -1
  105. package/static/assets/{badge-D6QJCkgl.js → badge-DRyeFib9.js} +1 -1
  106. package/static/assets/{browser-modal-DT5zGtM2.js → browser-modal-vnePkRfO.js} +2 -2
  107. package/static/assets/{card-CjY6k9qN.js → card-CuQs3dpy.js} +1 -1
  108. package/static/assets/{chevron-left-DiMUBSvf.js → chevron-left-QZIoYcVa.js} +1 -1
  109. package/static/assets/{plus-BCs8PAn6.js → chevron-up-DreyvhRd.js} +2 -2
  110. package/static/assets/{chevrons-up-CKVPmJ25.js → chevrons-up-CsAkc9vE.js} +1 -1
  111. package/static/assets/{circle-alert-Bc4Eo-aL.js → circle-alert-ewz28SE3.js} +1 -1
  112. package/static/assets/{circle-check-C8DZc7FJ.js → circle-check-2TuD-EHs.js} +1 -1
  113. package/static/assets/{circle-check-big-D_PvuS7-.js → circle-check-big-1xNuBPkR.js} +1 -1
  114. package/static/assets/{circle-play-Ba60SPvN.js → circle-play-C_w-qCn4.js} +1 -1
  115. package/static/assets/{circle-x-BYe1-ctZ.js → circle-x-B_d4wjG-.js} +1 -1
  116. package/static/assets/{clipboard-DZHDxSAN.js → clipboard-B6vBm1BP.js} +1 -1
  117. package/static/assets/{clock-E0FNqZih.js → clock-BIzEsx1g.js} +1 -1
  118. package/static/assets/{download-DbHXGD3a.js → download-Dv-RIvKK.js} +1 -1
  119. package/static/assets/droid-GYYyVzN-.js +18 -0
  120. package/static/assets/external-link-Cr8wjV6X.js +6 -0
  121. package/static/assets/{eye-CvcvqrS0.js → eye-DN958vyL.js} +1 -1
  122. package/static/assets/{folder-git-2-DK9b1q2x.js → folder-git-2-BproRzAR.js} +1 -1
  123. package/static/assets/index-Co_SJV3n.js +472 -0
  124. package/static/assets/index-GFQ5RqVh.css +2 -0
  125. package/static/assets/info-CzKk8mbR.js +6 -0
  126. package/static/assets/{label-DGhQh35t.js → label-h5GIKGcJ.js} +1 -1
  127. package/static/assets/{markdown-editor-52vxb0rp.js → markdown-editor-C6il4XWv.js} +1 -1
  128. package/static/assets/{pause-B7dyLcuH.js → pause-BDsjEmXM.js} +1 -1
  129. package/static/assets/{play-C3zkOZiK.js → play-CGsVQUJG.js} +1 -1
  130. package/static/assets/{radio-group-BseQ4OVV.js → radio-group-Bsd75ahK.js} +1 -1
  131. package/static/assets/{refresh-cw-ucF4I6xx.js → refresh-cw-qE1iNkL_.js} +1 -1
  132. package/static/assets/{search-TqAjHy3_.js → search-dvi0J4Dr.js} +1 -1
  133. package/static/assets/select-DylRS99W.js +1 -0
  134. package/static/assets/status-utils-CDkPeVfP.js +1 -0
  135. package/static/assets/{switch-B6px80Oh.js → switch-CsB3wpq9.js} +1 -1
  136. package/static/assets/{tabs-BHSWuVOa.js → tabs-Bw_4k2Rs.js} +1 -1
  137. package/static/assets/{tag-DjI_1POr.js → tag-Dh5PraRd.js} +1 -1
  138. package/static/assets/{terminal-preview-C0DTE3G7.js → terminal-preview-CfOb7xMx.js} +1 -1
  139. package/static/assets/use-terminal-T_tdJTCU.js +1 -0
  140. package/static/assets/video-bO6uuAjA.js +36 -0
  141. package/static/assets/{zap-DruahTJJ.js → zap-DHZ91NcK.js} +1 -1
  142. package/static/index.html +2 -2
  143. package/static/assets/AgentDetailPage-BJD22FSv.js +0 -1
  144. package/static/assets/AgentEditPage-ZYd0Rode.js +0 -1
  145. package/static/assets/AgentsPage-CUuxxQ2o.js +0 -3
  146. package/static/assets/AgentsSettingsPage-Dd8MrsKx.js +0 -6
  147. package/static/assets/ApiKeysSettingsPage-DTZStkII.js +0 -7
  148. package/static/assets/CodePage-xpXX0hlR.js +0 -2
  149. package/static/assets/DashboardPage-DQFlhP54.js +0 -41
  150. package/static/assets/GitSettingsPage-vLNJs4r3.js +0 -6
  151. package/static/assets/IdentityPage-ZAp_iARt.js +0 -11
  152. package/static/assets/IntegrationsSettingsPage-CqWZ8GUI.js +0 -1
  153. package/static/assets/JobDetailPage-BWq4XLO2.js +0 -1
  154. package/static/assets/KnowledgeDetailPage-C8evStGp.js +0 -1
  155. package/static/assets/KnowledgeEditPage-DquJprU_.js +0 -1
  156. package/static/assets/KnowledgePage-BBUKBhzS.js +0 -8
  157. package/static/assets/McpSettingsPage-BGIEripM.js +0 -1
  158. package/static/assets/NewAgentPage-D9hL7NY6.js +0 -1
  159. package/static/assets/NewKnowledgePage-CEdd8Yns.js +0 -9
  160. package/static/assets/NewProposalPage-B152OXnT.js +0 -90
  161. package/static/assets/ProjectEditPage-D0uSaGy0.js +0 -11
  162. package/static/assets/ProjectPage-DzWJky4Y.js +0 -1
  163. package/static/assets/PromptsSettingsPage-DH-4vcbF.js +0 -1
  164. package/static/assets/ProposalDetailPage-BI5HDp5I.js +0 -1
  165. package/static/assets/ProposalEditPage-D4412azZ.js +0 -1
  166. package/static/assets/ProposalsPage-D2gMbCBV.js +0 -17
  167. package/static/assets/ResourcesPage-7tbvXxDb.js +0 -71
  168. package/static/assets/SchedulePage-Crd-VMiL.js +0 -4
  169. package/static/assets/SourceInput-fvbAHpzT.js +0 -1
  170. package/static/assets/TerminalPage-BGZJDqvR.js +0 -1
  171. package/static/assets/TerminalSessionPage-DILvcnLG.js +0 -13
  172. package/static/assets/UserPreferencesPage-ChHrBs8H.js +0 -1
  173. package/static/assets/UserSettingsPage-Cv60YInV.js +0 -1
  174. package/static/assets/UtilitiesPage-ChLTn_u9.js +0 -1
  175. package/static/assets/calendar-sFw_mHQb.js +0 -6
  176. package/static/assets/droid-Caom7ttu.js +0 -4
  177. package/static/assets/index-C4LGSoHO.js +0 -468
  178. package/static/assets/index-CzjbtPHw.css +0 -2
  179. 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 { listProposals, getProposal, createProposal, updateProposal, deleteProposal, getContext, updateContext, appendContext, replaceContextSection, listKnowledge, getKnowledge, createKnowledge, updateKnowledge, listEvents, } from '@lovelybunch/core';
6
- import { proposalsFullTool, knowledgeTool, normalizeKnowledgeMetadata, eventsTool, projectContextTool, architectureContextTool, roleContextTool } from '@lovelybunch/mcp';
5
+ import { listTasks, getTask, createTask, updateTask, deleteTask, getContext, updateContext, appendContext, replaceContextSection, listKnowledge, getKnowledge, createKnowledge, updateKnowledge, listEvents, } from '@lovelybunch/core';
6
+ import { tasksFullTool, knowledgeTool, normalizeKnowledgeMetadata, eventsTool, projectContextTool, architectureContextTool, roleContextTool, resourcesTool } from '@lovelybunch/mcp';
7
7
  import { FileStorageAdapter } from '../../../../lib/storage/file-storage.js';
8
8
  const app = new Hono();
9
9
  const storage = new FileStorageAdapter();
@@ -78,14 +78,15 @@ app.get('/', async (c) => {
78
78
  }
79
79
  const names = Object.keys(externalServers);
80
80
  // Add built-in tools (include full JSON schema for parameters)
81
- // Note: proposals now supports full CRUD, knowledge/project/architecture are read+write, events is read-only
81
+ // Note: tasks now supports full CRUD, knowledge/project/architecture are read+write, events is read-only
82
82
  const builtInTools = {
83
- change_proposals: proposalsFullTool,
83
+ tasks: tasksFullTool,
84
84
  knowledge_documents: knowledgeTool,
85
85
  activity_events: eventsTool,
86
86
  project_context: projectContextTool,
87
87
  architecture_context: architectureContextTool,
88
- role_context: roleContextTool
88
+ role_context: roleContextTool,
89
+ resources: resourcesTool
89
90
  };
90
91
  return c.json({
91
92
  success: true,
@@ -105,15 +106,16 @@ app.get('/', async (c) => {
105
106
  */
106
107
  app.get('/schema', async (c) => {
107
108
  try {
108
- // Note: proposals now supports full CRUD, knowledge/project/architecture are read+write, events is read-only
109
+ // Note: tasks now supports full CRUD, knowledge/project/architecture are read+write, events is read-only
109
110
  const schema = {
110
111
  tools: {
111
- change_proposals: proposalsFullTool,
112
+ tasks: tasksFullTool,
112
113
  knowledge_documents: knowledgeTool,
113
114
  activity_events: eventsTool,
114
115
  project_context: projectContextTool,
115
116
  architecture_context: architectureContextTool,
116
- role_context: roleContextTool
117
+ role_context: roleContextTool,
118
+ resources: resourcesTool
117
119
  }
118
120
  };
119
121
  return c.json(schema);
@@ -133,8 +135,8 @@ app.post('/execute', async (c) => {
133
135
  if (!tool || !args) {
134
136
  return c.json({ success: false, error: 'Tool and arguments are required' }, 400);
135
137
  }
136
- if (tool === 'change_proposals') {
137
- return await executeProposalsTool(c, args);
138
+ if (tool === 'tasks') {
139
+ return await executeTasksTool(c, args);
138
140
  }
139
141
  if (tool === 'knowledge_documents') {
140
142
  return await executeKnowledgeTool(c, args);
@@ -151,6 +153,9 @@ app.post('/execute', async (c) => {
151
153
  if (tool === 'role_context') {
152
154
  return await executeRoleContextTool(c, args);
153
155
  }
156
+ if (tool === 'resources') {
157
+ return await executeResourcesTool(c, args);
158
+ }
154
159
  return c.json({ success: false, error: 'Unknown tool' }, 400);
155
160
  }
156
161
  catch (error) {
@@ -158,71 +163,71 @@ app.post('/execute', async (c) => {
158
163
  return c.json({ success: false, error: 'Tool execution failed' }, 500);
159
164
  }
160
165
  });
161
- // Proposals tool - full CRUD operations using @lovelybunch/core
162
- async function executeProposalsTool(c, args) {
163
- const { operation, id, filters, proposal, updates } = args;
166
+ // Tasks tool - full CRUD operations using @lovelybunch/core
167
+ async function executeTasksTool(c, args) {
168
+ const { operation, id, filters, task, updates } = args;
164
169
  try {
165
170
  switch (operation) {
166
171
  case 'list': {
167
- const proposals = await listProposals(filters || {});
172
+ const tasks = await listTasks(filters || {});
168
173
  return c.json({
169
174
  success: true,
170
- data: proposals,
171
- count: proposals.length,
172
- message: `Found ${proposals.length} proposals`
175
+ data: tasks,
176
+ count: tasks.length,
177
+ message: `Found ${tasks.length} tasks`
173
178
  });
174
179
  }
175
180
  case 'get': {
176
181
  if (!id) {
177
- return c.json({ success: false, error: 'Proposal ID is required for get operation' }, 400);
182
+ return c.json({ success: false, error: 'Task ID is required for get operation' }, 400);
178
183
  }
179
- const result = await getProposal(id);
184
+ const result = await getTask(id);
180
185
  if (!result) {
181
- return c.json({ success: false, error: 'Proposal not found' }, 404);
186
+ return c.json({ success: false, error: 'Task not found' }, 404);
182
187
  }
183
188
  return c.json({
184
189
  success: true,
185
190
  data: result,
186
- message: `Retrieved proposal ${id}`
191
+ message: `Retrieved task ${id}`
187
192
  });
188
193
  }
189
194
  case 'create': {
190
- if (!proposal) {
191
- return c.json({ success: false, error: 'Proposal data is required for create operation' }, 400);
195
+ if (!task) {
196
+ return c.json({ success: false, error: 'Task data is required for create operation' }, 400);
192
197
  }
193
- const created = await createProposal(proposal);
198
+ const created = await createTask(task);
194
199
  return c.json({
195
200
  success: true,
196
201
  data: created,
197
- message: `Created proposal ${created.id}`
202
+ message: `Created task ${created.id}`
198
203
  }, 201);
199
204
  }
200
205
  case 'update': {
201
206
  if (!id) {
202
- return c.json({ success: false, error: 'Proposal ID is required for update operation' }, 400);
207
+ return c.json({ success: false, error: 'Task ID is required for update operation' }, 400);
203
208
  }
204
- const updateData = updates || proposal;
209
+ const updateData = updates || task;
205
210
  if (!updateData) {
206
211
  return c.json({ success: false, error: 'Update data is required for update operation' }, 400);
207
212
  }
208
- const updated = await updateProposal(id, updateData);
213
+ const updated = await updateTask(id, updateData);
209
214
  return c.json({
210
215
  success: true,
211
216
  data: updated,
212
- message: `Updated proposal ${id}`
217
+ message: `Updated task ${id}`
213
218
  });
214
219
  }
215
220
  case 'delete': {
216
221
  if (!id) {
217
- return c.json({ success: false, error: 'Proposal ID is required for delete operation' }, 400);
222
+ return c.json({ success: false, error: 'Task ID is required for delete operation' }, 400);
218
223
  }
219
- const deleted = await deleteProposal(id);
224
+ const deleted = await deleteTask(id);
220
225
  if (!deleted) {
221
- return c.json({ success: false, error: 'Proposal not found' }, 404);
226
+ return c.json({ success: false, error: 'Task not found' }, 404);
222
227
  }
223
228
  return c.json({
224
229
  success: true,
225
- message: `Deleted proposal ${id}`
230
+ message: `Deleted task ${id}`
226
231
  });
227
232
  }
228
233
  default:
@@ -244,7 +249,7 @@ async function executeProposalsTool(c, args) {
244
249
  }))
245
250
  }, 400);
246
251
  }
247
- console.error('Error executing proposals tool:', error);
252
+ console.error('Error executing tasks tool:', error);
248
253
  return c.json({ success: false, error: error.message || 'Tool execution failed' }, 500);
249
254
  }
250
255
  }
@@ -449,6 +454,76 @@ async function executeArchitectureContextTool(c, args) {
449
454
  async function executeRoleContextTool(c, args) {
450
455
  return executeContextTool(c, 'role', args);
451
456
  }
457
+ // Resources tool executor — proxies to the resource API endpoints on the same server
458
+ async function executeResourcesTool(c, args) {
459
+ const { operation, query, type_filter, resource_id, prompt, model, aspect_ratio, text, voice, duration, resolution, url, tags, description } = args;
460
+ const port = process.env.PORT ? parseInt(process.env.PORT) : 3001;
461
+ const apiBase = `http://127.0.0.1:${port}`;
462
+ try {
463
+ switch (operation) {
464
+ case 'list': {
465
+ const response = await fetch(`${apiBase}/api/v1/resources`);
466
+ const result = await response.json();
467
+ if (!result.success || !result.data) {
468
+ return c.json({ success: false, error: 'Failed to list resources' }, 500);
469
+ }
470
+ let resources = result.data;
471
+ if (type_filter) {
472
+ const prefix = type_filter.toLowerCase();
473
+ resources = resources.filter((r) => r.type?.toLowerCase().startsWith(prefix));
474
+ }
475
+ if (query) {
476
+ const q = query.toLowerCase();
477
+ resources = resources.filter((r) => r.name?.toLowerCase().includes(q) ||
478
+ r.metadata?.description?.toLowerCase().includes(q) ||
479
+ r.metadata?.tags?.some((tag) => tag.toLowerCase().includes(q)));
480
+ }
481
+ return c.json({
482
+ success: true,
483
+ data: resources.map((r) => ({
484
+ id: r.id, name: r.name, type: r.type, size: r.size,
485
+ tags: r.metadata?.tags, description: r.metadata?.description
486
+ })),
487
+ count: resources.length,
488
+ message: query ? `Found ${resources.length} resources matching "${query}"` : `Found ${resources.length} resources`
489
+ });
490
+ }
491
+ case 'get': {
492
+ if (!resource_id) {
493
+ return c.json({ success: false, error: 'resource_id is required for get operation' }, 400);
494
+ }
495
+ const response = await fetch(`${apiBase}/api/v1/resources`);
496
+ const result = await response.json();
497
+ if (!result.success || !result.data) {
498
+ return c.json({ success: false, error: 'Failed to fetch resources' }, 500);
499
+ }
500
+ const resource = result.data.find((r) => r.id === resource_id);
501
+ if (!resource) {
502
+ return c.json({ success: false, error: `Resource '${resource_id}' not found` }, 404);
503
+ }
504
+ return c.json({ success: true, data: resource, message: `Retrieved resource ${resource.name}` });
505
+ }
506
+ // For write operations, return a not-implemented message since these require
507
+ // long-running Replicate calls that are better handled via the AI route's
508
+ // tool execution (which runs within streamText's tool loop).
509
+ case 'generate_image':
510
+ case 'generate_audio':
511
+ case 'generate_video':
512
+ case 'add_from_url': {
513
+ return c.json({
514
+ success: false,
515
+ error: `The '${operation}' operation is only available through the AI assistant chat. Use the assistant sidebar to generate or add resources.`
516
+ }, 400);
517
+ }
518
+ default:
519
+ return c.json({ success: false, error: `Unknown operation: ${operation}` }, 400);
520
+ }
521
+ }
522
+ catch (error) {
523
+ console.error('Error executing resources tool:', error);
524
+ return c.json({ success: false, error: error.message || 'Resources tool execution failed' }, 500);
525
+ }
526
+ }
452
527
  /**
453
528
  * GET /api/v1/mcp/raw-config
454
529
  * Returns the raw MCP configuration for editing in settings UI
@@ -0,0 +1 @@
1
+ export { default } from './route.js';
@@ -0,0 +1 @@
1
+ export { default } from './route.js';
@@ -0,0 +1,3 @@
1
+ import { Hono } from 'hono';
2
+ declare const app: Hono<import("hono/types").BlankEnv, import("hono/types").BlankSchema, "/">;
3
+ export default app;
@@ -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';
@@ -0,0 +1,3 @@
1
+ import { Hono } from 'hono';
2
+ declare const app: Hono<import("hono/types").BlankEnv, import("hono/types").BlankSchema, "/">;
3
+ export default app;