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,352 @@
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
+ import { ResponseBuilder } from '../lib/response-builder.js';
13
+ const extractTextBlocksFromContent = (content) => {
14
+ const trimmed = content.trim();
15
+ if (!trimmed.startsWith('[') && !trimmed.startsWith('{')) {
16
+ return [];
17
+ }
18
+ try {
19
+ const parsed = JSON.parse(trimmed);
20
+ if (Array.isArray(parsed)) {
21
+ return parsed
22
+ .filter((block) => block && typeof block === 'object' && block.type === 'text')
23
+ .map((block) => (typeof block.text === 'string' ? block.text : ''))
24
+ .filter((text) => text.length > 0);
25
+ }
26
+ if (parsed && typeof parsed === 'object' && typeof parsed.text === 'string') {
27
+ return [parsed.text];
28
+ }
29
+ }
30
+ catch {
31
+ return [];
32
+ }
33
+ return [];
34
+ };
35
+ const extractAssistantContent = (events, fallback) => {
36
+ if (!events || events.length === 0) {
37
+ return fallback;
38
+ }
39
+ const resultEvent = [...events].reverse().find((event) => event.type === 'result');
40
+ if (resultEvent && typeof resultEvent.content === 'string' && resultEvent.content.trim().length > 0) {
41
+ return resultEvent.content;
42
+ }
43
+ const assistantMessages = events.filter((event) => event.type === 'message' && event.role === 'assistant');
44
+ let lastTextBlock = null;
45
+ const assistantChunks = [];
46
+ for (const event of assistantMessages) {
47
+ if (typeof event.content !== 'string') {
48
+ continue;
49
+ }
50
+ assistantChunks.push(event.content);
51
+ const textBlocks = extractTextBlocksFromContent(event.content);
52
+ if (textBlocks.length > 0) {
53
+ lastTextBlock = textBlocks[textBlocks.length - 1];
54
+ }
55
+ }
56
+ if (lastTextBlock) {
57
+ return lastTextBlock;
58
+ }
59
+ if (assistantChunks.length === 0) {
60
+ return fallback;
61
+ }
62
+ const combined = assistantChunks.join('');
63
+ return combined.trim().length > 0 ? combined : fallback;
64
+ };
65
+ export function createThreadRoutes(threadManager, gitManager, conversationManager) {
66
+ const router = new Hono();
67
+ /**
68
+ * POST /api/threads
69
+ * Create a new thread for a project
70
+ *
71
+ * Request body:
72
+ * {
73
+ * "projectId": "uuid",
74
+ * "title": "Optional thread title"
75
+ * }
76
+ *
77
+ * Response: Newline-delimited JSON stream of ThreadEvent objects
78
+ *
79
+ * Requirements:
80
+ * - 6.3 - THE CLI SHALL expose REST API endpoints for Thread operations
81
+ * - 8.3 - WHEN creating a Thread, THE App SHALL send a POST request with the Project identifier to the CLI
82
+ * - 8.4 - THE CLI SHALL support streaming responses to the client
83
+ */
84
+ router.post('/', async (c) => {
85
+ try {
86
+ const body = await c.req.json();
87
+ const { projectId, title } = body;
88
+ // Validate projectId is provided
89
+ if (!projectId || typeof projectId !== 'string') {
90
+ const { response, statusCode } = ResponseBuilder.error('INVALID_REQUEST', 'projectId is required and must be a string', 400);
91
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
92
+ return c.json(response, statusCode);
93
+ }
94
+ // Validate title if provided
95
+ if (title !== undefined && typeof title !== 'string') {
96
+ const { response, statusCode } = ResponseBuilder.error('INVALID_REQUEST', 'title must be a string if provided', 400);
97
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
98
+ return c.json(response, statusCode);
99
+ }
100
+ // Validate thread name (empty/whitespace is allowed, will auto-generate)
101
+ if (title && title.trim() !== '') {
102
+ const nameError = validateThreadName(title);
103
+ if (nameError) {
104
+ const { response, statusCode } = ResponseBuilder.error('INVALID_REQUEST', nameError, 400);
105
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
106
+ return c.json(response, statusCode);
107
+ }
108
+ // Check for duplicate branch names
109
+ const existingThreads = await threadManager.listThreads(projectId);
110
+ const sanitizedNewName = gitManager.sanitizeBranchName(title);
111
+ const existingSanitized = existingThreads.map(t => gitManager.sanitizeBranchName(t.title));
112
+ if (existingSanitized.includes(sanitizedNewName)) {
113
+ const { response, statusCode } = ResponseBuilder.error('DUPLICATE_BRANCH', `A thread with branch name "${sanitizedNewName}" already exists`, 409);
114
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
115
+ return c.json(response, statusCode);
116
+ }
117
+ }
118
+ // Stream the thread creation events
119
+ return streamAsyncGenerator(c, threadManager.createThread(projectId, title));
120
+ }
121
+ catch (error) {
122
+ const { response, statusCode } = ResponseBuilder.error('REQUEST_PARSE_ERROR', 'Failed to parse request body', 400, error instanceof Error ? error.message : String(error));
123
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
124
+ return c.json(response, statusCode);
125
+ }
126
+ });
127
+ /**
128
+ * GET /api/threads?projectId=xxx
129
+ * List all threads for a specific project
130
+ *
131
+ * Query parameters:
132
+ * - projectId (required): The project ID to filter threads
133
+ *
134
+ * Response:
135
+ * [
136
+ * {
137
+ * "id": "uuid",
138
+ * "projectId": "uuid",
139
+ * "title": "Thread title",
140
+ * "path": "/path/to/thread",
141
+ * "currentBranch": "branch-name",
142
+ * "createdAt": "2024-01-01T00:00:00Z"
143
+ * }
144
+ * ]
145
+ *
146
+ * Requirements:
147
+ * - 6.3 - THE CLI SHALL expose REST API endpoints for Thread operations
148
+ */
149
+ router.get('/', async (c) => {
150
+ try {
151
+ const projectId = c.req.query('projectId');
152
+ // Validate projectId is provided
153
+ if (!projectId) {
154
+ const { response, statusCode } = ResponseBuilder.error('INVALID_REQUEST', 'projectId query parameter is required', 400);
155
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
156
+ return c.json(response, statusCode);
157
+ }
158
+ const threads = await threadManager.listThreads(projectId);
159
+ return c.json(threads);
160
+ }
161
+ catch (error) {
162
+ const { response, statusCode } = ResponseBuilder.error('LIST_THREADS_ERROR', 'Failed to list threads', 500, error instanceof Error ? error.message : String(error));
163
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
164
+ return c.json(response, statusCode);
165
+ }
166
+ });
167
+ /**
168
+ * DELETE /api/threads/:id
169
+ * Delete a thread
170
+ *
171
+ * Response:
172
+ * {
173
+ * "success": true,
174
+ * "message": "Thread deleted successfully"
175
+ * }
176
+ *
177
+ * Requirements:
178
+ * - 6.3 - THE CLI SHALL expose REST API endpoints for Thread operations
179
+ * - 8.4 - WHEN deleting a Thread, THE App SHALL send a DELETE request with the Thread identifier to the CLI
180
+ */
181
+ router.delete('/:id', async (c) => {
182
+ try {
183
+ const threadId = c.req.param('id');
184
+ if (!threadId) {
185
+ const { response, statusCode } = ResponseBuilder.error('INVALID_REQUEST', 'Thread ID is required', 400);
186
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
187
+ return c.json(response, statusCode);
188
+ }
189
+ await threadManager.deleteThread(threadId);
190
+ const { response, statusCode } = ResponseBuilder.success({ success: true, message: 'Thread deleted successfully' });
191
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
192
+ return c.json(response, statusCode);
193
+ }
194
+ catch (error) {
195
+ const errorMessage = error instanceof Error ? error.message : String(error);
196
+ // Check if it's a "not found" error
197
+ if (errorMessage.includes('not found')) {
198
+ const { response, statusCode } = ResponseBuilder.error('THREAD_NOT_FOUND', errorMessage, 404);
199
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
200
+ return c.json(response, statusCode);
201
+ }
202
+ const { response, statusCode } = ResponseBuilder.error('DELETE_THREAD_ERROR', 'Failed to delete thread', 500, errorMessage);
203
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
204
+ return c.json(response, statusCode);
205
+ }
206
+ });
207
+ /**
208
+ * POST /api/threads/:id/select
209
+ * Select a thread as the active thread
210
+ *
211
+ * Response:
212
+ * {
213
+ * "success": true,
214
+ * "message": "Thread selected successfully",
215
+ * "threadId": "uuid"
216
+ * }
217
+ *
218
+ * Requirements:
219
+ * - 6.3 - THE CLI SHALL expose REST API endpoints for Thread operations
220
+ */
221
+ router.post('/:id/select', async (c) => {
222
+ try {
223
+ const threadId = c.req.param('id');
224
+ if (!threadId) {
225
+ const { response, statusCode } = ResponseBuilder.error('INVALID_REQUEST', 'Thread ID is required', 400);
226
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
227
+ return c.json(response, statusCode);
228
+ }
229
+ // Verify thread exists
230
+ const thread = await threadManager.getThread(threadId);
231
+ if (!thread) {
232
+ const { response, statusCode } = ResponseBuilder.error('THREAD_NOT_FOUND', `Thread not found: ${threadId}`, 404);
233
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
234
+ return c.json(response, statusCode);
235
+ }
236
+ await threadManager.selectThread(threadId);
237
+ const { response, statusCode } = ResponseBuilder.success({ success: true, message: 'Thread selected successfully', threadId });
238
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
239
+ return c.json(response, statusCode);
240
+ }
241
+ catch (error) {
242
+ const { response, statusCode } = ResponseBuilder.error('SELECT_THREAD_ERROR', 'Failed to select thread', 500, error instanceof Error ? error.message : String(error));
243
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
244
+ return c.json(response, statusCode);
245
+ }
246
+ });
247
+ /**
248
+ * GET /api/threads/:id/messages
249
+ * Get chat history for a thread
250
+ */
251
+ router.get('/:id/messages', async (c) => {
252
+ try {
253
+ const threadId = c.req.param('id');
254
+ if (!threadId) {
255
+ const { response, statusCode } = ResponseBuilder.error('INVALID_REQUEST', 'Thread ID is required', 400);
256
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
257
+ return c.json(response, statusCode);
258
+ }
259
+ const thread = await threadManager.getThread(threadId);
260
+ if (!thread) {
261
+ const { response, statusCode } = ResponseBuilder.error('THREAD_NOT_FOUND', `Thread not found: ${threadId}`, 404);
262
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
263
+ return c.json(response, statusCode);
264
+ }
265
+ const history = await conversationManager.getConversationHistory(thread.path);
266
+ if (!history || history.messages.length === 0) {
267
+ return c.json([]);
268
+ }
269
+ const messages = history.messages.flatMap((message) => {
270
+ const userMessage = {
271
+ messageId: `user-${message.id}`,
272
+ sender: 'user',
273
+ content: message.request.message,
274
+ contentType: 'text',
275
+ timestamp: message.timestamp,
276
+ model: message.request.model,
277
+ attachments: message.request.attachments?.map((attachment) => ({
278
+ fileName: attachment.name,
279
+ content: attachment.content,
280
+ size: attachment.size,
281
+ }))
282
+ };
283
+ if (!message.response) {
284
+ return [userMessage];
285
+ }
286
+ const agentMessage = {
287
+ messageId: `agent-${message.id}`,
288
+ sender: 'agent',
289
+ content: extractAssistantContent(message.response.events, message.response.content),
290
+ contentType: 'markdown',
291
+ timestamp: message.response.completedAt,
292
+ model: message.request.model,
293
+ };
294
+ return [userMessage, agentMessage];
295
+ });
296
+ return c.json(messages);
297
+ }
298
+ catch (error) {
299
+ const { response, statusCode } = ResponseBuilder.error('GET_THREAD_MESSAGES_ERROR', 'Failed to load thread messages', 500, error instanceof Error ? error.message : String(error));
300
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
301
+ return c.json(response, statusCode);
302
+ }
303
+ });
304
+ /**
305
+ * GET /api/threads/:id/files
306
+ * List all files in a thread's directory
307
+ */
308
+ router.get('/:id/files', async (c) => {
309
+ try {
310
+ const threadId = c.req.param('id');
311
+ if (!threadId) {
312
+ const { response, statusCode } = ResponseBuilder.error('INVALID_REQUEST', 'Thread ID is required', 400);
313
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
314
+ return c.json(response, statusCode);
315
+ }
316
+ const files = await threadManager.listFiles(threadId);
317
+ return c.json(files);
318
+ }
319
+ catch (error) {
320
+ const { response, statusCode } = ResponseBuilder.error('LIST_THREAD_FILES_ERROR', 'Failed to list thread files', 500, error instanceof Error ? error.message : String(error));
321
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
322
+ return c.json(response, statusCode);
323
+ }
324
+ });
325
+ /**
326
+ * PATCH /api/threads/:id
327
+ * Update thread metadata
328
+ */
329
+ router.patch('/:id', async (c) => {
330
+ try {
331
+ const threadId = c.req.param('id');
332
+ const body = await c.req.json();
333
+ if (!threadId) {
334
+ const { response, statusCode } = ResponseBuilder.error('INVALID_REQUEST', 'Thread ID is required', 400);
335
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
336
+ return c.json(response, statusCode);
337
+ }
338
+ await threadManager.updateThread(threadId, body);
339
+ const { response, statusCode } = ResponseBuilder.success({ success: true, message: 'Thread updated successfully' });
340
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
341
+ return c.json(response, statusCode);
342
+ }
343
+ catch (error) {
344
+ const errorMessage = error instanceof Error ? error.message : String(error);
345
+ const { response, statusCode } = ResponseBuilder.error('UPDATE_THREAD_ERROR', 'Failed to update thread', 500, errorMessage);
346
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
347
+ return c.json(response, statusCode);
348
+ }
349
+ });
350
+ return router;
351
+ }
352
+ //# sourceMappingURL=threads.js.map
@@ -0,0 +1,315 @@
1
+ /**
2
+ * Data models for the Project Threads Manager
3
+ *
4
+ * This file defines the core data structures used throughout the application
5
+ * for projects, threads, chat messages, and file attachments.
6
+ */
7
+ /**
8
+ * Available IDEs/editors for opening projects
9
+ */
10
+ export declare const AVAILABLE_PROGRAMS: string[];
11
+ /**
12
+ * Command represents a custom shell command that can be run on a project
13
+ */
14
+ export interface Command {
15
+ /** Unique identifier (UUID) */
16
+ id: string;
17
+ /** Human-readable name */
18
+ name: string;
19
+ /** Lucide icon name */
20
+ icon: string;
21
+ /** The shell command to execute */
22
+ commandLine: string;
23
+ }
24
+ /**
25
+ * Project represents a git repository with associated threads
26
+ */
27
+ export interface Project {
28
+ /** Unique identifier (UUID) */
29
+ id: string;
30
+ /** Project name derived from git URL */
31
+ name: string;
32
+ /** Original git repository URL */
33
+ gitUrl: string;
34
+ /** Absolute path to project folder */
35
+ path: string;
36
+ /** Timestamp when project was created */
37
+ createdAt: Date;
38
+ /** Array of thread IDs belonging to this project */
39
+ threads: string[];
40
+ /** Preferred IDE to open the project in (VS Code, Cursor, Windsurf, Xcode, Android Studio) */
41
+ openWith?: string;
42
+ /** Custom commands defined for this project */
43
+ commands?: Command[];
44
+ }
45
+ /**
46
+ * Thread represents a specific clone instance of a project's git repository
47
+ */
48
+ export interface Thread {
49
+ /** Unique identifier (UUID) */
50
+ id: string;
51
+ /** Parent project ID */
52
+ projectId: string;
53
+ /** User-defined or auto-generated title */
54
+ title: string;
55
+ /** Absolute path to thread folder */
56
+ path: string;
57
+ /** Current git branch for this thread */
58
+ currentBranch: string;
59
+ /** Timestamp when thread was created */
60
+ createdAt: Date;
61
+ }
62
+ /**
63
+ * ChatMessage represents a message in the agent conversation
64
+ * (Frontend only - not persisted by CLI)
65
+ */
66
+ export interface ChatMessage {
67
+ /** Unique identifier (UUID) */
68
+ id: string;
69
+ /** Associated thread ID */
70
+ threadId: string;
71
+ /** Message sender role */
72
+ role: 'user' | 'agent';
73
+ /** Message content */
74
+ content: string;
75
+ /** Timestamp when message was sent */
76
+ timestamp: Date;
77
+ /** Optional file attachments */
78
+ attachments?: FileAttachment[];
79
+ }
80
+ /**
81
+ * FileAttachment represents a file attached to a chat message
82
+ */
83
+ export interface FileAttachment {
84
+ /** File name */
85
+ name: string;
86
+ /** File path relative to thread */
87
+ path: string;
88
+ /** File size in bytes */
89
+ size: number;
90
+ /** MIME type of the file */
91
+ mimeType: string;
92
+ }
93
+ /**
94
+ * Event types for streaming operations
95
+ */
96
+ /**
97
+ * ProjectEvent is yielded during project creation operations
98
+ */
99
+ export interface ProjectEvent {
100
+ /** Event type */
101
+ type: 'progress' | 'complete' | 'error';
102
+ /** Progress or error message */
103
+ message?: string;
104
+ /** Error details (only present on 'error' type) */
105
+ error?: unknown;
106
+ /** Completed project data (only present on 'complete' type) */
107
+ project?: Project;
108
+ }
109
+ /**
110
+ * ThreadEvent is yielded during thread creation operations
111
+ */
112
+ export interface ThreadEvent {
113
+ /** Event type */
114
+ type: 'progress' | 'complete' | 'error';
115
+ /** Progress or error message */
116
+ message?: string;
117
+ /** Error details (only present on 'error' type) */
118
+ error?: unknown;
119
+ /** Completed thread data (only present on 'complete' type) */
120
+ thread?: Thread;
121
+ }
122
+ /**
123
+ * GitEvent is yielded during git clone operations
124
+ */
125
+ export interface GitEvent {
126
+ /** Event type */
127
+ type: 'stdout' | 'stderr' | 'complete' | 'error';
128
+ /** Output data from git command */
129
+ data?: string;
130
+ /** Error message (only present on 'error' type) */
131
+ message?: string;
132
+ /** Error details (only present on 'error' type) */
133
+ error?: unknown;
134
+ }
135
+ /**
136
+ * NeovateEvent is yielded during neovate SDK prompt execution
137
+ */
138
+ export interface NeovateEvent {
139
+ /** Event type */
140
+ type: 'message' | 'result' | 'error';
141
+ /** Role of the message sender (for 'message' type) */
142
+ role?: string;
143
+ /** Message or result content */
144
+ content?: string;
145
+ /** Error details (only present on 'error' type) */
146
+ error?: {
147
+ /** Machine-readable error code */
148
+ code?: string;
149
+ /** Human-readable error message */
150
+ message: string;
151
+ /** Additional error context */
152
+ details?: unknown;
153
+ };
154
+ }
155
+ /**
156
+ * ExecutionContext provides context for neovate SDK prompt execution
157
+ */
158
+ export interface ExecutionContext {
159
+ /** Thread ID for context */
160
+ threadId: string;
161
+ /** Absolute path to thread directory */
162
+ threadPath: string;
163
+ /** Optional model selection */
164
+ model?: string;
165
+ /** Optional provider selection (e.g., 'openrouter', 'anthropic') */
166
+ provider?: string;
167
+ /** Optional file attachments */
168
+ attachments?: FileData[];
169
+ /** Optional plan mode flag */
170
+ planMode?: boolean;
171
+ }
172
+ /**
173
+ * FileData represents file data for transmission over API
174
+ */
175
+ export interface FileData {
176
+ /** File name */
177
+ name: string;
178
+ /** File content (base64 encoded for binary files) */
179
+ content: string;
180
+ /** File size in bytes */
181
+ size: number;
182
+ /** MIME type */
183
+ mimeType: string;
184
+ }
185
+ /**
186
+ * API Request/Response types
187
+ */
188
+ /**
189
+ * ChatRequest is sent from frontend to CLI for chat messages
190
+ */
191
+ export interface ChatRequest {
192
+ /** Thread ID for context */
193
+ threadId: string;
194
+ /** User message content */
195
+ content: string;
196
+ /** Selected model */
197
+ model: string;
198
+ /** Selected provider (lowercased name like 'openrouter', 'anthropic', etc.) */
199
+ provider?: string;
200
+ /** Optional file attachments */
201
+ attachments?: FileData[];
202
+ /** Optional plan mode flag */
203
+ planMode?: boolean;
204
+ }
205
+ /**
206
+ * ChatResponse is streamed from CLI to frontend during chat
207
+ */
208
+ export interface ChatResponse {
209
+ /** Message ID */
210
+ messageId: string;
211
+ /** Response content (may be partial during streaming) */
212
+ content: string;
213
+ /** Whether the response is complete */
214
+ isComplete: boolean;
215
+ }
216
+ /**
217
+ * StreamEvent wraps streaming responses with type information
218
+ */
219
+ export interface StreamEvent<T> {
220
+ /** Event type */
221
+ type: 'progress' | 'complete' | 'error';
222
+ /** Event data (type depends on T) */
223
+ data?: T;
224
+ /** Progress or error message */
225
+ message?: string;
226
+ /** Progress percentage (0-100) */
227
+ progress?: number;
228
+ }
229
+ /**
230
+ * ErrorResponse is returned for failed API operations
231
+ */
232
+ export interface ErrorResponse {
233
+ error: {
234
+ /** Machine-readable error code */
235
+ code: string;
236
+ /** Human-readable error message */
237
+ message: string;
238
+ /** Additional error context */
239
+ details?: unknown;
240
+ /** ISO 8601 timestamp */
241
+ timestamp: string;
242
+ };
243
+ }
244
+ /**
245
+ * Conversation history types
246
+ */
247
+ /**
248
+ * ConversationMessage represents a single request/response exchange
249
+ */
250
+ export interface ConversationMessage {
251
+ /** Unique message identifier */
252
+ id: string;
253
+ /** Timestamp of the request */
254
+ timestamp: string;
255
+ /** User's request */
256
+ request: {
257
+ /** User message content */
258
+ message: string;
259
+ /** Model used for the request */
260
+ model: string;
261
+ /** Optional file attachments */
262
+ attachments?: FileData[];
263
+ /** Optional plan mode flag */
264
+ planMode?: boolean;
265
+ };
266
+ /** Agent's response (null if incomplete) */
267
+ response: {
268
+ /** Complete response content */
269
+ content: string;
270
+ /** All events captured during execution */
271
+ events: NeovateEvent[];
272
+ /** Response completion timestamp */
273
+ completedAt: string;
274
+ } | null;
275
+ }
276
+ /**
277
+ * ConversationHistory stores all conversation messages for a thread
278
+ */
279
+ export interface ConversationHistory {
280
+ /** Thread ID */
281
+ threadId: string;
282
+ /** Array of conversation messages */
283
+ messages: ConversationMessage[];
284
+ /** Last updated timestamp */
285
+ lastUpdated: string;
286
+ }
287
+ /**
288
+ * Model represents an AI model available from a provider
289
+ */
290
+ export interface Model {
291
+ /** Unique model identifier (e.g., "gpt-4", "openrouter/gpt-4") */
292
+ id: string;
293
+ /** Human-readable model name */
294
+ name: string;
295
+ /** Detailed description of the model */
296
+ description: string;
297
+ /** Provider that offers this model */
298
+ provider: string;
299
+ /**
300
+ * Pricing information for the model (optional).
301
+ * If omitted, pricing is unknown for this provider/model.
302
+ */
303
+ pricing?: {
304
+ /** Cost per token in USD */
305
+ prompt: number;
306
+ /** Cost per token in USD */
307
+ completion: number;
308
+ };
309
+ /** Supported parameters for this model (optional) */
310
+ supportedParameters?: {
311
+ /** Whether this model supports function/tool calling */
312
+ tools?: boolean;
313
+ };
314
+ }
315
+ //# sourceMappingURL=models.d.ts.map
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Data models for the Project Threads Manager
3
+ *
4
+ * This file defines the core data structures used throughout the application
5
+ * for projects, threads, chat messages, and file attachments.
6
+ */
7
+ /**
8
+ * Available IDEs/editors for opening projects
9
+ */
10
+ export const AVAILABLE_PROGRAMS = ['VS Code', 'Cursor', 'Windsurf', 'Xcode', 'Android Studio', 'Kiro'];
11
+ //# sourceMappingURL=models.js.map
@@ -0,0 +1,3 @@
1
+ export declare function updateEnvFile(keyNames: Record<string, string>): Promise<void>;
2
+ export declare function readEnvFile(): Promise<Record<string, string>>;
3
+ //# sourceMappingURL=env-manager.d.ts.map