@lovelybunch/api 1.0.7

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 (131) hide show
  1. package/dist/lib/gait-path.d.ts +13 -0
  2. package/dist/lib/gait-path.js +57 -0
  3. package/dist/lib/project-paths.d.ts +13 -0
  4. package/dist/lib/project-paths.js +57 -0
  5. package/dist/lib/storage/file-storage.d.ts +28 -0
  6. package/dist/lib/storage/file-storage.js +224 -0
  7. package/dist/lib/symlinks/symlink-manager.d.ts +66 -0
  8. package/dist/lib/symlinks/symlink-manager.js +444 -0
  9. package/dist/lib/symlinks/types.d.ts +23 -0
  10. package/dist/lib/symlinks/types.js +4 -0
  11. package/dist/lib/terminal/context-helper.d.ts +11 -0
  12. package/dist/lib/terminal/context-helper.js +164 -0
  13. package/dist/lib/terminal/global-manager.d.ts +2 -0
  14. package/dist/lib/terminal/global-manager.js +15 -0
  15. package/dist/lib/terminal/shell-utils.d.ts +33 -0
  16. package/dist/lib/terminal/shell-utils.js +176 -0
  17. package/dist/lib/terminal/terminal-manager.d.ts +26 -0
  18. package/dist/lib/terminal/terminal-manager.js +276 -0
  19. package/dist/lib/user-preferences.d.ts +48 -0
  20. package/dist/lib/user-preferences.js +87 -0
  21. package/dist/lib/utils.d.ts +2 -0
  22. package/dist/lib/utils.js +5 -0
  23. package/dist/routes/api/symlink-status/route.d.ts +1 -0
  24. package/dist/routes/api/symlink-status/route.js +37 -0
  25. package/dist/routes/api/symlinks/[id]/route.d.ts +19 -0
  26. package/dist/routes/api/symlinks/[id]/route.js +95 -0
  27. package/dist/routes/api/symlinks/[id]/toggle/route.d.ts +11 -0
  28. package/dist/routes/api/symlinks/[id]/toggle/route.js +32 -0
  29. package/dist/routes/api/symlinks/debug/route.d.ts +1 -0
  30. package/dist/routes/api/symlinks/debug/route.js +35 -0
  31. package/dist/routes/api/symlinks/route.d.ts +9 -0
  32. package/dist/routes/api/symlinks/route.js +72 -0
  33. package/dist/routes/api/toggle-symlink/route.d.ts +2 -0
  34. package/dist/routes/api/toggle-symlink/route.js +94 -0
  35. package/dist/routes/api/v1/agents/[id]/index.d.ts +1 -0
  36. package/dist/routes/api/v1/agents/[id]/index.js +1 -0
  37. package/dist/routes/api/v1/agents/[id]/route.d.ts +3 -0
  38. package/dist/routes/api/v1/agents/[id]/route.js +163 -0
  39. package/dist/routes/api/v1/agents/index.d.ts +1 -0
  40. package/dist/routes/api/v1/agents/index.js +1 -0
  41. package/dist/routes/api/v1/agents/route.d.ts +3 -0
  42. package/dist/routes/api/v1/agents/route.js +133 -0
  43. package/dist/routes/api/v1/ai/index.d.ts +3 -0
  44. package/dist/routes/api/v1/ai/index.js +5 -0
  45. package/dist/routes/api/v1/ai/route.d.ts +8 -0
  46. package/dist/routes/api/v1/ai/route.js +86 -0
  47. package/dist/routes/api/v1/chats/[id]/index.d.ts +3 -0
  48. package/dist/routes/api/v1/chats/[id]/index.js +6 -0
  49. package/dist/routes/api/v1/chats/[id]/route.d.ts +12 -0
  50. package/dist/routes/api/v1/chats/[id]/route.js +31 -0
  51. package/dist/routes/api/v1/chats/index.d.ts +3 -0
  52. package/dist/routes/api/v1/chats/index.js +6 -0
  53. package/dist/routes/api/v1/chats/route.d.ts +32 -0
  54. package/dist/routes/api/v1/chats/route.js +67 -0
  55. package/dist/routes/api/v1/config/index.d.ts +3 -0
  56. package/dist/routes/api/v1/config/index.js +5 -0
  57. package/dist/routes/api/v1/config/route.d.ts +9 -0
  58. package/dist/routes/api/v1/config/route.js +29 -0
  59. package/dist/routes/api/v1/context/[...path]/route.d.ts +16 -0
  60. package/dist/routes/api/v1/context/[...path]/route.js +107 -0
  61. package/dist/routes/api/v1/context/architecture/route.d.ts +3 -0
  62. package/dist/routes/api/v1/context/architecture/route.js +198 -0
  63. package/dist/routes/api/v1/context/index.d.ts +3 -0
  64. package/dist/routes/api/v1/context/index.js +9 -0
  65. package/dist/routes/api/v1/context/knowledge/[filename]/index.d.ts +1 -0
  66. package/dist/routes/api/v1/context/knowledge/[filename]/index.js +1 -0
  67. package/dist/routes/api/v1/context/knowledge/[filename]/route.d.ts +3 -0
  68. package/dist/routes/api/v1/context/knowledge/[filename]/route.js +165 -0
  69. package/dist/routes/api/v1/context/knowledge/index.d.ts +1 -0
  70. package/dist/routes/api/v1/context/knowledge/index.js +1 -0
  71. package/dist/routes/api/v1/context/knowledge/route.d.ts +3 -0
  72. package/dist/routes/api/v1/context/knowledge/route.js +121 -0
  73. package/dist/routes/api/v1/context/project/route.d.ts +3 -0
  74. package/dist/routes/api/v1/context/project/route.js +153 -0
  75. package/dist/routes/api/v1/proposals/[id]/route.d.ts +337 -0
  76. package/dist/routes/api/v1/proposals/[id]/route.js +99 -0
  77. package/dist/routes/api/v1/proposals/index.d.ts +3 -0
  78. package/dist/routes/api/v1/proposals/index.js +10 -0
  79. package/dist/routes/api/v1/proposals/route.d.ts +315 -0
  80. package/dist/routes/api/v1/proposals/route.js +103 -0
  81. package/dist/routes/api/v1/resources/[id]/index.d.ts +3 -0
  82. package/dist/routes/api/v1/resources/[id]/index.js +7 -0
  83. package/dist/routes/api/v1/resources/[id]/route.d.ts +46 -0
  84. package/dist/routes/api/v1/resources/[id]/route.js +143 -0
  85. package/dist/routes/api/v1/resources/[id]/thumbnail/index.d.ts +3 -0
  86. package/dist/routes/api/v1/resources/[id]/thumbnail/index.js +5 -0
  87. package/dist/routes/api/v1/resources/[id]/thumbnail/route.d.ts +2 -0
  88. package/dist/routes/api/v1/resources/[id]/thumbnail/route.js +50 -0
  89. package/dist/routes/api/v1/resources/index.d.ts +3 -0
  90. package/dist/routes/api/v1/resources/index.js +6 -0
  91. package/dist/routes/api/v1/resources/route.d.ts +51 -0
  92. package/dist/routes/api/v1/resources/route.js +147 -0
  93. package/dist/routes/api/v1/search/route.d.ts +3 -0
  94. package/dist/routes/api/v1/search/route.js +39 -0
  95. package/dist/routes/api/v1/terminal/[proposalId]/create/index.d.ts +3 -0
  96. package/dist/routes/api/v1/terminal/[proposalId]/create/index.js +5 -0
  97. package/dist/routes/api/v1/terminal/[proposalId]/create/route.d.ts +10 -0
  98. package/dist/routes/api/v1/terminal/[proposalId]/create/route.js +27 -0
  99. package/dist/routes/api/v1/terminal/[proposalId]/destroy/index.d.ts +3 -0
  100. package/dist/routes/api/v1/terminal/[proposalId]/destroy/index.js +5 -0
  101. package/dist/routes/api/v1/terminal/[proposalId]/destroy/route.d.ts +10 -0
  102. package/dist/routes/api/v1/terminal/[proposalId]/destroy/route.js +21 -0
  103. package/dist/routes/api/v1/terminal/[proposalId]/resize/index.d.ts +3 -0
  104. package/dist/routes/api/v1/terminal/[proposalId]/resize/index.js +5 -0
  105. package/dist/routes/api/v1/terminal/[proposalId]/resize/route.d.ts +10 -0
  106. package/dist/routes/api/v1/terminal/[proposalId]/resize/route.js +21 -0
  107. package/dist/routes/api/v1/terminal/sessions/index.d.ts +3 -0
  108. package/dist/routes/api/v1/terminal/sessions/index.js +5 -0
  109. package/dist/routes/api/v1/terminal/sessions/route.d.ts +6 -0
  110. package/dist/routes/api/v1/terminal/sessions/route.js +29 -0
  111. package/dist/routes/api/v1/user/index.d.ts +3 -0
  112. package/dist/routes/api/v1/user/index.js +5 -0
  113. package/dist/routes/api/v1/user/preferences/route.d.ts +11 -0
  114. package/dist/routes/api/v1/user/preferences/route.js +31 -0
  115. package/dist/routes/api/v1/user/profile/route.d.ts +11 -0
  116. package/dist/routes/api/v1/user/profile/route.js +31 -0
  117. package/dist/routes/api/v1/user/settings/index.d.ts +1 -0
  118. package/dist/routes/api/v1/user/settings/index.js +1 -0
  119. package/dist/routes/api/v1/user/settings/route.d.ts +3 -0
  120. package/dist/routes/api/v1/user/settings/route.js +51 -0
  121. package/dist/server-with-static.d.ts +4 -0
  122. package/dist/server-with-static.js +144 -0
  123. package/dist/server.d.ts +1 -0
  124. package/dist/server.js +91 -0
  125. package/package.json +42 -0
  126. package/static/assets/index-BvTnrm0O.js +576 -0
  127. package/static/assets/index-Cm5dZHTl.css +33 -0
  128. package/static/assets/index-ORkAkJNi.js +576 -0
  129. package/static/assets/index-_Keadpms.js +576 -0
  130. package/static/index.html +17 -0
  131. package/static/vite.svg +1 -0
