@lovelybunch/api 1.0.76-alpha.8 → 1.0.76

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 (185) hide show
  1. package/dist/lib/git.d.ts +3 -0
  2. package/dist/lib/git.js +35 -0
  3. package/dist/routes/api/v1/ai/route.js +214 -152
  4. package/dist/routes/api/v1/config/route.js +13 -9
  5. package/dist/routes/api/v1/context/agents/route.js +159 -0
  6. package/dist/routes/api/v1/context/index.js +6 -4
  7. package/dist/routes/api/v1/context/memory/route.js +163 -0
  8. package/dist/routes/api/v1/context/team/route.js +159 -0
  9. package/dist/routes/api/v1/git/index.js +27 -1
  10. package/dist/routes/api/v1/jobs/[id]/route.d.ts +26 -32
  11. package/dist/routes/api/v1/jobs/[id]/route.js +3 -3
  12. package/dist/routes/api/v1/jobs/route.d.ts +33 -33
  13. package/dist/routes/api/v1/jobs/route.js +17 -2
  14. package/dist/routes/api/v1/mcp/index.js +194 -21
  15. package/dist/routes/api/v1/resources/generate/route.js +10 -3
  16. package/package.json +4 -4
  17. package/static/assets/ActivityPage-sJEQn6DK.js +1 -0
  18. package/static/assets/AgentsContextEditPage-DU3qIXk9.js +9 -0
  19. package/static/assets/AgentsContextPage-tJ-LhFYb.js +1 -0
  20. package/static/assets/{ApiKeysSettingsPage-BhaH6ZYP.js → ApiKeysSettingsPage-Bg84BQHV.js} +2 -2
  21. package/static/assets/{AuthSettingsPage-D0MQlHyh.js → AuthSettingsPage-Bwr7uP3z.js} +1 -1
  22. package/static/assets/{CallbackPage-Bz4m3_W8.js → CallbackPage-BFn0Np2S.js} +1 -1
  23. package/static/assets/CodePage-kp4s3wCJ.js +2 -0
  24. package/static/assets/{CollapsibleSection-CxX11hr-.js → CollapsibleSection-CNs1mvsZ.js} +1 -1
  25. package/static/assets/{DashboardPage-B3HR1UM7.js → DashboardPage-DMJSzzgD.js} +9 -19
  26. package/static/assets/{GitPage-Dm36PRw_.js → GitPage-uqene8zj.js} +3 -3
  27. package/static/assets/{GitSettingsPage-CRWcjgVI.js → GitSettingsPage-CLswbZsT.js} +2 -2
  28. package/static/assets/{IdentityPage-YCkmdyzR.js → IdentityPage-BDTPXEo7.js} +2 -2
  29. package/static/assets/{ImplementationStepsEditor-u3dPxmKW.js → ImplementationStepsEditor-D4cvhPhz.js} +2 -2
  30. package/static/assets/IntegrationsSettingsPage-o7NXZGt9.js +1 -0
  31. package/static/assets/JobDetailPage-DuEiPz6X.js +1 -0
  32. package/static/assets/KnowledgeDetailPage-DFVud_VC.js +1 -0
  33. package/static/assets/{KnowledgeEditPage-DhrF6UPg.js → KnowledgeEditPage-XG6HKK7E.js} +1 -1
  34. package/static/assets/{KnowledgePage-_gZhpTe3.js → KnowledgePage-B2zI3xwW.js} +2 -2
  35. package/static/assets/{LoginPage-Cc1Ac2j4.js → LoginPage-CUJRxwXy.js} +1 -1
  36. package/static/assets/MailInboxPage-BlCG-tba.js +1 -0
  37. package/static/assets/MailProcessingModal-BJIdHOqK.js +1 -0
  38. package/static/assets/MailReadPage-MoNo_gmW.js +1 -0
  39. package/static/assets/{MailSentPage-Dj63oQ5D.js → MailSentPage-QzpuIJmT.js} +1 -1
  40. package/static/assets/{McpSettingsPage-DYZ0QNbp.js → McpSettingsPage-BZcCGkGM.js} +1 -1
  41. package/static/assets/MemoryEditPage-DXSQoCT4.js +13 -0
  42. package/static/assets/MemoryPage-oBnyuvSf.js +1 -0
  43. package/static/assets/NewKnowledgePage-deMsezK8.js +1 -0
  44. package/static/assets/{NewSkillPage-BEn18f2A.js → NewSkillPage-DRYWdrlV.js} +1 -1
  45. package/static/assets/{NewTaskPage-CSlncpI5.js → NewTaskPage-B6xdic5_.js} +2 -2
  46. package/static/assets/{NotFoundPage-C4x0lGai.js → NotFoundPage-Bxu9uKFO.js} +1 -1
  47. package/static/assets/{NotificationsSettingsPage-C9YnfRlj.js → NotificationsSettingsPage-CLgtsCVM.js} +1 -1
  48. package/static/assets/{PromptsSettingsPage-Chc4da1S.js → PromptsSettingsPage-BWaELCjG.js} +1 -1
  49. package/static/assets/{ResourceDetailPage-DDYKQxpM.js → ResourceDetailPage-CMPDRdVM.js} +1 -1
  50. package/static/assets/ResourcesPage-DspYILfG.js +41 -0
  51. package/static/assets/{RoleEditPage-Ccfu1tn1.js → RoleEditPage-DXtzicVZ.js} +1 -1
  52. package/static/assets/{RolePage-CcdEUjSm.js → RolePage-DafGURGp.js} +1 -1
  53. package/static/assets/{RulesSettingsPage-Cz1g_eAj.js → RulesSettingsPage-E8V9cexV.js} +1 -1
  54. package/static/assets/RunDetailPage-DsxkqFst.js +1 -0
  55. package/static/assets/SchedulePage-B2YvNDHr.js +4 -0
  56. package/static/assets/{SkillDetailPage-sJg-L8A8.js → SkillDetailPage-CWkqSfuT.js} +1 -1
  57. package/static/assets/{SkillEditPage-BksV7GmD.js → SkillEditPage-DwyebzFV.js} +1 -1
  58. package/static/assets/{SkillsPage-CwarkJmZ.js → SkillsPage-CauK65X_.js} +2 -2
  59. package/static/assets/{SkillsSettingsPage-DTnBlBdE.js → SkillsSettingsPage-DXMRv3jR.js} +1 -1
  60. package/static/assets/{SourceInput-CWazIr6v.js → SourceInput-C0iKqbQ1.js} +1 -1
  61. package/static/assets/{TagInput-Bgyxb_JU.js → TagInput-Ct-WRvTs.js} +1 -1
  62. package/static/assets/{TaskDetailPage-DlmG1kZR.js → TaskDetailPage-CApk2iBh.js} +1 -1
  63. package/static/assets/{TaskEditPage-BnpNeed_.js → TaskEditPage-NgOVShfK.js} +1 -1
  64. package/static/assets/{TasksPage-CXeTMpgy.js → TasksPage-BoPrP_Rl.js} +3 -3
  65. package/static/assets/TeamEditPage-ChY6mYm8.js +9 -0
  66. package/static/assets/TeamPage-DH-dJhFG.js +1 -0
  67. package/static/assets/{TerminalPage-BLcPt381.js → TerminalPage-CRhcscF2.js} +1 -1
  68. package/static/assets/TerminalSessionPage-CSCQg2sn.js +3 -0
  69. package/static/assets/{UserPreferencesPage-BNwEqlRW.js → UserPreferencesPage-DxCSWJnS.js} +1 -1
  70. package/static/assets/{UserSettingsPage-BRafqkiD.js → UserSettingsPage-DKkOLNPV.js} +1 -1
  71. package/static/assets/UtilitiesPage-CBNSvixW.js +1 -0
  72. package/static/assets/{alert-Ci2-OWZ_.js → alert-Dw_RSroN.js} +1 -1
  73. package/static/assets/{arrow-down-C6Flf0DF.js → arrow-down-UClxXzT-.js} +1 -1
  74. package/static/assets/{arrow-left-7TCkaJlN.js → arrow-left-DWmf9YJp.js} +1 -1
  75. package/static/assets/{arrow-up-down-tqbfiBy6.js → arrow-up-down-Btc3okb3.js} +1 -1
  76. package/static/assets/{arrow-up-DeQAxOPq.js → arrow-up-fLCh7Hvh.js} +1 -1
  77. package/static/assets/{badge-D4vHU_w_.js → badge-vIqE5SOP.js} +1 -1
  78. package/static/assets/{browser-modal-BiaqhKHm.js → browser-modal-DgMJTsMd.js} +2 -2
  79. package/static/assets/{card-xkODbJy-.js → card-DPLdBoa5.js} +1 -1
  80. package/static/assets/{chevron-left-CvpfJBPQ.js → chevron-left-CiNaLX-v.js} +1 -1
  81. package/static/assets/{chevron-up-BB-6OS4z.js → chevron-up-DFd-7wxW.js} +1 -1
  82. package/static/assets/{chevrons-up-CLKrQHMU.js → chevrons-up-BfU70OcQ.js} +1 -1
  83. package/static/assets/{circle-alert-lnP0-w3N.js → circle-alert-Mv00T-P2.js} +1 -1
  84. package/static/assets/{circle-check-big-Dbo-OmWQ.js → circle-check-big-BEY1IoIP.js} +1 -1
  85. package/static/assets/{circle-check-BPkEav83.js → circle-check-xMiP6SLO.js} +1 -1
  86. package/static/assets/{circle-play-BbtBIeo3.js → circle-play-iZZwaGbV.js} +1 -1
  87. package/static/assets/{circle-x-BBwi8e5G.js → circle-x-z3iynaE7.js} +1 -1
  88. package/static/assets/{clipboard-Ce816tAO.js → clipboard-C8wZRPDH.js} +1 -1
  89. package/static/assets/{clock-BIeoO5Mt.js → clock-C_9shc08.js} +1 -1
  90. package/static/assets/{code-DTW3giBe.js → code-DH-sRhus.js} +1 -1
  91. package/static/assets/{download-BgKxfry9.js → download-CE8b59ER.js} +1 -1
  92. package/static/assets/{external-link--RjKXREe.js → external-link-DPyKt8NE.js} +1 -1
  93. package/static/assets/{eye--K-OgK7L.js → eye-BpGD-yoS.js} +1 -1
  94. package/static/assets/{folder-git-2-Bgv7r0zC.js → folder-git-2-BIw4zbmy.js} +1 -1
  95. package/static/assets/globe-CUo7eHKN.js +6 -0
  96. package/static/assets/{index-Di7xMYoG.js → index-B07hel4U.js} +1 -1
  97. package/static/assets/{index-DF_KNbKf.js → index-BCwmQxLC.js} +1 -1
  98. package/static/assets/{index-D9xZafJb.js → index-BOKaM9K-.js} +1 -1
  99. package/static/assets/{index-Cd5hBt4x.js → index-BaR4iUzg.js} +1 -1
  100. package/static/assets/index-BcCuKdbf.css +1 -0
  101. package/static/assets/{index-Db5-BoCU.js → index-Bfb3OTwj.js} +1 -1
  102. package/static/assets/{index-Do92mBFr.js → index-Bkt1rQVV.js} +1 -1
  103. package/static/assets/{index-BD9UBXsr.js → index-C65b3D5_.js} +1 -1
  104. package/static/assets/{index-BbrX1XcC.js → index-CGbmjmEy.js} +1 -1
  105. package/static/assets/{index-4RuWYO4M.js → index-CTouvf2d.js} +1 -1
  106. package/static/assets/{index-Dt_WtbUU.js → index-Cdwx6Zps.js} +1 -1
  107. package/static/assets/{index-iIFwHD3L.js → index-ClO9-JVh.js} +1 -1
  108. package/static/assets/{index-BteQHbZ1.js → index-CpJ0uBf3.js} +1 -1
  109. package/static/assets/{index-LMsLdXw_.js → index-CsBxEWw5.js} +1 -1
  110. package/static/assets/{index-CW9pK_cZ.js → index-DZAYfTI2.js} +1 -1
  111. package/static/assets/{index-BkEdELOI.js → index-Dkr9CBL7.js} +1 -1
  112. package/static/assets/{index-BQYB8kWb.js → index-DnZKG-_7.js} +1 -1
  113. package/static/assets/index-UXL5-kaP.js +497 -0
  114. package/static/assets/{index-Ch4GVR8L.js → index-iB8oed57.js} +1 -1
  115. package/static/assets/{index-R44k73Ca.js → index-jaRIZ6SY.js} +1 -1
  116. package/static/assets/{info-DgZN3xWF.js → info-D-UNBNx2.js} +1 -1
  117. package/static/assets/{label-DvPENm3h.js → label-8VKluf9w.js} +1 -1
  118. package/static/assets/{markdown-editor-DpZxV-fa.js → markdown-editor-DBdRsbP2.js} +3 -3
  119. package/static/assets/{message-square-CoaQYehb.js → message-square-CO8kDUed.js} +1 -1
  120. package/static/assets/{paperclip-ChugoOAp.js → paperclip-DlLXZbru.js} +1 -1
  121. package/static/assets/{pause-m9YcgxdE.js → pause-zSiaxJBu.js} +1 -1
  122. package/static/assets/{play-DtFz_MLh.js → play-DVBhRokt.js} +1 -1
  123. package/static/assets/{radio-group-C5Te9bVb.js → radio-group-CThYUcA4.js} +1 -1
  124. package/static/assets/{refresh-cw-B1bWW9Rg.js → refresh-cw-tXYl1ePu.js} +1 -1
  125. package/static/assets/{search-CPOHeeUa.js → search-BxF7Wwex.js} +1 -1
  126. package/static/assets/{select-B1v2u6hQ.js → select-CyHFRA1Y.js} +1 -1
  127. package/static/assets/server-lRxThHjr.js +6 -0
  128. package/static/assets/{switch-Bf1Cq3P6.js → switch-BUpDbrux.js} +1 -1
  129. package/static/assets/tabs-DkvCmQEX.js +1 -0
  130. package/static/assets/{tag-Cz4z82t0.js → tag-CkcZNLnh.js} +1 -1
  131. package/static/assets/{terminal-preview-DTUohQ5b.js → terminal-preview-CLWDhoOZ.js} +1 -1
  132. package/static/assets/triangle-alert-CmjG_mbF.js +6 -0
  133. package/static/assets/{use-terminal-CFbQv1ie.js → use-terminal-D3iV7-iC.js} +1 -1
  134. package/static/assets/{video-B6ZJ-Epb.js → video-CY_dOujm.js} +1 -1
  135. package/static/index.html +2 -2
  136. package/dist/lib/mcp-client.d.ts +0 -39
  137. package/dist/lib/mcp-client.js +0 -131
  138. package/dist/routes/api/v1/ai/tools.d.ts +0 -17
  139. package/dist/routes/api/v1/ai/tools.js +0 -931
  140. package/dist/routes/api/v1/context/knowledge/[filename]/index.d.ts +0 -1
  141. package/dist/routes/api/v1/context/knowledge/[filename]/index.js +0 -1
  142. package/dist/routes/api/v1/context/knowledge/[filename]/route.js +0 -254
  143. package/dist/routes/api/v1/context/knowledge/index.d.ts +0 -1
  144. package/dist/routes/api/v1/context/knowledge/index.js +0 -1
  145. package/dist/routes/api/v1/context/knowledge/route.js +0 -176
  146. package/dist/routes/api/v1/proposals/[id]/route.d.ts +0 -337
  147. package/dist/routes/api/v1/proposals/[id]/route.js +0 -165
  148. package/dist/routes/api/v1/proposals/index.d.ts +0 -3
  149. package/dist/routes/api/v1/proposals/index.js +0 -10
  150. package/dist/routes/api/v1/proposals/route.d.ts +0 -315
  151. package/dist/routes/api/v1/proposals/route.js +0 -129
  152. package/dist/routes/api/v1/terminal/[proposalId]/create/index.d.ts +0 -3
  153. package/dist/routes/api/v1/terminal/[proposalId]/create/index.js +0 -5
  154. package/dist/routes/api/v1/terminal/[proposalId]/create/route.d.ts +0 -10
  155. package/dist/routes/api/v1/terminal/[proposalId]/create/route.js +0 -27
  156. package/dist/routes/api/v1/terminal/[proposalId]/destroy/index.js +0 -5
  157. package/dist/routes/api/v1/terminal/[proposalId]/destroy/route.d.ts +0 -10
  158. package/dist/routes/api/v1/terminal/[proposalId]/destroy/route.js +0 -21
  159. package/dist/routes/api/v1/terminal/[proposalId]/resize/index.d.ts +0 -3
  160. package/dist/routes/api/v1/terminal/[proposalId]/resize/index.js +0 -5
  161. package/dist/routes/api/v1/terminal/[proposalId]/resize/route.d.ts +0 -10
  162. package/dist/routes/api/v1/terminal/[proposalId]/resize/route.js +0 -21
  163. package/static/assets/ActivityPage-uL-Qknui.js +0 -1
  164. package/static/assets/ArchitectureEditPage-BWKyKi3T.js +0 -21
  165. package/static/assets/ArchitecturePage-Dtm0OAac.js +0 -1
  166. package/static/assets/CodePage-BuO2K_xx.js +0 -2
  167. package/static/assets/IntegrationsSettingsPage-Z8xCUmX9.js +0 -1
  168. package/static/assets/JobDetailPage-B8Za82RA.js +0 -1
  169. package/static/assets/KnowledgeDetailPage-CR9c4_WD.js +0 -1
  170. package/static/assets/MailInboxPage-B_h1Kz4D.js +0 -1
  171. package/static/assets/MailProcessingModal-D_qEwqmL.js +0 -6
  172. package/static/assets/MailReadPage-_q-xk_cX.js +0 -1
  173. package/static/assets/NewKnowledgePage-BEVMYnKG.js +0 -9
  174. package/static/assets/ProjectEditPage-X0-4mEAS.js +0 -11
  175. package/static/assets/ProjectPage-D8OX1GKt.js +0 -1
  176. package/static/assets/ResourcesPage-BmOpgt3L.js +0 -41
  177. package/static/assets/SchedulePage-CGxZHEL-.js +0 -4
  178. package/static/assets/TerminalSessionPage-CeAd8IAy.js +0 -8
  179. package/static/assets/UtilitiesPage-BPX_Unxu.js +0 -1
  180. package/static/assets/index-DH_vXhd4.css +0 -1
  181. package/static/assets/index-PyVlsLW8.js +0 -487
  182. package/static/assets/tabs-DAbCZiFC.js +0 -1
  183. /package/dist/routes/api/v1/context/{knowledge/[filename] → agents}/route.d.ts +0 -0
  184. /package/dist/routes/api/v1/context/{knowledge → memory}/route.d.ts +0 -0
  185. /package/dist/routes/api/v1/{terminal/[proposalId]/destroy/index.d.ts → context/team/route.d.ts} +0 -0
