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.
Files changed (119) hide show
  1. package/README.md +1 -7
  2. package/dist/index.d.ts +3 -0
  3. package/dist/index.js +92 -32
  4. package/dist/lib/response-builder.d.ts +50 -0
  5. package/dist/lib/response-builder.js +56 -0
  6. package/dist/lib/stream-helper.d.ts +39 -0
  7. package/dist/lib/stream-helper.js +43 -0
  8. package/dist/managers/ConversationManager.d.ts +83 -0
  9. package/dist/managers/ConversationManager.js +129 -0
  10. package/dist/managers/GitManager.d.ts +133 -0
  11. package/dist/managers/GitManager.js +330 -0
  12. package/dist/managers/MetadataManager.d.ts +139 -0
  13. package/dist/managers/MetadataManager.js +309 -0
  14. package/dist/managers/ModelManager.d.ts +57 -0
  15. package/dist/managers/ModelManager.js +129 -0
  16. package/dist/managers/NeovateExecutor.d.ts +40 -0
  17. package/dist/managers/NeovateExecutor.js +138 -0
  18. package/dist/managers/ProjectManager.d.ts +162 -0
  19. package/dist/managers/ProjectManager.js +353 -0
  20. package/dist/managers/ThreadManager.d.ts +181 -0
  21. package/dist/managers/ThreadManager.js +325 -0
  22. package/dist/managers/conversation-manager.d.ts +83 -0
  23. package/dist/managers/conversation-manager.js +129 -0
  24. package/dist/managers/git-manager.d.ts +133 -0
  25. package/dist/managers/git-manager.js +330 -0
  26. package/dist/managers/metadata-manager.d.ts +139 -0
  27. package/dist/managers/metadata-manager.js +305 -0
  28. package/dist/managers/model-manager.d.ts +59 -0
  29. package/dist/managers/model-manager.js +144 -0
  30. package/dist/managers/neovate-executor.d.ts +43 -0
  31. package/dist/managers/neovate-executor.js +205 -0
  32. package/dist/managers/processing-state-manager.d.ts +40 -0
  33. package/dist/managers/processing-state-manager.js +27 -0
  34. package/dist/managers/project-manager.d.ts +199 -0
  35. package/dist/managers/project-manager.js +465 -0
  36. package/dist/managers/thread-manager.d.ts +193 -0
  37. package/dist/managers/thread-manager.js +368 -0
  38. package/dist/model-info-aihubmix.d.ts +25 -0
  39. package/dist/model-info-aihubmix.js +117 -0
  40. package/dist/model-info-openai.d.ts +17 -0
  41. package/dist/model-info-openai.js +59 -0
  42. package/dist/model-info-openrouter.d.ts +25 -0
  43. package/dist/model-info-openrouter.js +101 -0
  44. package/dist/model-info.d.ts +37 -0
  45. package/dist/model-info.js +39 -0
  46. package/dist/provider-data.d.ts +101 -0
  47. package/dist/provider-data.js +471 -0
  48. package/dist/provider.d.ts +10 -0
  49. package/dist/provider.js +192 -0
  50. package/dist/public/android-chrome-192x192.png +0 -0
  51. package/dist/public/android-chrome-512x512.png +0 -0
  52. package/dist/public/apple-touch-icon.png +0 -0
  53. package/dist/public/assets/index-B443aj9k.js +8506 -0
  54. package/dist/public/assets/index-CjXGVbI7.css +1 -0
  55. package/dist/public/assets/index-DJC-p914.js +8506 -0
  56. package/dist/public/favicon-16x16.png +0 -0
  57. package/dist/public/favicon-32x32.png +0 -0
  58. package/dist/public/favicon.ico +0 -0
  59. package/dist/public/index.html +28 -0
  60. package/dist/public/manifest.json +82 -0
  61. package/dist/public/placeholder-logo.svg +1 -0
  62. package/dist/public/placeholder.svg +1 -0
  63. package/dist/public/snpro.woff2 +0 -0
  64. package/dist/public/tarsk-color.svg +12 -0
  65. package/dist/public/tarsk.png +0 -0
  66. package/dist/public/tarsk.svg +12 -0
  67. package/dist/public/zalando-sans.woff2 +0 -0
  68. package/dist/routes/chat-old.d.ts +21 -0
  69. package/dist/routes/chat-old.js +251 -0
  70. package/dist/routes/chat.d.ts +21 -0
  71. package/dist/routes/chat.js +217 -0
  72. package/dist/routes/git.d.ts +4 -0
  73. package/dist/routes/git.js +668 -0
  74. package/dist/routes/models.d.ts +18 -0
  75. package/dist/routes/models.js +128 -0
  76. package/dist/routes/projects-old.d.ts +20 -0
  77. package/dist/routes/projects-old.js +297 -0
  78. package/dist/routes/projects.d.ts +20 -0
  79. package/dist/routes/projects.js +365 -0
  80. package/dist/routes/providers.d.ts +15 -0
  81. package/dist/routes/providers.js +130 -0
  82. package/dist/routes/threads-old.d.ts +14 -0
  83. package/dist/routes/threads-old.js +393 -0
  84. package/dist/routes/threads.d.ts +14 -0
  85. package/dist/routes/threads.js +352 -0
  86. package/dist/types/models.d.ts +315 -0
  87. package/dist/types/models.js +11 -0
  88. package/dist/utils/env-manager.d.ts +3 -0
  89. package/dist/utils/env-manager.js +60 -0
  90. package/dist/utils/open-router-models.d.ts +45 -0
  91. package/dist/utils/open-router-models.js +103 -0
  92. package/dist/utils/openai-models.d.ts +63 -0
  93. package/dist/utils/openai-models.js +152 -0
  94. package/dist/utils/openai-pricing-scraper.d.ts +17 -0
  95. package/dist/utils/openai-pricing-scraper.js +185 -0
  96. package/dist/utils/validation.d.ts +10 -0
  97. package/dist/utils/validation.js +20 -0
  98. package/dist/utils.d.ts +10 -0
  99. package/dist/utils.js +12 -0
  100. package/package.json +36 -22
  101. package/LICENSE.md +0 -7
  102. package/dist/agent/agent.js +0 -131
  103. package/dist/agent/interfaces.js +0 -1
  104. package/dist/api/encryption.js +0 -41
  105. package/dist/api/models.js +0 -169
  106. package/dist/api/prompt.js +0 -12
  107. package/dist/api/settings.js +0 -43
  108. package/dist/api/test.js +0 -29
  109. package/dist/api/tools.js +0 -287
  110. package/dist/api/utils.js +0 -18
  111. package/dist/interfaces/meta.js +0 -1
  112. package/dist/interfaces/model.js +0 -1
  113. package/dist/interfaces/settings.js +0 -1
  114. package/dist/log/log.js +0 -33
  115. package/dist/prompt.js +0 -49
  116. package/dist/tools.js +0 -84
  117. package/dist/utils/files.js +0 -14
  118. package/dist/utils/json-file.js +0 -28
  119. 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