@@ -0,0 +1,198 @@
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 getArchitecturePath() {
7
+ const basePath = process.env.GAIT_DATA_PATH ?
8
+ path.resolve(process.env.GAIT_DATA_PATH, '.gait') :
9
+ path.resolve(process.cwd(), '.gait');
10
+ return path.join(basePath, 'context');
11
+ }
12
+ /**
13
+ * GET /api/v1/context/architecture
14
+ * Load architecture document
15
+ */
16
+ app.get('/', async (c) => {
17
+ try {
18
+ const architecturePath = getArchitecturePath();
19
+ // Ensure directory exists
20
+ await fs.mkdir(architecturePath, { recursive: true });
21
+ // Look for architecture.md file
22
+ const filePath = path.join(architecturePath, 'architecture.md');
23
+ try {
24
+ const fileContent = await fs.readFile(filePath, 'utf-8');
25
+ const { data, content } = matter(fileContent);
26
+ // Extract title from first heading or use default
27
+ const title = content.match(/^#\s+(.+)$/m)?.[1] || 'Architecture Overview';
28
+ const document = {
29
+ filename: 'architecture.md',
30
+ metadata: {
31
+ ...data,
32
+ updated: data.updated || new Date().toISOString().split('T')[0],
33
+ type: 'architecture',
34
+ category: 'design',
35
+ tags: data.tags || []
36
+ },
37
+ content,
38
+ title
39
+ };
40
+ return c.json({
41
+ success: true,
42
+ document
43
+ });
44
+ }
45
+ catch (fileError) {
46
+ // If file doesn't exist, return default content
47
+ const defaultContent = `# Architecture Overview
48
+
49
+ This document describes the overall architecture and design patterns used in this project.
50
+
51
+ ## System Architecture
52
+
53
+ Describe the high-level system architecture, including major components and their relationships.
54
+
55
+ ## Design Patterns
56
+
57
+ Document the key design patterns and architectural principles followed in this project.
58
+
59
+ ### Frontend Architecture
60
+
61
+ - Component structure
62
+ - State management
63
+ - Routing approach
64
+ - UI/UX patterns
65
+
66
+ ### Backend Architecture
67
+
68
+ - API design
69
+ - Data layer
70
+ - Service architecture
71
+ - Authentication & authorization
72
+
73
+ ## Data Flow
74
+
75
+ Explain how data flows through the system, including:
76
+
77
+ - Request/response cycles
78
+ - Data transformations
79
+ - Caching strategies
80
+ - Error handling
81
+
82
+ ## Technology Decisions
83
+
84
+ Document key technology choices and the reasoning behind them:
85
+
86
+ - Framework selections
87
+ - Database choices
88
+ - Third-party integrations
89
+ - Development tools
90
+
91
+ ## Deployment Architecture
92
+
93
+ Describe the deployment strategy and infrastructure:
94
+
95
+ - Environment setup
96
+ - CI/CD pipeline
97
+ - Monitoring and logging
98
+ - Scaling considerations
99
+
100
+ ## Security Considerations
101
+
102
+ Outline security measures and best practices:
103
+
104
+ - Authentication mechanisms
105
+ - Data protection
106
+ - API security
107
+ - Infrastructure security
108
+
109
+ ## Performance Considerations
110
+
111
+ Document performance optimization strategies:
112
+
113
+ - Caching layers
114
+ - Database optimization
115
+ - Frontend performance
116
+ - Monitoring and metrics
117
+ `;
118
+ const document = {
119
+ filename: 'architecture.md',
120
+ metadata: {
121
+ version: '1.0',
122
+ updated: new Date().toISOString().split('T')[0],
123
+ type: 'architecture',
124
+ category: 'design',
125
+ tags: []
126
+ },
127
+ content: defaultContent,
128
+ title: 'Architecture Overview'
129
+ };
130
+ return c.json({
131
+ success: true,
132
+ document
133
+ });
134
+ }
135
+ }
136
+ catch (error) {
137
+ console.error('Error loading architecture document:', error);
138
+ return c.json({
139
+ success: false,
140
+ error: 'Failed to load architecture document'
141
+ }, 500);
142
+ }
143
+ });
144
+ /**
145
+ * PUT /api/v1/context/architecture
146
+ * Update architecture document
147
+ */
148
+ app.put('/', async (c) => {
149
+ try {
150
+ const body = await c.req.json();
151
+ if (!body.content) {
152
+ return c.json({ success: false, error: 'Content is required' }, 400);
153
+ }
154
+ const architecturePath = getArchitecturePath();
155
+ await fs.mkdir(architecturePath, { recursive: true });
156
+ const filePath = path.join(architecturePath, 'architecture.md');
157
+ // Read current content if it exists
158
+ let currentData = {};
159
+ try {
160
+ const currentContent = await fs.readFile(filePath, 'utf-8');
161
+ const { data } = matter(currentContent);
162
+ currentData = data;
163
+ }
164
+ catch {
165
+ // File doesn't exist, use defaults
166
+ }
167
+ // Prepare updated metadata
168
+ const updatedMetadata = {
169
+ ...currentData,
170
+ ...body.metadata,
171
+ updated: new Date().toISOString().split('T')[0],
172
+ type: 'architecture',
173
+ category: 'design',
174
+ version: currentData.version || '1.0'
175
+ };
176
+ // Create the markdown content with frontmatter
177
+ const fileContent = matter.stringify(body.content, updatedMetadata);
178
+ await fs.writeFile(filePath, fileContent, 'utf-8');
179
+ // Extract updated title
180
+ const title = body.title ||
181
+ body.content.match(/^#\s+(.+)$/m)?.[1] ||
182
+ 'Architecture Overview';
183
+ return c.json({
184
+ success: true,
185
+ document: {
186
+ filename: 'architecture.md',
187
+ title,
188
+ metadata: updatedMetadata,
189
+ content: body.content
190
+ }
191
+ });
192
+ }
193
+ catch (error) {
194
+ console.error('Error updating architecture document:', error);
195
+ return c.json({ success: false, error: 'Failed to update architecture document' }, 500);
196
+ }
197
+ });
198
+ export default app;
@@ -0,0 +1,3 @@
1
+ import { Hono } from 'hono';
2
+ declare const context: Hono<import("hono/types").BlankEnv, import("hono/types").BlankSchema, "/">;
3
+ export default context;
@@ -0,0 +1,9 @@
1
+ import { Hono } from 'hono';
2
+ import project from './project/route.js';
3
+ import architecture from './architecture/route.js';
4
+ import knowledge from './knowledge/index.js';
5
+ const context = new Hono();
6
+ context.route('/project', project);
7
+ context.route('/architecture', architecture);
8
+ context.route('/knowledge', knowledge);
9
+ export default context;
@@ -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,165 @@
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 getKnowledgePath() {
7
+ const basePath = process.env.GAIT_DATA_PATH ?
8
+ path.resolve(process.env.GAIT_DATA_PATH, '.gait') :
9
+ path.resolve(process.cwd(), '.gait');
10
+ return path.join(basePath, 'context', 'knowledge');
11
+ }
12
+ function generateFilename(title) {
13
+ // Convert title to filename-safe format
14
+ return title
15
+ .toLowerCase()
16
+ .replace(/[^a-z0-9\s-]/g, '') // Remove special characters
17
+ .replace(/\s+/g, '-') // Replace spaces with hyphens
18
+ .replace(/--+/g, '-') // Replace multiple hyphens with single
19
+ .replace(/^-|-$/g, '') // Remove leading/trailing hyphens
20
+ + '.md';
21
+ }
22
+ /**
23
+ * GET /api/v1/context/knowledge/:filename
24
+ * Load a specific knowledge document
25
+ */
26
+ app.get('/:filename', async (c) => {
27
+ try {
28
+ const filename = c.req.param('filename');
29
+ const knowledgePath = getKnowledgePath();
30
+ const actualFilename = filename.endsWith('.md') ? filename : `${filename}.md`;
31
+ const filePath = path.join(knowledgePath, actualFilename);
32
+ const fileContent = await fs.readFile(filePath, 'utf-8');
33
+ const { data, content } = matter(fileContent);
34
+ // Extract title from first heading or use filename
35
+ const title = content.match(/^#\s+(.+)$/m)?.[1] ||
36
+ actualFilename.replace('.md', '').replace(/[_-]/g, ' ').replace(/\w\S*/g, (txt) => txt.charAt(0).toUpperCase() + txt.substr(1).toLowerCase());
37
+ const document = {
38
+ filename: actualFilename,
39
+ metadata: {
40
+ ...data,
41
+ updated: data.updated || new Date().toISOString().split('T')[0],
42
+ tags: data.tags || [],
43
+ sources: data.sources || []
44
+ },
45
+ content,
46
+ title
47
+ };
48
+ return c.json({
49
+ success: true,
50
+ document
51
+ });
52
+ }
53
+ catch (error) {
54
+ if (error.code === 'ENOENT') {
55
+ return c.json({ success: false, error: 'Knowledge document not found' }, 404);
56
+ }
57
+ console.error('Error loading knowledge document:', error);
58
+ return c.json({ success: false, error: 'Failed to load knowledge document' }, 500);
59
+ }
60
+ });
61
+ /**
62
+ * PUT /api/v1/context/knowledge/:filename
63
+ * Update a specific knowledge document
64
+ */
65
+ app.put('/:filename', async (c) => {
66
+ try {
67
+ const filename = c.req.param('filename');
68
+ const body = await c.req.json();
69
+ const knowledgePath = getKnowledgePath();
70
+ const actualFilename = filename.endsWith('.md') ? filename : `${filename}.md`;
71
+ const filePath = path.join(knowledgePath, actualFilename);
72
+ // Check if file exists
73
+ try {
74
+ await fs.access(filePath);
75
+ }
76
+ catch {
77
+ return c.json({ success: false, error: 'Knowledge document not found' }, 404);
78
+ }
79
+ // Read current content
80
+ const currentContent = await fs.readFile(filePath, 'utf-8');
81
+ const { data: currentData, content: currentMarkdown } = matter(currentContent);
82
+ // Prepare updated content
83
+ const updatedContent = body.content !== undefined ? body.content : currentMarkdown;
84
+ const updatedMetadata = {
85
+ ...currentData,
86
+ ...body.metadata,
87
+ updated: new Date().toISOString().split('T')[0],
88
+ // Ensure these are arrays
89
+ tags: body.metadata?.tags !== undefined ? body.metadata.tags : (currentData.tags || []),
90
+ sources: body.metadata?.sources !== undefined ? body.metadata.sources : (currentData.sources || [])
91
+ };
92
+ // Handle title change - might need to rename file
93
+ let newFilename = actualFilename;
94
+ let newFilePath = filePath;
95
+ if (body.title) {
96
+ newFilename = generateFilename(body.title);
97
+ newFilePath = path.join(knowledgePath, newFilename);
98
+ // Check if new filename conflicts with existing file (unless it's the same file)
99
+ if (newFilename !== actualFilename) {
100
+ try {
101
+ await fs.access(newFilePath);
102
+ return c.json({ success: false, error: 'A document with this title already exists' }, 409);
103
+ }
104
+ catch {
105
+ // File doesn't exist, which is what we want
106
+ }
107
+ }
108
+ }
109
+ // Create the updated markdown content with frontmatter
110
+ const fileContent = matter.stringify(updatedContent, updatedMetadata);
111
+ // Write to new location (or same location if filename unchanged)
112
+ await fs.writeFile(newFilePath, fileContent, 'utf-8');
113
+ // If filename changed, delete old file
114
+ if (newFilename !== actualFilename) {
115
+ await fs.unlink(filePath);
116
+ }
117
+ // Extract updated title
118
+ const title = body.title ||
119
+ updatedContent.match(/^#\s+(.+)$/m)?.[1] ||
120
+ newFilename.replace('.md', '').replace(/[_-]/g, ' ').replace(/\w\S*/g, (txt) => txt.charAt(0).toUpperCase() + txt.substr(1).toLowerCase());
121
+ return c.json({
122
+ success: true,
123
+ document: {
124
+ filename: newFilename,
125
+ title,
126
+ metadata: updatedMetadata,
127
+ content: updatedContent
128
+ }
129
+ });
130
+ }
131
+ catch (error) {
132
+ console.error('Error updating knowledge document:', error);
133
+ return c.json({ success: false, error: 'Failed to update knowledge document' }, 500);
134
+ }
135
+ });
136
+ /**
137
+ * DELETE /api/v1/context/knowledge/:filename
138
+ * Delete a specific knowledge document
139
+ */
140
+ app.delete('/:filename', async (c) => {
141
+ try {
142
+ const filename = c.req.param('filename');
143
+ const knowledgePath = getKnowledgePath();
144
+ const actualFilename = filename.endsWith('.md') ? filename : `${filename}.md`;
145
+ const filePath = path.join(knowledgePath, actualFilename);
146
+ // Check if file exists
147
+ try {
148
+ await fs.access(filePath);
149
+ }
150
+ catch {
151
+ return c.json({ success: false, error: 'Knowledge document not found' }, 404);
152
+ }
153
+ // Delete the file
154
+ await fs.unlink(filePath);
155
+ return c.json({
156
+ success: true,
157
+ message: 'Knowledge document deleted successfully'
158
+ });
159
+ }
160
+ catch (error) {
161
+ console.error('Error deleting knowledge document:', error);
162
+ return c.json({ success: false, error: 'Failed to delete knowledge document' }, 500);
163
+ }
164
+ });
165
+ 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;
@@ -0,0 +1,121 @@
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 filenameRoute from './[filename]/index.js';
6
+ const app = new Hono();
7
+ function getKnowledgePath() {
8
+ const basePath = process.env.GAIT_DATA_PATH ?
9
+ path.resolve(process.env.GAIT_DATA_PATH, '.gait') :
10
+ path.resolve(process.cwd(), '.gait');
11
+ return path.join(basePath, 'context', 'knowledge');
12
+ }
13
+ function generateFilename(title) {
14
+ // Convert title to filename-safe format
15
+ return title
16
+ .toLowerCase()
17
+ .replace(/[^a-z0-9\s-]/g, '') // Remove special characters
18
+ .replace(/\s+/g, '-') // Replace spaces with hyphens
19
+ .replace(/--+/g, '-') // Replace multiple hyphens with single
20
+ .replace(/^-|-$/g, '') // Remove leading/trailing hyphens
21
+ + '.md';
22
+ }
23
+ /**
24
+ * GET /api/v1/context/knowledge
25
+ * Load all knowledge documents
26
+ */
27
+ app.get('/', async (c) => {
28
+ try {
29
+ const knowledgePath = getKnowledgePath();
30
+ // Ensure directory exists
31
+ await fs.mkdir(knowledgePath, { recursive: true });
32
+ const files = await fs.readdir(knowledgePath);
33
+ const documents = await Promise.all(files
34
+ .filter(file => file.endsWith('.md'))
35
+ .map(async (file) => {
36
+ const filePath = path.join(knowledgePath, file);
37
+ const fileContent = await fs.readFile(filePath, 'utf-8');
38
+ const { data, content } = matter(fileContent);
39
+ // Extract title from first heading or use filename
40
+ const title = content.match(/^#\s+(.+)$/m)?.[1] ||
41
+ file.replace('.md', '').replace(/[_-]/g, ' ').replace(/\w\S*/g, (txt) => txt.charAt(0).toUpperCase() + txt.substr(1).toLowerCase());
42
+ return {
43
+ filename: file,
44
+ metadata: {
45
+ ...data,
46
+ updated: data.updated || new Date().toISOString().split('T')[0],
47
+ tags: data.tags || [],
48
+ sources: data.sources || []
49
+ },
50
+ content,
51
+ title
52
+ };
53
+ }));
54
+ return c.json({
55
+ success: true,
56
+ documents: documents.sort((a, b) => a.filename.localeCompare(b.filename))
57
+ });
58
+ }
59
+ catch (error) {
60
+ console.error('Error loading knowledge documents:', error);
61
+ return c.json({
62
+ success: false,
63
+ error: 'Failed to load knowledge documents',
64
+ documents: []
65
+ }, 500);
66
+ }
67
+ });
68
+ /**
69
+ * POST /api/v1/context/knowledge
70
+ * Create a new knowledge document
71
+ */
72
+ app.post('/', async (c) => {
73
+ try {
74
+ const body = await c.req.json();
75
+ if (!body.title || !body.content) {
76
+ return c.json({ success: false, error: 'Title and content are required' }, 400);
77
+ }
78
+ const knowledgePath = getKnowledgePath();
79
+ await fs.mkdir(knowledgePath, { recursive: true });
80
+ const filename = generateFilename(body.title);
81
+ const filePath = path.join(knowledgePath, filename);
82
+ // Check if file already exists
83
+ try {
84
+ await fs.access(filePath);
85
+ return c.json({ success: false, error: 'A document with this title already exists' }, 409);
86
+ }
87
+ catch {
88
+ // File doesn't exist, which is what we want
89
+ }
90
+ // Prepare frontmatter
91
+ const now = new Date();
92
+ const frontmatter = {
93
+ version: '1.0',
94
+ updated: now.toISOString().split('T')[0],
95
+ type: 'knowledge',
96
+ category: body.metadata?.category || 'general',
97
+ tags: body.metadata?.tags || [],
98
+ sources: body.metadata?.sources || [],
99
+ ...body.metadata
100
+ };
101
+ // Create the markdown content with frontmatter
102
+ const fileContent = matter.stringify(body.content, frontmatter);
103
+ await fs.writeFile(filePath, fileContent, 'utf-8');
104
+ return c.json({
105
+ success: true,
106
+ document: {
107
+ filename,
108
+ title: body.title,
109
+ metadata: frontmatter,
110
+ content: body.content
111
+ }
112
+ }, 201);
113
+ }
114
+ catch (error) {
115
+ console.error('Error creating knowledge document:', error);
116
+ return c.json({ success: false, error: 'Failed to create knowledge document' }, 500);
117
+ }
118
+ });
119
+ // Register filename route for individual documents
120
+ app.route('/', filenameRoute);
121
+ export default app;
@@ -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,153 @@
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 getProjectPath() {
7
+ const basePath = process.env.GAIT_DATA_PATH ?
8
+ path.resolve(process.env.GAIT_DATA_PATH, '.gait') :
9
+ path.resolve(process.cwd(), '.gait');
10
+ return path.join(basePath, 'context');
11
+ }
12
+ /**
13
+ * GET /api/v1/context/project
14
+ * Load project overview document
15
+ */
16
+ app.get('/', async (c) => {
17
+ try {
18
+ const projectPath = getProjectPath();
19
+ // Ensure directory exists
20
+ await fs.mkdir(projectPath, { recursive: true });
21
+ // Look for project.md file
22
+ const filePath = path.join(projectPath, 'project.md');
23
+ try {
24
+ const fileContent = await fs.readFile(filePath, 'utf-8');
25
+ const { data, content } = matter(fileContent);
26
+ // Extract title from first heading or use default
27
+ const title = content.match(/^#\s+(.+)$/m)?.[1] || 'Project Overview';
28
+ const document = {
29
+ filename: 'project.md',
30
+ metadata: {
31
+ ...data,
32
+ updated: data.updated || new Date().toISOString().split('T')[0],
33
+ type: 'project',
34
+ category: 'overview',
35
+ tags: data.tags || []
36
+ },
37
+ content,
38
+ title
39
+ };
40
+ return c.json({
41
+ success: true,
42
+ document
43
+ });
44
+ }
45
+ catch (fileError) {
46
+ // If file doesn't exist, return default content
47
+ const defaultContent = `# Project Overview
48
+
49
+ This document provides an overview of the project, including its purpose, goals, and key information.
50
+
51
+ ## Purpose
52
+
53
+ Describe the main purpose and objectives of this project.
54
+
55
+ ## Key Features
56
+
57
+ - Feature 1
58
+ - Feature 2
59
+ - Feature 3
60
+
61
+ ## Technology Stack
62
+
63
+ List the main technologies, frameworks, and tools used in this project.
64
+
65
+ ## Getting Started
66
+
67
+ Provide instructions for setting up and running the project locally.
68
+
69
+ ## Documentation
70
+
71
+ Links to additional documentation, guides, and resources.
72
+ `;
73
+ const document = {
74
+ filename: 'project.md',
75
+ metadata: {
76
+ version: '1.0',
77
+ updated: new Date().toISOString().split('T')[0],
78
+ type: 'project',
79
+ category: 'overview',
80
+ tags: []
81
+ },
82
+ content: defaultContent,
83
+ title: 'Project Overview'
84
+ };
85
+ return c.json({
86
+ success: true,
87
+ document
88
+ });
89
+ }
90
+ }
91
+ catch (error) {
92
+ console.error('Error loading project document:', error);
93
+ return c.json({
94
+ success: false,
95
+ error: 'Failed to load project document'
96
+ }, 500);
97
+ }
98
+ });
99
+ /**
100
+ * PUT /api/v1/context/project
101
+ * Update project overview document
102
+ */
103
+ app.put('/', async (c) => {
104
+ try {
105
+ const body = await c.req.json();
106
+ if (!body.content) {
107
+ return c.json({ success: false, error: 'Content is required' }, 400);
108
+ }
109
+ const projectPath = getProjectPath();
110
+ await fs.mkdir(projectPath, { recursive: true });
111
+ const filePath = path.join(projectPath, 'project.md');
112
+ // Read current content if it exists
113
+ let currentData = {};
114
+ try {
115
+ const currentContent = await fs.readFile(filePath, 'utf-8');
116
+ const { data } = matter(currentContent);
117
+ currentData = data;
118
+ }
119
+ catch {
120
+ // File doesn't exist, use defaults
121
+ }
122
+ // Prepare updated metadata
123
+ const updatedMetadata = {
124
+ ...currentData,
125
+ ...body.metadata,
126
+ updated: new Date().toISOString().split('T')[0],
127
+ type: 'project',
128
+ category: 'overview',
129
+ version: currentData.version || '1.0'
130
+ };
131
+ // Create the markdown content with frontmatter
132
+ const fileContent = matter.stringify(body.content, updatedMetadata);
133
+ await fs.writeFile(filePath, fileContent, 'utf-8');
134
+ // Extract updated title
135
+ const title = body.title ||
136
+ body.content.match(/^#\s+(.+)$/m)?.[1] ||
137
+ 'Project Overview';
138
+ return c.json({
139
+ success: true,
140
+ document: {
141
+ filename: 'project.md',
142
+ title,
143
+ metadata: updatedMetadata,
144
+ content: body.content
145
+ }
146
+ });
147
+ }
148
+ catch (error) {
149
+ console.error('Error updating project document:', error);
150
+ return c.json({ success: false, error: 'Failed to update project document' }, 500);
151
+ }
152
+ });
153
+ export default app;