@@ -0,0 +1,159 @@
1
+ import { Hono } from 'hono';
2
+ import { promises as fs } from 'fs';
3
+ import path from 'path';
4
+ import matter from 'gray-matter';
5
+ import { findGaitDirectory } from '../../../../../lib/gait-path.js';
6
+ import { getLogger, ContextKinds } from '@lovelybunch/core/logging';
7
+ import { requireAuth } from '../../../../../middleware/auth.js';
8
+ function generateSummary(content, maxLines = 3, maxChars = 200) {
9
+ const cleanContent = content
10
+ .replace(/^#+\s+/gm, '')
11
+ .replace(/[*_`]/g, '')
12
+ .replace(/\[([^\]]+)\]\([^)]+\)/g, '$1')
13
+ .trim();
14
+ const lines = cleanContent.split('\n').filter(line => line.trim().length > 0);
15
+ const summary = lines.slice(0, maxLines).join(' ');
16
+ return summary.length > maxChars
17
+ ? summary.substring(0, maxChars) + '...'
18
+ : summary;
19
+ }
20
+ const app = new Hono();
21
+ async function getAgentsPath() {
22
+ const gaitDir = await findGaitDirectory();
23
+ if (!gaitDir)
24
+ return null;
25
+ return path.join(gaitDir, 'context');
26
+ }
27
+ /**
28
+ * GET /api/v1/context/agents
29
+ */
30
+ app.get('/', async (c) => {
31
+ try {
32
+ const agentsPath = await getAgentsPath();
33
+ if (!agentsPath) {
34
+ return c.json({ success: false, error: 'GAIT directory not found' }, 404);
35
+ }
36
+ await fs.mkdir(agentsPath, { recursive: true });
37
+ const filePath = path.join(agentsPath, 'agents.md');
38
+ try {
39
+ const fileContent = await fs.readFile(filePath, 'utf-8');
40
+ const { data, content } = matter(fileContent);
41
+ const title = content.match(/^#\s+(.+)$/m)?.[1] || 'Agents';
42
+ const document = {
43
+ filename: 'agents.md',
44
+ metadata: {
45
+ ...data,
46
+ updated: data.updated || new Date().toISOString().split('T')[0],
47
+ type: 'agents',
48
+ category: 'context',
49
+ tags: data.tags || []
50
+ },
51
+ content,
52
+ title
53
+ };
54
+ return c.json({ success: true, document });
55
+ }
56
+ catch (fileError) {
57
+ const defaultContent = `# Agents
58
+
59
+ This document defines the agents available in this project.
60
+
61
+ ## Agent Definitions
62
+
63
+ Describe agents, their capabilities, and configurations.
64
+
65
+ ## Agent Guidelines
66
+
67
+ Key guidelines for agent behavior and interaction patterns.
68
+ `;
69
+ const document = {
70
+ filename: 'agents.md',
71
+ metadata: {
72
+ version: '1.0',
73
+ updated: new Date().toISOString().split('T')[0],
74
+ type: 'agents',
75
+ category: 'context',
76
+ tags: []
77
+ },
78
+ content: defaultContent,
79
+ title: 'Agents'
80
+ };
81
+ return c.json({ success: true, document });
82
+ }
83
+ }
84
+ catch (error) {
85
+ console.error('Error loading agents document:', error);
86
+ return c.json({ success: false, error: 'Failed to load agents document' }, 500);
87
+ }
88
+ });
89
+ /**
90
+ * PUT /api/v1/context/agents
91
+ */
92
+ app.put('/', async (c) => {
93
+ try {
94
+ const body = await c.req.json();
95
+ if (!body.content) {
96
+ return c.json({ success: false, error: 'Content is required' }, 400);
97
+ }
98
+ const agentsPath = await getAgentsPath();
99
+ if (!agentsPath) {
100
+ return c.json({ success: false, error: 'GAIT directory not found' }, 404);
101
+ }
102
+ await fs.mkdir(agentsPath, { recursive: true });
103
+ const filePath = path.join(agentsPath, 'agents.md');
104
+ let currentData = {};
105
+ try {
106
+ const currentContent = await fs.readFile(filePath, 'utf-8');
107
+ const { data } = matter(currentContent);
108
+ currentData = data;
109
+ }
110
+ catch {
111
+ // File doesn't exist, use defaults
112
+ }
113
+ const updatedMetadata = {
114
+ ...currentData,
115
+ ...body.metadata,
116
+ updated: new Date().toISOString().split('T')[0],
117
+ type: 'agents',
118
+ category: 'context',
119
+ version: currentData.version || '1.0'
120
+ };
121
+ const fileContent = matter.stringify(body.content, updatedMetadata);
122
+ await fs.writeFile(filePath, fileContent, 'utf-8');
123
+ const title = body.title ||
124
+ body.content.match(/^#\s+(.+)$/m)?.[1] ||
125
+ 'Agents';
126
+ try {
127
+ const session = await requireAuth(c);
128
+ const actor = session ? `human:${session.email}` : "human:unknown";
129
+ const logger = getLogger();
130
+ logger.log({
131
+ kind: ContextKinds.AGENTS_UPDATE,
132
+ actor,
133
+ subject: `context:agents.md`,
134
+ tags: ["context", "agents"],
135
+ payload: {
136
+ title,
137
+ summary: generateSummary(body.content),
138
+ }
139
+ });
140
+ }
141
+ catch (logError) {
142
+ console.error('Error logging agents update:', logError);
143
+ }
144
+ return c.json({
145
+ success: true,
146
+ document: {
147
+ filename: 'agents.md',
148
+ title,
149
+ metadata: updatedMetadata,
150
+ content: body.content
151
+ }
152
+ });
153
+ }
154
+ catch (error) {
155
+ console.error('Error updating agents document:', error);
156
+ return c.json({ success: false, error: 'Failed to update agents document' }, 500);
157
+ }
158
+ });
159
+ export default app;
@@ -1,11 +1,13 @@
1
1
  import { Hono } from 'hono';
2
- import project from './project/route.js';
3
- import architecture from './architecture/route.js';
4
2
  import role from './role/route.js';
3
+ import agents from './agents/route.js';
4
+ import team from './team/route.js';
5
+ import memory from './memory/route.js';
5
6
  import images from './images/index.js';
6
7
  const context = new Hono();
7
- context.route('/project', project);
8
- context.route('/architecture', architecture);
9
8
  context.route('/role', role);
9
+ context.route('/agents', agents);
10
+ context.route('/team', team);
11
+ context.route('/memory', memory);
10
12
  context.route('/images', images);
11
13
  export default context;
@@ -0,0 +1,163 @@
1
+ import { Hono } from 'hono';
2
+ import { promises as fs } from 'fs';
3
+ import path from 'path';
4
+ import matter from 'gray-matter';
5
+ import { findGaitDirectory } from '../../../../../lib/gait-path.js';
6
+ import { getLogger, ContextKinds } from '@lovelybunch/core/logging';
7
+ import { requireAuth } from '../../../../../middleware/auth.js';
8
+ function generateSummary(content, maxLines = 3, maxChars = 200) {
9
+ const cleanContent = content
10
+ .replace(/^#+\s+/gm, '')
11
+ .replace(/[*_`]/g, '')
12
+ .replace(/\[([^\]]+)\]\([^)]+\)/g, '$1')
13
+ .trim();
14
+ const lines = cleanContent.split('\n').filter(line => line.trim().length > 0);
15
+ const summary = lines.slice(0, maxLines).join(' ');
16
+ return summary.length > maxChars
17
+ ? summary.substring(0, maxChars) + '...'
18
+ : summary;
19
+ }
20
+ const app = new Hono();
21
+ async function getMemoryPath() {
22
+ const gaitDir = await findGaitDirectory();
23
+ if (!gaitDir)
24
+ return null;
25
+ return path.join(gaitDir, 'context');
26
+ }
27
+ /**
28
+ * GET /api/v1/context/memory
29
+ */
30
+ app.get('/', async (c) => {
31
+ try {
32
+ const memoryPath = await getMemoryPath();
33
+ if (!memoryPath) {
34
+ return c.json({ success: false, error: 'GAIT directory not found' }, 404);
35
+ }
36
+ await fs.mkdir(memoryPath, { recursive: true });
37
+ const filePath = path.join(memoryPath, 'memory.md');
38
+ try {
39
+ const fileContent = await fs.readFile(filePath, 'utf-8');
40
+ const { data, content } = matter(fileContent);
41
+ const title = content.match(/^#\s+(.+)$/m)?.[1] || 'Memory';
42
+ const document = {
43
+ filename: 'memory.md',
44
+ metadata: {
45
+ ...data,
46
+ updated: data.updated || new Date().toISOString().split('T')[0],
47
+ type: 'memory',
48
+ category: 'context',
49
+ tags: data.tags || []
50
+ },
51
+ content,
52
+ title
53
+ };
54
+ return c.json({ success: true, document });
55
+ }
56
+ catch (fileError) {
57
+ const defaultContent = `# Memory
58
+
59
+ This document stores persistent memory and learned context.
60
+
61
+ ## Key Decisions
62
+
63
+ Important decisions made during the project.
64
+
65
+ ## Lessons Learned
66
+
67
+ Insights and patterns discovered over time.
68
+
69
+ ## Preferences
70
+
71
+ Remembered preferences and conventions.
72
+ `;
73
+ const document = {
74
+ filename: 'memory.md',
75
+ metadata: {
76
+ version: '1.0',
77
+ updated: new Date().toISOString().split('T')[0],
78
+ type: 'memory',
79
+ category: 'context',
80
+ tags: []
81
+ },
82
+ content: defaultContent,
83
+ title: 'Memory'
84
+ };
85
+ return c.json({ success: true, document });
86
+ }
87
+ }
88
+ catch (error) {
89
+ console.error('Error loading memory document:', error);
90
+ return c.json({ success: false, error: 'Failed to load memory document' }, 500);
91
+ }
92
+ });
93
+ /**
94
+ * PUT /api/v1/context/memory
95
+ */
96
+ app.put('/', async (c) => {
97
+ try {
98
+ const body = await c.req.json();
99
+ if (!body.content) {
100
+ return c.json({ success: false, error: 'Content is required' }, 400);
101
+ }
102
+ const memoryPath = await getMemoryPath();
103
+ if (!memoryPath) {
104
+ return c.json({ success: false, error: 'GAIT directory not found' }, 404);
105
+ }
106
+ await fs.mkdir(memoryPath, { recursive: true });
107
+ const filePath = path.join(memoryPath, 'memory.md');
108
+ let currentData = {};
109
+ try {
110
+ const currentContent = await fs.readFile(filePath, 'utf-8');
111
+ const { data } = matter(currentContent);
112
+ currentData = data;
113
+ }
114
+ catch {
115
+ // File doesn't exist, use defaults
116
+ }
117
+ const updatedMetadata = {
118
+ ...currentData,
119
+ ...body.metadata,
120
+ updated: new Date().toISOString().split('T')[0],
121
+ type: 'memory',
122
+ category: 'context',
123
+ version: currentData.version || '1.0'
124
+ };
125
+ const fileContent = matter.stringify(body.content, updatedMetadata);
126
+ await fs.writeFile(filePath, fileContent, 'utf-8');
127
+ const title = body.title ||
128
+ body.content.match(/^#\s+(.+)$/m)?.[1] ||
129
+ 'Memory';
130
+ try {
131
+ const session = await requireAuth(c);
132
+ const actor = session ? `human:${session.email}` : "human:unknown";
133
+ const logger = getLogger();
134
+ logger.log({
135
+ kind: ContextKinds.MEMORY_UPDATE,
136
+ actor,
137
+ subject: `context:memory.md`,
138
+ tags: ["context", "memory"],
139
+ payload: {
140
+ title,
141
+ summary: generateSummary(body.content),
142
+ }
143
+ });
144
+ }
145
+ catch (logError) {
146
+ console.error('Error logging memory update:', logError);
147
+ }
148
+ return c.json({
149
+ success: true,
150
+ document: {
151
+ filename: 'memory.md',
152
+ title,
153
+ metadata: updatedMetadata,
154
+ content: body.content
155
+ }
156
+ });
157
+ }
158
+ catch (error) {
159
+ console.error('Error updating memory document:', error);
160
+ return c.json({ success: false, error: 'Failed to update memory document' }, 500);
161
+ }
162
+ });
163
+ export default app;
@@ -0,0 +1,159 @@
1
+ import { Hono } from 'hono';
2
+ import { promises as fs } from 'fs';
3
+ import path from 'path';
4
+ import matter from 'gray-matter';
5
+ import { findGaitDirectory } from '../../../../../lib/gait-path.js';
6
+ import { getLogger, ContextKinds } from '@lovelybunch/core/logging';
7
+ import { requireAuth } from '../../../../../middleware/auth.js';
8
+ function generateSummary(content, maxLines = 3, maxChars = 200) {
9
+ const cleanContent = content
10
+ .replace(/^#+\s+/gm, '')
11
+ .replace(/[*_`]/g, '')
12
+ .replace(/\[([^\]]+)\]\([^)]+\)/g, '$1')
13
+ .trim();
14
+ const lines = cleanContent.split('\n').filter(line => line.trim().length > 0);
15
+ const summary = lines.slice(0, maxLines).join(' ');
16
+ return summary.length > maxChars
17
+ ? summary.substring(0, maxChars) + '...'
18
+ : summary;
19
+ }
20
+ const app = new Hono();
21
+ async function getTeamPath() {
22
+ const gaitDir = await findGaitDirectory();
23
+ if (!gaitDir)
24
+ return null;
25
+ return path.join(gaitDir, 'context');
26
+ }
27
+ /**
28
+ * GET /api/v1/context/team
29
+ */
30
+ app.get('/', async (c) => {
31
+ try {
32
+ const teamPath = await getTeamPath();
33
+ if (!teamPath) {
34
+ return c.json({ success: false, error: 'GAIT directory not found' }, 404);
35
+ }
36
+ await fs.mkdir(teamPath, { recursive: true });
37
+ const filePath = path.join(teamPath, 'team.md');
38
+ try {
39
+ const fileContent = await fs.readFile(filePath, 'utf-8');
40
+ const { data, content } = matter(fileContent);
41
+ const title = content.match(/^#\s+(.+)$/m)?.[1] || 'Team';
42
+ const document = {
43
+ filename: 'team.md',
44
+ metadata: {
45
+ ...data,
46
+ updated: data.updated || new Date().toISOString().split('T')[0],
47
+ type: 'team',
48
+ category: 'context',
49
+ tags: data.tags || []
50
+ },
51
+ content,
52
+ title
53
+ };
54
+ return c.json({ success: true, document });
55
+ }
56
+ catch (fileError) {
57
+ const defaultContent = `# Team
58
+
59
+ This document describes the team structure and members.
60
+
61
+ ## Team Members
62
+
63
+ List team members, their roles, and responsibilities.
64
+
65
+ ## Communication
66
+
67
+ Team communication channels and conventions.
68
+ `;
69
+ const document = {
70
+ filename: 'team.md',
71
+ metadata: {
72
+ version: '1.0',
73
+ updated: new Date().toISOString().split('T')[0],
74
+ type: 'team',
75
+ category: 'context',
76
+ tags: []
77
+ },
78
+ content: defaultContent,
79
+ title: 'Team'
80
+ };
81
+ return c.json({ success: true, document });
82
+ }
83
+ }
84
+ catch (error) {
85
+ console.error('Error loading team document:', error);
86
+ return c.json({ success: false, error: 'Failed to load team document' }, 500);
87
+ }
88
+ });
89
+ /**
90
+ * PUT /api/v1/context/team
91
+ */
92
+ app.put('/', async (c) => {
93
+ try {
94
+ const body = await c.req.json();
95
+ if (!body.content) {
96
+ return c.json({ success: false, error: 'Content is required' }, 400);
97
+ }
98
+ const teamPath = await getTeamPath();
99
+ if (!teamPath) {
100
+ return c.json({ success: false, error: 'GAIT directory not found' }, 404);
101
+ }
102
+ await fs.mkdir(teamPath, { recursive: true });
103
+ const filePath = path.join(teamPath, 'team.md');
104
+ let currentData = {};
105
+ try {
106
+ const currentContent = await fs.readFile(filePath, 'utf-8');
107
+ const { data } = matter(currentContent);
108
+ currentData = data;
109
+ }
110
+ catch {
111
+ // File doesn't exist, use defaults
112
+ }
113
+ const updatedMetadata = {
114
+ ...currentData,
115
+ ...body.metadata,
116
+ updated: new Date().toISOString().split('T')[0],
117
+ type: 'team',
118
+ category: 'context',
119
+ version: currentData.version || '1.0'
120
+ };
121
+ const fileContent = matter.stringify(body.content, updatedMetadata);
122
+ await fs.writeFile(filePath, fileContent, 'utf-8');
123
+ const title = body.title ||
124
+ body.content.match(/^#\s+(.+)$/m)?.[1] ||
125
+ 'Team';
126
+ try {
127
+ const session = await requireAuth(c);
128
+ const actor = session ? `human:${session.email}` : "human:unknown";
129
+ const logger = getLogger();
130
+ logger.log({
131
+ kind: ContextKinds.TEAM_UPDATE,
132
+ actor,
133
+ subject: `context:team.md`,
134
+ tags: ["context", "team"],
135
+ payload: {
136
+ title,
137
+ summary: generateSummary(body.content),
138
+ }
139
+ });
140
+ }
141
+ catch (logError) {
142
+ console.error('Error logging team update:', logError);
143
+ }
144
+ return c.json({
145
+ success: true,
146
+ document: {
147
+ filename: 'team.md',
148
+ title,
149
+ metadata: updatedMetadata,
150
+ content: body.content
151
+ }
152
+ });
153
+ }
154
+ catch (error) {
155
+ console.error('Error updating team document:', error);
156
+ return c.json({ success: false, error: 'Failed to update team document' }, 500);
157
+ }
158
+ });
159
+ export default app;
@@ -1,6 +1,7 @@
1
1
  import { Hono } from 'hono';
2
2
  import crypto from 'crypto';
3
- import { getRepoStatus, listBranches, createBranch, deleteBranch, switchBranch, mergeBranch, pushCurrent, pullCurrent, listWorktrees, addWorktree, removeWorktree, commitInWorktree, pushWorktree, pullWorktree, checkRemoteAuth, getCredentialConfig, storeCredentials, getCommitDetails, getFileDiff, setRemoteUrl, } from '../../../../lib/git.js';
3
+ import { getRepoStatus, listBranches, createBranch, deleteBranch, switchBranch, mergeBranch, pushCurrent, pullCurrent, listWorktrees, addWorktree, removeWorktree, commitInWorktree, pushWorktree, pullWorktree, checkRemoteAuth, getCredentialConfig, storeCredentials, getCommitDetails, getFileDiff, setRemoteUrl, lsTree, getInstructionFiles, } from '../../../../lib/git.js';
4
+ import { INSTRUCTION_FILE_KINDS } from '@lovelybunch/types';
4
5
  import { saveGithubToken, clearGithubToken, readGithubToken, isGithubTokenValid } from '../../../../lib/github-token.js';
5
6
  import { createGithubAuthState, consumeGithubAuthState } from '../../../../lib/github-auth-state.js';
6
7
  import { resolveCoconutId, resolveControlPlaneUrl } from '../../../../lib/coconut-context.js';
@@ -674,4 +675,29 @@ app.get('/commits/:sha/files/:filepath{.+}', async (c) => {
674
675
  return c.json({ success: false, error: { message: e.message || 'Failed to get file diff' } }, 500);
675
676
  }
676
677
  });
678
+ // ls-tree
679
+ app.get('/ls-tree', async (c) => {
680
+ try {
681
+ const files = await lsTree();
682
+ return c.json({ success: true, data: files });
683
+ }
684
+ catch (e) {
685
+ return c.json({ success: false, error: { message: e.message || 'Failed to list tree' } }, 500);
686
+ }
687
+ });
688
+ // instruction-files
689
+ const VALID_FILTERS = new Set([...INSTRUCTION_FILE_KINDS, 'all']);
690
+ app.get('/instruction-files', async (c) => {
691
+ try {
692
+ const kind = (c.req.query('kind') || 'all');
693
+ if (!VALID_FILTERS.has(kind)) {
694
+ return c.json({ success: false, error: { message: `Invalid kind. Must be one of: ${[...VALID_FILTERS].join(', ')}` } }, 400);
695
+ }
696
+ const data = await getInstructionFiles(kind);
697
+ return c.json({ success: true, data });
698
+ }
699
+ catch (e) {
700
+ return c.json({ success: false, error: { message: e.message || 'Failed to retrieve instruction files' } }, 500);
701
+ }
702
+ });
677
703
  export default app;
@@ -9,12 +9,6 @@ export declare function GET(c: Context): Promise<(Response & import("hono").Type
9
9
  }, 404, "json">) | (Response & import("hono").TypedResponse<{
10
10
  success: true;
11
11
  data: {
12
- id: string;
13
- name: string;
14
- description?: string;
15
- prompt: string;
16
- model: string;
17
- status: ScheduledJobStatus;
18
12
  schedule: {
19
13
  type: "cron";
20
14
  expression: string;
@@ -27,29 +21,32 @@ export declare function GET(c: Context): Promise<(Response & import("hono").Type
27
21
  timezone?: string;
28
22
  anchorHour?: number;
29
23
  };
24
+ description?: string;
25
+ id: string;
26
+ name: string;
27
+ prompt: string;
28
+ model: string;
29
+ status: ScheduledJobStatus;
30
30
  metadata: {
31
31
  createdAt: string;
32
32
  updatedAt: string;
33
33
  lastRunAt?: string;
34
34
  nextRunAt?: string;
35
35
  };
36
+ tags?: string[];
37
+ contextPaths?: string[];
38
+ agentId?: string;
39
+ agentIds?: string[];
40
+ mcpServers?: string[];
36
41
  runs: {
42
+ error?: string;
37
43
  id: string;
44
+ status: import("@lovelybunch/types").ScheduledJobRunStatus;
38
45
  jobId: string;
39
46
  trigger: import("@lovelybunch/types").ScheduledJobTrigger;
40
- status: import("@lovelybunch/types").ScheduledJobRunStatus;
41
47
  startedAt: string;
42
48
  finishedAt?: string;
43
- outputPath?: string;
44
- summary?: string;
45
- error?: string;
46
- cliCommand?: string;
47
49
  }[];
48
- tags?: string[];
49
- contextPaths?: string[];
50
- agentId?: string;
51
- agentIds?: string[];
52
- mcpServers?: string[];
53
50
  };
54
51
  }, import("hono/utils/http-status").ContentfulStatusCode, "json">) | (Response & import("hono").TypedResponse<{
55
52
  success: false;
@@ -73,12 +70,6 @@ export declare function PATCH(c: Context): Promise<(Response & import("hono").Ty
73
70
  }, 400, "json">) | (Response & import("hono").TypedResponse<{
74
71
  success: true;
75
72
  data: {
76
- id: string;
77
- name: string;
78
- description?: string;
79
- prompt: string;
80
- model: string;
81
- status: ScheduledJobStatus;
82
73
  schedule: {
83
74
  type: "cron";
84
75
  expression: string;
@@ -91,29 +82,32 @@ export declare function PATCH(c: Context): Promise<(Response & import("hono").Ty
91
82
  timezone?: string;
92
83
  anchorHour?: number;
93
84
  };
85
+ description?: string;
86
+ id: string;
87
+ name: string;
88
+ prompt: string;
89
+ model: string;
90
+ status: ScheduledJobStatus;
94
91
  metadata: {
95
92
  createdAt: string;
96
93
  updatedAt: string;
97
94
  lastRunAt?: string;
98
95
  nextRunAt?: string;
99
96
  };
97
+ tags?: string[];
98
+ contextPaths?: string[];
99
+ agentId?: string;
100
+ agentIds?: string[];
101
+ mcpServers?: string[];
100
102
  runs: {
103
+ error?: string;
101
104
  id: string;
105
+ status: import("@lovelybunch/types").ScheduledJobRunStatus;
102
106
  jobId: string;
103
107
  trigger: import("@lovelybunch/types").ScheduledJobTrigger;
104
- status: import("@lovelybunch/types").ScheduledJobRunStatus;
105
108
  startedAt: string;
106
109
  finishedAt?: string;
107
- outputPath?: string;
108
- summary?: string;
109
- error?: string;
110
- cliCommand?: string;
111
110
  }[];
112
- tags?: string[];
113
- contextPaths?: string[];
114
- agentId?: string;
115
- agentIds?: string[];
116
- mcpServers?: string[];
117
111
  };
118
112
  }, import("hono/utils/http-status").ContentfulStatusCode, "json">) | (Response & import("hono").TypedResponse<{
119
113
  success: false;
@@ -1,6 +1,6 @@
1
1
  import { JobStore } from '../../../../../lib/jobs/job-store.js';
2
2
  import { getGlobalJobScheduler } from '../../../../../lib/jobs/global-job-scheduler.js';
3
- import { normalizeSchedule, normalizeStatus, } from '../route.js';
3
+ import { normalizeSchedule, normalizeStatus, withLightweightRuns, } from '../route.js';
4
4
  const store = new JobStore();
5
5
  const scheduler = getGlobalJobScheduler();
6
6
  function normalizeScheduleUpdate(current, incoming) {
@@ -32,7 +32,7 @@ export async function GET(c) {
32
32
  }
33
33
  }, 404);
34
34
  }
35
- return c.json({ success: true, data: job });
35
+ return c.json({ success: true, data: withLightweightRuns(job) });
36
36
  }
37
37
  catch (error) {
38
38
  console.error('Failed to fetch job:', error);
@@ -101,7 +101,7 @@ export async function PATCH(c) {
101
101
  const reloaded = await store.getJob(updated.id);
102
102
  return c.json({
103
103
  success: true,
104
- data: reloaded ?? updated
104
+ data: withLightweightRuns(reloaded ?? updated)
105
105
  });
106
106
  }
107
107
  catch (error) {