tarsk 0.2.5 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -7
- package/dist/index.d.ts +3 -0
- package/dist/index.js +92 -32
- package/dist/lib/response-builder.d.ts +50 -0
- package/dist/lib/response-builder.js +56 -0
- package/dist/lib/stream-helper.d.ts +39 -0
- package/dist/lib/stream-helper.js +43 -0
- package/dist/managers/ConversationManager.d.ts +83 -0
- package/dist/managers/ConversationManager.js +129 -0
- package/dist/managers/GitManager.d.ts +133 -0
- package/dist/managers/GitManager.js +330 -0
- package/dist/managers/MetadataManager.d.ts +139 -0
- package/dist/managers/MetadataManager.js +309 -0
- package/dist/managers/ModelManager.d.ts +57 -0
- package/dist/managers/ModelManager.js +129 -0
- package/dist/managers/NeovateExecutor.d.ts +40 -0
- package/dist/managers/NeovateExecutor.js +138 -0
- package/dist/managers/ProjectManager.d.ts +162 -0
- package/dist/managers/ProjectManager.js +353 -0
- package/dist/managers/ThreadManager.d.ts +181 -0
- package/dist/managers/ThreadManager.js +325 -0
- package/dist/managers/conversation-manager.d.ts +83 -0
- package/dist/managers/conversation-manager.js +129 -0
- package/dist/managers/git-manager.d.ts +133 -0
- package/dist/managers/git-manager.js +330 -0
- package/dist/managers/metadata-manager.d.ts +139 -0
- package/dist/managers/metadata-manager.js +305 -0
- package/dist/managers/model-manager.d.ts +59 -0
- package/dist/managers/model-manager.js +144 -0
- package/dist/managers/neovate-executor.d.ts +43 -0
- package/dist/managers/neovate-executor.js +205 -0
- package/dist/managers/processing-state-manager.d.ts +40 -0
- package/dist/managers/processing-state-manager.js +27 -0
- package/dist/managers/project-manager.d.ts +199 -0
- package/dist/managers/project-manager.js +465 -0
- package/dist/managers/thread-manager.d.ts +193 -0
- package/dist/managers/thread-manager.js +368 -0
- package/dist/model-info-aihubmix.d.ts +25 -0
- package/dist/model-info-aihubmix.js +117 -0
- package/dist/model-info-openai.d.ts +17 -0
- package/dist/model-info-openai.js +59 -0
- package/dist/model-info-openrouter.d.ts +25 -0
- package/dist/model-info-openrouter.js +101 -0
- package/dist/model-info.d.ts +37 -0
- package/dist/model-info.js +39 -0
- package/dist/provider-data.d.ts +101 -0
- package/dist/provider-data.js +471 -0
- package/dist/provider.d.ts +10 -0
- package/dist/provider.js +192 -0
- package/dist/public/android-chrome-192x192.png +0 -0
- package/dist/public/android-chrome-512x512.png +0 -0
- package/dist/public/apple-touch-icon.png +0 -0
- package/dist/public/assets/index-B443aj9k.js +8506 -0
- package/dist/public/assets/index-CjXGVbI7.css +1 -0
- package/dist/public/assets/index-DJC-p914.js +8506 -0
- package/dist/public/favicon-16x16.png +0 -0
- package/dist/public/favicon-32x32.png +0 -0
- package/dist/public/favicon.ico +0 -0
- package/dist/public/index.html +28 -0
- package/dist/public/manifest.json +82 -0
- package/dist/public/placeholder-logo.svg +1 -0
- package/dist/public/placeholder.svg +1 -0
- package/dist/public/snpro.woff2 +0 -0
- package/dist/public/tarsk-color.svg +12 -0
- package/dist/public/tarsk.png +0 -0
- package/dist/public/tarsk.svg +12 -0
- package/dist/public/zalando-sans.woff2 +0 -0
- package/dist/routes/chat-old.d.ts +21 -0
- package/dist/routes/chat-old.js +251 -0
- package/dist/routes/chat.d.ts +21 -0
- package/dist/routes/chat.js +217 -0
- package/dist/routes/git.d.ts +4 -0
- package/dist/routes/git.js +668 -0
- package/dist/routes/models.d.ts +18 -0
- package/dist/routes/models.js +128 -0
- package/dist/routes/projects-old.d.ts +20 -0
- package/dist/routes/projects-old.js +297 -0
- package/dist/routes/projects.d.ts +20 -0
- package/dist/routes/projects.js +365 -0
- package/dist/routes/providers.d.ts +15 -0
- package/dist/routes/providers.js +130 -0
- package/dist/routes/threads-old.d.ts +14 -0
- package/dist/routes/threads-old.js +393 -0
- package/dist/routes/threads.d.ts +14 -0
- package/dist/routes/threads.js +352 -0
- package/dist/types/models.d.ts +315 -0
- package/dist/types/models.js +11 -0
- package/dist/utils/env-manager.d.ts +3 -0
- package/dist/utils/env-manager.js +60 -0
- package/dist/utils/open-router-models.d.ts +45 -0
- package/dist/utils/open-router-models.js +103 -0
- package/dist/utils/openai-models.d.ts +63 -0
- package/dist/utils/openai-models.js +152 -0
- package/dist/utils/openai-pricing-scraper.d.ts +17 -0
- package/dist/utils/openai-pricing-scraper.js +185 -0
- package/dist/utils/validation.d.ts +10 -0
- package/dist/utils/validation.js +20 -0
- package/dist/utils.d.ts +10 -0
- package/dist/utils.js +12 -0
- package/package.json +36 -22
- package/LICENSE.md +0 -7
- package/dist/agent/agent.js +0 -131
- package/dist/agent/interfaces.js +0 -1
- package/dist/api/encryption.js +0 -41
- package/dist/api/models.js +0 -169
- package/dist/api/prompt.js +0 -12
- package/dist/api/settings.js +0 -43
- package/dist/api/test.js +0 -29
- package/dist/api/tools.js +0 -287
- package/dist/api/utils.js +0 -18
- package/dist/interfaces/meta.js +0 -1
- package/dist/interfaces/model.js +0 -1
- package/dist/interfaces/settings.js +0 -1
- package/dist/log/log.js +0 -33
- package/dist/prompt.js +0 -49
- package/dist/tools.js +0 -84
- package/dist/utils/files.js +0 -14
- package/dist/utils/json-file.js +0 -28
- package/dist/utils/strip-markdown.js +0 -5
|
@@ -0,0 +1,365 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Project routes for the REST API
|
|
3
|
+
*
|
|
4
|
+
* Handles all project-related operations:
|
|
5
|
+
* - POST /api/projects - Create a new project
|
|
6
|
+
* - GET /api/projects - List all projects
|
|
7
|
+
* - GET /api/projects/:id - Get project details
|
|
8
|
+
* - DELETE /api/projects/:id - Delete a project
|
|
9
|
+
*/
|
|
10
|
+
import { Hono } from 'hono';
|
|
11
|
+
import { AVAILABLE_PROGRAMS } from '../types/models.js';
|
|
12
|
+
import { streamAsyncGenerator } from '../lib/stream-helper.js';
|
|
13
|
+
import { ResponseBuilder } from '../lib/response-builder.js';
|
|
14
|
+
/**
|
|
15
|
+
* Creates project routes
|
|
16
|
+
* @param projectManager - The ProjectManager instance
|
|
17
|
+
* @param threadManager - The ThreadManager instance
|
|
18
|
+
* @returns Hono router with project routes
|
|
19
|
+
*/
|
|
20
|
+
export function createProjectRoutes(projectManager, threadManager) {
|
|
21
|
+
const router = new Hono();
|
|
22
|
+
/**
|
|
23
|
+
* POST /api/projects
|
|
24
|
+
* Create a new project from a git URL
|
|
25
|
+
*
|
|
26
|
+
* Request body:
|
|
27
|
+
* {
|
|
28
|
+
* "gitUrl": "https://github.com/user/repo.git"
|
|
29
|
+
* }
|
|
30
|
+
*
|
|
31
|
+
* Response: Newline-delimited JSON stream of ProjectEvent objects
|
|
32
|
+
*
|
|
33
|
+
* Requirements:
|
|
34
|
+
* - 6.2 - THE App SHALL send a POST request with the git URL to the CLI
|
|
35
|
+
* - 8.2 - THE CLI SHALL support streaming responses to the client
|
|
36
|
+
*/
|
|
37
|
+
router.post('/', async (c) => {
|
|
38
|
+
try {
|
|
39
|
+
const body = await c.req.json();
|
|
40
|
+
const { gitUrl } = body;
|
|
41
|
+
// Validate gitUrl is provided
|
|
42
|
+
if (!gitUrl || typeof gitUrl !== 'string') {
|
|
43
|
+
const { response, statusCode } = ResponseBuilder.error('INVALID_REQUEST', 'gitUrl is required and must be a string', 400);
|
|
44
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
45
|
+
return c.json(response, statusCode);
|
|
46
|
+
}
|
|
47
|
+
// Stream the project creation events
|
|
48
|
+
return streamAsyncGenerator(c, projectManager.createProject(gitUrl));
|
|
49
|
+
}
|
|
50
|
+
catch (error) {
|
|
51
|
+
const { response, statusCode } = ResponseBuilder.error('REQUEST_PARSE_ERROR', 'Failed to parse request body', 400, error instanceof Error ? error.message : String(error));
|
|
52
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
53
|
+
return c.json(response, statusCode);
|
|
54
|
+
}
|
|
55
|
+
});
|
|
56
|
+
/**
|
|
57
|
+
* GET /api/projects
|
|
58
|
+
* List all projects with expanded threads
|
|
59
|
+
*
|
|
60
|
+
* Response:
|
|
61
|
+
* [
|
|
62
|
+
* {
|
|
63
|
+
* "projectId": "uuid",
|
|
64
|
+
* "gitUrl": "https://github.com/user/repo.git",
|
|
65
|
+
* "projectPath": "/path/to/project",
|
|
66
|
+
* "threads": [
|
|
67
|
+
* {
|
|
68
|
+
* "threadId": "uuid",
|
|
69
|
+
* "title": "thread-title",
|
|
70
|
+
* "path": "/path/to/thread",
|
|
71
|
+
* "isSelected": false
|
|
72
|
+
* }
|
|
73
|
+
* ]
|
|
74
|
+
* }
|
|
75
|
+
* ]
|
|
76
|
+
*
|
|
77
|
+
* Requirements:
|
|
78
|
+
* - 6.2 - THE CLI SHALL expose REST API endpoints for Project operations
|
|
79
|
+
*/
|
|
80
|
+
router.get('/', async (c) => {
|
|
81
|
+
try {
|
|
82
|
+
const projects = await projectManager.listProjects();
|
|
83
|
+
// Get the currently selected thread
|
|
84
|
+
const selectedThreadId = await threadManager.getSelectedThreadId();
|
|
85
|
+
// Expand threads for each project
|
|
86
|
+
const expandedProjects = await Promise.all(projects.map(async (project) => {
|
|
87
|
+
const threads = await threadManager.listThreads(project.id);
|
|
88
|
+
return {
|
|
89
|
+
projectId: project.id,
|
|
90
|
+
gitUrl: project.gitUrl,
|
|
91
|
+
projectPath: project.path,
|
|
92
|
+
openWith: project.openWith,
|
|
93
|
+
commands: project.commands || [],
|
|
94
|
+
threads: threads.map(thread => ({
|
|
95
|
+
threadId: thread.id,
|
|
96
|
+
title: thread.title,
|
|
97
|
+
path: thread.path,
|
|
98
|
+
isSelected: thread.id === selectedThreadId
|
|
99
|
+
}))
|
|
100
|
+
};
|
|
101
|
+
}));
|
|
102
|
+
return c.json(expandedProjects);
|
|
103
|
+
}
|
|
104
|
+
catch (error) {
|
|
105
|
+
const { response, statusCode } = ResponseBuilder.error('LIST_PROJECTS_ERROR', 'Failed to list projects', 500, error instanceof Error ? error.message : String(error));
|
|
106
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
107
|
+
return c.json(response, statusCode);
|
|
108
|
+
}
|
|
109
|
+
});
|
|
110
|
+
/**
|
|
111
|
+
* GET /api/projects/:id
|
|
112
|
+
* Get project details by ID
|
|
113
|
+
*
|
|
114
|
+
* Response:
|
|
115
|
+
* {
|
|
116
|
+
* "id": "uuid",
|
|
117
|
+
* "name": "project-name",
|
|
118
|
+
* "gitUrl": "https://github.com/user/repo.git",
|
|
119
|
+
* "path": "/path/to/project",
|
|
120
|
+
* "createdAt": "2024-01-01T00:00:00Z",
|
|
121
|
+
* "threads": ["thread-id-1", "thread-id-2"]
|
|
122
|
+
* }
|
|
123
|
+
*
|
|
124
|
+
* Requirements:
|
|
125
|
+
* - 6.2 - THE CLI SHALL expose REST API endpoints for Project operations
|
|
126
|
+
*/
|
|
127
|
+
router.get('/:id', async (c) => {
|
|
128
|
+
try {
|
|
129
|
+
const projectId = c.req.param('id');
|
|
130
|
+
if (!projectId) {
|
|
131
|
+
const { response, statusCode } = ResponseBuilder.error('INVALID_REQUEST', 'Project ID is required', 400);
|
|
132
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
133
|
+
return c.json(response, statusCode);
|
|
134
|
+
}
|
|
135
|
+
const project = await projectManager.getProject(projectId);
|
|
136
|
+
if (!project) {
|
|
137
|
+
const { response, statusCode } = ResponseBuilder.error('PROJECT_NOT_FOUND', `Project not found: ${projectId}`, 404);
|
|
138
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
139
|
+
return c.json(response, statusCode);
|
|
140
|
+
}
|
|
141
|
+
return c.json(project);
|
|
142
|
+
}
|
|
143
|
+
catch (error) {
|
|
144
|
+
const { response, statusCode } = ResponseBuilder.error('GET_PROJECT_ERROR', 'Failed to get project', 500, error instanceof Error ? error.message : String(error));
|
|
145
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
146
|
+
return c.json(response, statusCode);
|
|
147
|
+
}
|
|
148
|
+
});
|
|
149
|
+
/**
|
|
150
|
+
* DELETE /api/projects/:id
|
|
151
|
+
* Delete a project and all its threads
|
|
152
|
+
*
|
|
153
|
+
* Response:
|
|
154
|
+
* {
|
|
155
|
+
* "success": true,
|
|
156
|
+
* "message": "Project deleted successfully"
|
|
157
|
+
* }
|
|
158
|
+
*
|
|
159
|
+
* Requirements:
|
|
160
|
+
* - 6.2 - THE CLI SHALL expose REST API endpoints for Project operations
|
|
161
|
+
*/
|
|
162
|
+
router.delete('/:id', async (c) => {
|
|
163
|
+
try {
|
|
164
|
+
const projectId = c.req.param('id');
|
|
165
|
+
if (!projectId) {
|
|
166
|
+
const { response, statusCode } = ResponseBuilder.error('INVALID_REQUEST', 'Project ID is required', 400);
|
|
167
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
168
|
+
return c.json(response, statusCode);
|
|
169
|
+
}
|
|
170
|
+
await projectManager.deleteProject(projectId);
|
|
171
|
+
const { response, statusCode } = ResponseBuilder.success({ success: true, message: 'Project deleted successfully' });
|
|
172
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
173
|
+
return c.json(response, statusCode);
|
|
174
|
+
}
|
|
175
|
+
catch (error) {
|
|
176
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
177
|
+
// Check if it's a "not found" error
|
|
178
|
+
if (errorMessage.includes('not found')) {
|
|
179
|
+
const { response, statusCode } = ResponseBuilder.error('PROJECT_NOT_FOUND', errorMessage, 404);
|
|
180
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
181
|
+
return c.json(response, statusCode);
|
|
182
|
+
}
|
|
183
|
+
const { response, statusCode } = ResponseBuilder.error('DELETE_PROJECT_ERROR', 'Failed to delete project', 500, errorMessage);
|
|
184
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
185
|
+
return c.json(response, statusCode);
|
|
186
|
+
}
|
|
187
|
+
});
|
|
188
|
+
/**
|
|
189
|
+
* POST /api/projects/:id/open
|
|
190
|
+
* Open a project in the specified program
|
|
191
|
+
*
|
|
192
|
+
* Request body:
|
|
193
|
+
* {
|
|
194
|
+
* "program": "VS Code" | "Cursor" | "Windsurf" | "Xcode" | "Android Studio" | "Kiro"
|
|
195
|
+
* }
|
|
196
|
+
*
|
|
197
|
+
* Response:
|
|
198
|
+
* {
|
|
199
|
+
* "success": true,
|
|
200
|
+
* "message": "Project opened in VS Code"
|
|
201
|
+
* }
|
|
202
|
+
*/
|
|
203
|
+
router.post('/:id/open', async (c) => {
|
|
204
|
+
try {
|
|
205
|
+
const projectId = c.req.param('id');
|
|
206
|
+
const body = await c.req.json();
|
|
207
|
+
const { program } = body;
|
|
208
|
+
if (!projectId) {
|
|
209
|
+
const { response, statusCode } = ResponseBuilder.error('INVALID_REQUEST', 'Project ID is required', 400);
|
|
210
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
211
|
+
return c.json(response, statusCode);
|
|
212
|
+
}
|
|
213
|
+
if (!program) {
|
|
214
|
+
const { response, statusCode } = ResponseBuilder.error('INVALID_REQUEST', 'Program is required', 400);
|
|
215
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
216
|
+
return c.json(response, statusCode);
|
|
217
|
+
}
|
|
218
|
+
if (!AVAILABLE_PROGRAMS.includes(program)) {
|
|
219
|
+
const { response, statusCode } = ResponseBuilder.error('INVALID_REQUEST', `Invalid program. Must be one of: ${AVAILABLE_PROGRAMS.join(', ')}`, 400);
|
|
220
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
221
|
+
return c.json(response, statusCode);
|
|
222
|
+
}
|
|
223
|
+
const project = await projectManager.getProject(projectId);
|
|
224
|
+
if (!project) {
|
|
225
|
+
const { response, statusCode } = ResponseBuilder.error('PROJECT_NOT_FOUND', `Project not found: ${projectId}`, 404);
|
|
226
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
227
|
+
return c.json(response, statusCode);
|
|
228
|
+
}
|
|
229
|
+
await projectManager.openWith(projectId, program);
|
|
230
|
+
const { response, statusCode } = ResponseBuilder.success({ success: true, message: `Project opened in ${program}` });
|
|
231
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
232
|
+
return c.json(response, statusCode);
|
|
233
|
+
}
|
|
234
|
+
catch (error) {
|
|
235
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
236
|
+
const { response, statusCode } = ResponseBuilder.error('OPEN_PROGRAM_ERROR', 'Failed to open project', 500, errorMessage);
|
|
237
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
238
|
+
return c.json(response, statusCode);
|
|
239
|
+
}
|
|
240
|
+
});
|
|
241
|
+
/**
|
|
242
|
+
* PUT /api/projects/:id/open-with
|
|
243
|
+
* Update the project's open-with program preference
|
|
244
|
+
*
|
|
245
|
+
* Request body:
|
|
246
|
+
* {
|
|
247
|
+
* "program": "VS Code" | "Cursor" | "Windsurf" | "Xcode" | "Android Studio" | "Kiro"
|
|
248
|
+
* }
|
|
249
|
+
*
|
|
250
|
+
* Response:
|
|
251
|
+
* {
|
|
252
|
+
* "success": true,
|
|
253
|
+
* "message": "Open-with program updated"
|
|
254
|
+
* }
|
|
255
|
+
*/
|
|
256
|
+
router.put('/:id/open-with', async (c) => {
|
|
257
|
+
try {
|
|
258
|
+
const projectId = c.req.param('id');
|
|
259
|
+
const body = await c.req.json();
|
|
260
|
+
const { program } = body;
|
|
261
|
+
if (!projectId) {
|
|
262
|
+
const { response, statusCode } = ResponseBuilder.error('INVALID_REQUEST', 'Project ID is required', 400);
|
|
263
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
264
|
+
return c.json(response, statusCode);
|
|
265
|
+
}
|
|
266
|
+
if (!program) {
|
|
267
|
+
const { response, statusCode } = ResponseBuilder.error('INVALID_REQUEST', 'Program is required', 400);
|
|
268
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
269
|
+
return c.json(response, statusCode);
|
|
270
|
+
}
|
|
271
|
+
if (!AVAILABLE_PROGRAMS.includes(program)) {
|
|
272
|
+
const { response, statusCode } = ResponseBuilder.error('INVALID_REQUEST', `Invalid program. Must be one of: ${AVAILABLE_PROGRAMS.join(', ')}`, 400);
|
|
273
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
274
|
+
return c.json(response, statusCode);
|
|
275
|
+
}
|
|
276
|
+
const project = await projectManager.getProject(projectId);
|
|
277
|
+
if (!project) {
|
|
278
|
+
const { response, statusCode } = ResponseBuilder.error('PROJECT_NOT_FOUND', `Project not found: ${projectId}`, 404);
|
|
279
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
280
|
+
return c.json(response, statusCode);
|
|
281
|
+
}
|
|
282
|
+
await projectManager.updateOpenWith(projectId, program);
|
|
283
|
+
const { response, statusCode } = ResponseBuilder.success({ success: true, message: 'Open-with program updated' });
|
|
284
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
285
|
+
return c.json(response, statusCode);
|
|
286
|
+
}
|
|
287
|
+
catch (error) {
|
|
288
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
289
|
+
const { response, statusCode } = ResponseBuilder.error('UPDATE_PROGRAM_ERROR', 'Failed to update open-with program', 500, errorMessage);
|
|
290
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
291
|
+
return c.json(response, statusCode);
|
|
292
|
+
}
|
|
293
|
+
});
|
|
294
|
+
/**
|
|
295
|
+
* POST /api/projects/:id/commands
|
|
296
|
+
* Add or update a command for a project
|
|
297
|
+
*/
|
|
298
|
+
router.post('/:id/commands', async (c) => {
|
|
299
|
+
try {
|
|
300
|
+
const projectId = c.req.param('id');
|
|
301
|
+
const command = await c.req.json();
|
|
302
|
+
if (!projectId) {
|
|
303
|
+
const { response, statusCode } = ResponseBuilder.error('INVALID_REQUEST', 'Project ID is required', 400);
|
|
304
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
305
|
+
return c.json(response, statusCode);
|
|
306
|
+
}
|
|
307
|
+
await projectManager.saveCommand(projectId, command);
|
|
308
|
+
const { response, statusCode } = ResponseBuilder.success({ success: true, message: 'Command saved' });
|
|
309
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
310
|
+
return c.json(response, statusCode);
|
|
311
|
+
}
|
|
312
|
+
catch (error) {
|
|
313
|
+
const { response, statusCode } = ResponseBuilder.error('SAVE_COMMAND_ERROR', 'Failed to save command', 500, error instanceof Error ? error.message : String(error));
|
|
314
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
315
|
+
return c.json(response, statusCode);
|
|
316
|
+
}
|
|
317
|
+
});
|
|
318
|
+
/**
|
|
319
|
+
* DELETE /api/projects/:id/commands/:commandId
|
|
320
|
+
* Delete a command from a project
|
|
321
|
+
*/
|
|
322
|
+
router.delete('/:id/commands/:commandId', async (c) => {
|
|
323
|
+
try {
|
|
324
|
+
const projectId = c.req.param('id');
|
|
325
|
+
const commandId = c.req.param('commandId');
|
|
326
|
+
if (!projectId || !commandId) {
|
|
327
|
+
const { response, statusCode } = ResponseBuilder.error('INVALID_REQUEST', 'Project ID and Command ID are required', 400);
|
|
328
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
329
|
+
return c.json(response, statusCode);
|
|
330
|
+
}
|
|
331
|
+
await projectManager.deleteCommand(projectId, commandId);
|
|
332
|
+
const { response, statusCode } = ResponseBuilder.success({ success: true, message: 'Command deleted' });
|
|
333
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
334
|
+
return c.json(response, statusCode);
|
|
335
|
+
}
|
|
336
|
+
catch (error) {
|
|
337
|
+
const { response, statusCode } = ResponseBuilder.error('DELETE_COMMAND_ERROR', 'Failed to delete command', 500, error instanceof Error ? error.message : String(error));
|
|
338
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
339
|
+
return c.json(response, statusCode);
|
|
340
|
+
}
|
|
341
|
+
});
|
|
342
|
+
/**
|
|
343
|
+
* POST /api/projects/:projectId/threads/:threadId/commands/run
|
|
344
|
+
* Run a command in a thread's directory
|
|
345
|
+
*/
|
|
346
|
+
router.post('/:projectId/threads/:threadId/commands/run', async (c) => {
|
|
347
|
+
try {
|
|
348
|
+
const threadId = c.req.param('threadId');
|
|
349
|
+
const { commandLine, cwd } = await c.req.json();
|
|
350
|
+
if (!threadId || !commandLine) {
|
|
351
|
+
const { response, statusCode } = ResponseBuilder.error('INVALID_REQUEST', 'Thread ID and commandLine are required', 400);
|
|
352
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
353
|
+
return c.json(response, statusCode);
|
|
354
|
+
}
|
|
355
|
+
return streamAsyncGenerator(c, projectManager.runCommand(threadId, commandLine, cwd));
|
|
356
|
+
}
|
|
357
|
+
catch (error) {
|
|
358
|
+
const { response, statusCode } = ResponseBuilder.error('RUN_COMMAND_ERROR', 'Failed to run command', 500, error instanceof Error ? error.message : String(error));
|
|
359
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
360
|
+
return c.json(response, statusCode);
|
|
361
|
+
}
|
|
362
|
+
});
|
|
363
|
+
return router;
|
|
364
|
+
}
|
|
365
|
+
//# sourceMappingURL=projects.js.map
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Provider routes for the REST API
|
|
3
|
+
*
|
|
4
|
+
* Handles all provider-related operations:
|
|
5
|
+
* - GET /api/providers - List all built-in providers
|
|
6
|
+
*/
|
|
7
|
+
import { Hono } from 'hono';
|
|
8
|
+
import { MetadataManager } from '../managers/metadata-manager.js';
|
|
9
|
+
/**
|
|
10
|
+
* Creates provider routes
|
|
11
|
+
* @param metadataManager - Manager for metadata persistence
|
|
12
|
+
* @returns Hono router with provider routes
|
|
13
|
+
*/
|
|
14
|
+
export declare function createProviderRoutes(metadataManager: MetadataManager): Hono;
|
|
15
|
+
//# sourceMappingURL=providers.d.ts.map
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Provider routes for the REST API
|
|
3
|
+
*
|
|
4
|
+
* Handles all provider-related operations:
|
|
5
|
+
* - GET /api/providers - List all built-in providers
|
|
6
|
+
*/
|
|
7
|
+
import { Hono } from 'hono';
|
|
8
|
+
import { PROVIDERS } from '../provider.js';
|
|
9
|
+
import { getOpenRouterCredits } from '../model-info-openrouter.js';
|
|
10
|
+
import { getAIHubMixCredits } from '../model-info-aihubmix.js';
|
|
11
|
+
import { updateEnvFile, readEnvFile } from '../utils/env-manager.js';
|
|
12
|
+
/**
|
|
13
|
+
* Creates provider routes
|
|
14
|
+
* @param metadataManager - Manager for metadata persistence
|
|
15
|
+
* @returns Hono router with provider routes
|
|
16
|
+
*/
|
|
17
|
+
export function createProviderRoutes(metadataManager) {
|
|
18
|
+
const router = new Hono();
|
|
19
|
+
/**
|
|
20
|
+
* GET /api/providers
|
|
21
|
+
* Get all built-in providers with their stored API keys
|
|
22
|
+
*/
|
|
23
|
+
router.get('/', async (c) => {
|
|
24
|
+
const keys = await metadataManager.getProviderKeys();
|
|
25
|
+
const envFileKeys = await readEnvFile();
|
|
26
|
+
const providersWithKeys = PROVIDERS.map(p => {
|
|
27
|
+
// Priority: metadata storage > .env file > environment variables
|
|
28
|
+
const storedKey = keys[p.name];
|
|
29
|
+
const envFileKey = p.keyName ? envFileKeys[p.keyName] : '';
|
|
30
|
+
const processEnvKey = p.keyName ? process.env[p.keyName] : '';
|
|
31
|
+
return {
|
|
32
|
+
...p,
|
|
33
|
+
apiKey: storedKey || envFileKey || processEnvKey || ''
|
|
34
|
+
};
|
|
35
|
+
});
|
|
36
|
+
return c.json(providersWithKeys);
|
|
37
|
+
});
|
|
38
|
+
/**
|
|
39
|
+
* POST /api/providers/keys
|
|
40
|
+
* Save a provider API key
|
|
41
|
+
*/
|
|
42
|
+
router.post('/keys', async (c) => {
|
|
43
|
+
try {
|
|
44
|
+
const { providerName, apiKey } = await c.req.json();
|
|
45
|
+
if (!providerName) {
|
|
46
|
+
return c.json({ error: 'providerName is required' }, 400);
|
|
47
|
+
}
|
|
48
|
+
await metadataManager.saveProviderKey(providerName, apiKey);
|
|
49
|
+
// Also update .env if provider has a keyName
|
|
50
|
+
const provider = PROVIDERS.find(p => p.name === providerName);
|
|
51
|
+
if (provider && provider.keyName) {
|
|
52
|
+
await updateEnvFile({ [provider.keyName]: apiKey });
|
|
53
|
+
}
|
|
54
|
+
return c.json({ success: true });
|
|
55
|
+
}
|
|
56
|
+
catch (error) {
|
|
57
|
+
return c.json({ error: `Failed to save provider key: ${error}` }, 500);
|
|
58
|
+
}
|
|
59
|
+
});
|
|
60
|
+
/**
|
|
61
|
+
* POST /api/providers/bulk-keys
|
|
62
|
+
* Save all provider API keys at once
|
|
63
|
+
*/
|
|
64
|
+
router.post('/bulk-keys', async (c) => {
|
|
65
|
+
try {
|
|
66
|
+
const { keys } = await c.req.json(); // keys is Record<string, string> where key is providerName
|
|
67
|
+
if (!keys || typeof keys !== 'object') {
|
|
68
|
+
return c.json({ error: 'keys object is required' }, 400);
|
|
69
|
+
}
|
|
70
|
+
await metadataManager.saveAllProviderKeys(keys);
|
|
71
|
+
// Also update .env for all providers that have a keyName
|
|
72
|
+
const envUpdates = {};
|
|
73
|
+
for (const [providerName, apiKey] of Object.entries(keys)) {
|
|
74
|
+
const provider = PROVIDERS.find(p => p.name === providerName);
|
|
75
|
+
if (provider && provider.keyName) {
|
|
76
|
+
envUpdates[provider.keyName] = apiKey;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
if (Object.keys(envUpdates).length > 0) {
|
|
80
|
+
await updateEnvFile(envUpdates);
|
|
81
|
+
}
|
|
82
|
+
return c.json({ success: true });
|
|
83
|
+
}
|
|
84
|
+
catch (error) {
|
|
85
|
+
return c.json({ error: `Failed to save bulk provider keys: ${error}` }, 500);
|
|
86
|
+
}
|
|
87
|
+
});
|
|
88
|
+
/**
|
|
89
|
+
* GET /api/providers/:name/credits
|
|
90
|
+
* Get current balance for a provider
|
|
91
|
+
*/
|
|
92
|
+
router.get('/:name/credits', async (c) => {
|
|
93
|
+
const name = c.req.param('name');
|
|
94
|
+
if (name.toLowerCase() === 'openrouter') {
|
|
95
|
+
try {
|
|
96
|
+
const keys = await metadataManager.getProviderKeys();
|
|
97
|
+
const envFileKeys = await readEnvFile();
|
|
98
|
+
const provider = PROVIDERS.find(p => p.name.toLowerCase() === 'openrouter');
|
|
99
|
+
const apiKey = keys['OpenRouter'] || (provider?.keyName ? (envFileKeys[provider.keyName] || process.env[provider.keyName]) : '');
|
|
100
|
+
if (!apiKey) {
|
|
101
|
+
return c.json({ balance: null, status: 'unknown', reason: 'No API key' });
|
|
102
|
+
}
|
|
103
|
+
const credits = await getOpenRouterCredits(apiKey);
|
|
104
|
+
return c.json(credits);
|
|
105
|
+
}
|
|
106
|
+
catch (error) {
|
|
107
|
+
return c.json({ balance: null, status: 'unknown', reason: String(error) });
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
if (name.toLowerCase() === 'aihubmix' || name.toLowerCase() === 'aihub') {
|
|
111
|
+
try {
|
|
112
|
+
const keys = await metadataManager.getProviderKeys();
|
|
113
|
+
const envFileKeys = await readEnvFile();
|
|
114
|
+
const provider = PROVIDERS.find(p => p.name.toLowerCase() === 'aihubmix');
|
|
115
|
+
const apiKey = keys['AIHubMix'] || (provider?.keyName ? (envFileKeys[provider.keyName] || process.env[provider.keyName]) : '');
|
|
116
|
+
if (!apiKey) {
|
|
117
|
+
return c.json({ balance: null, status: 'unknown', reason: 'No API key' });
|
|
118
|
+
}
|
|
119
|
+
const credits = await getAIHubMixCredits(apiKey);
|
|
120
|
+
return c.json(credits);
|
|
121
|
+
}
|
|
122
|
+
catch (error) {
|
|
123
|
+
return c.json({ balance: null, status: 'unknown', reason: String(error) });
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
return c.json({ balance: null, status: 'unknown' });
|
|
127
|
+
});
|
|
128
|
+
return router;
|
|
129
|
+
}
|
|
130
|
+
//# sourceMappingURL=providers.js.map
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Thread routes for the REST API
|
|
3
|
+
*
|
|
4
|
+
* Handles all thread-related operations:
|
|
5
|
+
* - POST /api/threads - Create a new thread
|
|
6
|
+
* - GET /api/threads?projectId=xxx - List threads for a project
|
|
7
|
+
* - DELETE /api/threads/:id - Delete a thread
|
|
8
|
+
*/
|
|
9
|
+
import { Hono } from 'hono';
|
|
10
|
+
import type { ThreadManager } from '../managers/thread-manager.js';
|
|
11
|
+
import type { ConversationManager } from '../managers/conversation-manager.js';
|
|
12
|
+
import type { GitManager } from '../managers/git-manager.js';
|
|
13
|
+
export declare function createThreadRoutes(threadManager: ThreadManager, gitManager: GitManager, conversationManager: ConversationManager): Hono;
|
|
14
|
+
//# sourceMappingURL=threads-old.d.ts.map
|