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,393 @@
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 { validateThreadName } from '../utils/validation.js';
11
+ import { streamAsyncGenerator } from '../lib/stream-helper.js';
12
+ const extractTextBlocksFromContent = (content) => {
13
+ const trimmed = content.trim();
14
+ if (!trimmed.startsWith('[') && !trimmed.startsWith('{')) {
15
+ return [];
16
+ }
17
+ try {
18
+ const parsed = JSON.parse(trimmed);
19
+ if (Array.isArray(parsed)) {
20
+ return parsed
21
+ .filter((block) => block && typeof block === 'object' && block.type === 'text')
22
+ .map((block) => (typeof block.text === 'string' ? block.text : ''))
23
+ .filter((text) => text.length > 0);
24
+ }
25
+ if (parsed && typeof parsed === 'object' && typeof parsed.text === 'string') {
26
+ return [parsed.text];
27
+ }
28
+ }
29
+ catch {
30
+ return [];
31
+ }
32
+ return [];
33
+ };
34
+ const extractAssistantContent = (events, fallback) => {
35
+ if (!events || events.length === 0) {
36
+ return fallback;
37
+ }
38
+ const resultEvent = [...events].reverse().find((event) => event.type === 'result');
39
+ if (resultEvent && typeof resultEvent.content === 'string' && resultEvent.content.trim().length > 0) {
40
+ return resultEvent.content;
41
+ }
42
+ const assistantMessages = events.filter((event) => event.type === 'message' && event.role === 'assistant');
43
+ let lastTextBlock = null;
44
+ const assistantChunks = [];
45
+ for (const event of assistantMessages) {
46
+ if (typeof event.content !== 'string') {
47
+ continue;
48
+ }
49
+ assistantChunks.push(event.content);
50
+ const textBlocks = extractTextBlocksFromContent(event.content);
51
+ if (textBlocks.length > 0) {
52
+ lastTextBlock = textBlocks[textBlocks.length - 1];
53
+ }
54
+ }
55
+ if (lastTextBlock) {
56
+ return lastTextBlock;
57
+ }
58
+ if (assistantChunks.length === 0) {
59
+ return fallback;
60
+ }
61
+ const combined = assistantChunks.join('');
62
+ return combined.trim().length > 0 ? combined : fallback;
63
+ };
64
+ export function createThreadRoutes(threadManager, gitManager, conversationManager) {
65
+ const router = new Hono();
66
+ /**
67
+ * POST /api/threads
68
+ * Create a new thread for a project
69
+ *
70
+ * Request body:
71
+ * {
72
+ * "projectId": "uuid",
73
+ * "title": "Optional thread title"
74
+ * }
75
+ *
76
+ * Response: Newline-delimited JSON stream of ThreadEvent objects
77
+ *
78
+ * Requirements:
79
+ * - 6.3 - THE CLI SHALL expose REST API endpoints for Thread operations
80
+ * - 8.3 - WHEN creating a Thread, THE App SHALL send a POST request with the Project identifier to the CLI
81
+ * - 8.4 - THE CLI SHALL support streaming responses to the client
82
+ */
83
+ router.post('/', async (c) => {
84
+ try {
85
+ const body = await c.req.json();
86
+ const { projectId, title } = body;
87
+ // Validate projectId is provided
88
+ if (!projectId || typeof projectId !== 'string') {
89
+ const errorResponse = {
90
+ error: {
91
+ code: 'INVALID_REQUEST',
92
+ message: 'projectId is required and must be a string',
93
+ timestamp: new Date().toISOString()
94
+ }
95
+ };
96
+ return c.json(errorResponse, 400);
97
+ }
98
+ // Validate title if provided
99
+ if (title !== undefined && typeof title !== 'string') {
100
+ const errorResponse = {
101
+ error: {
102
+ code: 'INVALID_REQUEST',
103
+ message: 'title must be a string if provided',
104
+ timestamp: new Date().toISOString()
105
+ }
106
+ };
107
+ return c.json(errorResponse, 400);
108
+ }
109
+ // Validate thread name (empty/whitespace is allowed, will auto-generate)
110
+ if (title && title.trim() !== '') {
111
+ const nameError = validateThreadName(title);
112
+ if (nameError) {
113
+ const errorResponse = {
114
+ error: {
115
+ code: 'INVALID_REQUEST',
116
+ message: nameError,
117
+ timestamp: new Date().toISOString()
118
+ }
119
+ };
120
+ return c.json(errorResponse, 400);
121
+ }
122
+ // Check for duplicate branch names
123
+ const existingThreads = await threadManager.listThreads(projectId);
124
+ const sanitizedNewName = gitManager.sanitizeBranchName(title);
125
+ const existingSanitized = existingThreads.map(t => gitManager.sanitizeBranchName(t.title));
126
+ if (existingSanitized.includes(sanitizedNewName)) {
127
+ const errorResponse = {
128
+ error: {
129
+ code: 'DUPLICATE_BRANCH',
130
+ message: `A thread with branch name "${sanitizedNewName}" already exists`,
131
+ timestamp: new Date().toISOString()
132
+ }
133
+ };
134
+ return c.json(errorResponse, 409);
135
+ }
136
+ }
137
+ // Stream the thread creation events
138
+ return streamAsyncGenerator(c, threadManager.createThread(projectId, title));
139
+ }
140
+ catch (error) {
141
+ const errorResponse = {
142
+ error: {
143
+ code: 'REQUEST_PARSE_ERROR',
144
+ message: 'Failed to parse request body',
145
+ details: error instanceof Error ? error.message : String(error),
146
+ timestamp: new Date().toISOString()
147
+ }
148
+ };
149
+ return c.json(errorResponse, 400);
150
+ }
151
+ });
152
+ /**
153
+ * GET /api/threads?projectId=xxx
154
+ * List all threads for a specific project
155
+ *
156
+ * Query parameters:
157
+ * - projectId (required): The project ID to filter threads
158
+ *
159
+ * Response:
160
+ * [
161
+ * {
162
+ * "id": "uuid",
163
+ * "projectId": "uuid",
164
+ * "title": "Thread title",
165
+ * "path": "/path/to/thread",
166
+ * "currentBranch": "branch-name",
167
+ * "createdAt": "2024-01-01T00:00:00Z"
168
+ * }
169
+ * ]
170
+ *
171
+ * Requirements:
172
+ * - 6.3 - THE CLI SHALL expose REST API endpoints for Thread operations
173
+ */
174
+ router.get('/', async (c) => {
175
+ try {
176
+ const projectId = c.req.query('projectId');
177
+ // Validate projectId is provided
178
+ if (!projectId) {
179
+ const errorResponse = {
180
+ error: {
181
+ code: 'INVALID_REQUEST',
182
+ message: 'projectId query parameter is required',
183
+ timestamp: new Date().toISOString()
184
+ }
185
+ };
186
+ return c.json(errorResponse, 400);
187
+ }
188
+ const threads = await threadManager.listThreads(projectId);
189
+ return c.json(threads);
190
+ }
191
+ catch (error) {
192
+ const errorResponse = {
193
+ error: {
194
+ code: 'LIST_THREADS_ERROR',
195
+ message: 'Failed to list threads',
196
+ details: error instanceof Error ? error.message : String(error),
197
+ timestamp: new Date().toISOString()
198
+ }
199
+ };
200
+ return c.json(errorResponse, 500);
201
+ }
202
+ });
203
+ /**
204
+ * DELETE /api/threads/:id
205
+ * Delete a thread
206
+ *
207
+ * Response:
208
+ * {
209
+ * "success": true,
210
+ * "message": "Thread deleted successfully"
211
+ * }
212
+ *
213
+ * Requirements:
214
+ * - 6.3 - THE CLI SHALL expose REST API endpoints for Thread operations
215
+ * - 8.4 - WHEN deleting a Thread, THE App SHALL send a DELETE request with the Thread identifier to the CLI
216
+ */
217
+ router.delete('/:id', async (c) => {
218
+ try {
219
+ const threadId = c.req.param('id');
220
+ if (!threadId) {
221
+ const errorResponse = {
222
+ error: {
223
+ code: 'INVALID_REQUEST',
224
+ message: 'Thread ID is required',
225
+ timestamp: new Date().toISOString()
226
+ }
227
+ };
228
+ return c.json(errorResponse, 400);
229
+ }
230
+ await threadManager.deleteThread(threadId);
231
+ return c.json({
232
+ success: true,
233
+ message: 'Thread deleted successfully'
234
+ });
235
+ }
236
+ catch (error) {
237
+ const errorMessage = error instanceof Error ? error.message : String(error);
238
+ // Check if it's a "not found" error
239
+ if (errorMessage.includes('not found')) {
240
+ const errorResponse = {
241
+ error: {
242
+ code: 'THREAD_NOT_FOUND',
243
+ message: errorMessage,
244
+ timestamp: new Date().toISOString()
245
+ }
246
+ };
247
+ return c.json(errorResponse, 404);
248
+ }
249
+ const errorResponse = {
250
+ error: {
251
+ code: 'DELETE_THREAD_ERROR',
252
+ message: 'Failed to delete thread',
253
+ details: errorMessage,
254
+ timestamp: new Date().toISOString()
255
+ }
256
+ };
257
+ return c.json(errorResponse, 500);
258
+ }
259
+ });
260
+ /**
261
+ * POST /api/threads/:id/select
262
+ * Select a thread as the active thread
263
+ *
264
+ * Response:
265
+ * {
266
+ * "success": true,
267
+ * "message": "Thread selected successfully",
268
+ * "threadId": "uuid"
269
+ * }
270
+ *
271
+ * Requirements:
272
+ * - 6.3 - THE CLI SHALL expose REST API endpoints for Thread operations
273
+ */
274
+ router.post('/:id/select', async (c) => {
275
+ try {
276
+ const threadId = c.req.param('id');
277
+ if (!threadId) {
278
+ const errorResponse = {
279
+ error: {
280
+ code: 'INVALID_REQUEST',
281
+ message: 'Thread ID is required',
282
+ timestamp: new Date().toISOString()
283
+ }
284
+ };
285
+ return c.json(errorResponse, 400);
286
+ }
287
+ // Verify thread exists
288
+ const thread = await threadManager.getThread(threadId);
289
+ if (!thread) {
290
+ const errorResponse = {
291
+ error: {
292
+ code: 'THREAD_NOT_FOUND',
293
+ message: `Thread not found: ${threadId}`,
294
+ timestamp: new Date().toISOString()
295
+ }
296
+ };
297
+ return c.json(errorResponse, 404);
298
+ }
299
+ await threadManager.selectThread(threadId);
300
+ return c.json({
301
+ success: true,
302
+ message: 'Thread selected successfully',
303
+ threadId
304
+ });
305
+ }
306
+ catch (error) {
307
+ const errorResponse = {
308
+ error: {
309
+ code: 'SELECT_THREAD_ERROR',
310
+ message: 'Failed to select thread',
311
+ details: error instanceof Error ? error.message : String(error),
312
+ timestamp: new Date().toISOString()
313
+ }
314
+ };
315
+ return c.json(errorResponse, 500);
316
+ }
317
+ });
318
+ /**
319
+ * GET /api/threads/:id/messages
320
+ * Get chat history for a thread
321
+ */
322
+ router.get('/:id/messages', async (c) => {
323
+ try {
324
+ const threadId = c.req.param('id');
325
+ if (!threadId) {
326
+ const errorResponse = {
327
+ error: {
328
+ code: 'INVALID_REQUEST',
329
+ message: 'Thread ID is required',
330
+ timestamp: new Date().toISOString()
331
+ }
332
+ };
333
+ return c.json(errorResponse, 400);
334
+ }
335
+ const thread = await threadManager.getThread(threadId);
336
+ if (!thread) {
337
+ const errorResponse = {
338
+ error: {
339
+ code: 'THREAD_NOT_FOUND',
340
+ message: `Thread not found: ${threadId}`,
341
+ timestamp: new Date().toISOString()
342
+ }
343
+ };
344
+ return c.json(errorResponse, 404);
345
+ }
346
+ const history = await conversationManager.getConversationHistory(thread.path);
347
+ if (!history || history.messages.length === 0) {
348
+ return c.json([]);
349
+ }
350
+ const messages = history.messages.flatMap((message) => {
351
+ const userMessage = {
352
+ messageId: `user-${message.id}`,
353
+ sender: 'user',
354
+ content: message.request.message,
355
+ contentType: 'text',
356
+ timestamp: message.timestamp,
357
+ model: message.request.model,
358
+ attachments: message.request.attachments?.map((attachment) => ({
359
+ fileName: attachment.name,
360
+ content: attachment.content,
361
+ size: attachment.size,
362
+ }))
363
+ };
364
+ if (!message.response) {
365
+ return [userMessage];
366
+ }
367
+ const agentMessage = {
368
+ messageId: `agent-${message.id}`,
369
+ sender: 'agent',
370
+ content: extractAssistantContent(message.response.events, message.response.content),
371
+ contentType: 'markdown',
372
+ timestamp: message.response.completedAt,
373
+ model: message.request.model,
374
+ };
375
+ return [userMessage, agentMessage];
376
+ });
377
+ return c.json(messages);
378
+ }
379
+ catch (error) {
380
+ const errorResponse = {
381
+ error: {
382
+ code: 'GET_THREAD_MESSAGES_ERROR',
383
+ message: 'Failed to load thread messages',
384
+ details: error instanceof Error ? error.message : String(error),
385
+ timestamp: new Date().toISOString()
386
+ }
387
+ };
388
+ return c.json(errorResponse, 500);
389
+ }
390
+ });
391
+ return router;
392
+ }
393
+ //# sourceMappingURL=threads-old.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.d.ts.map