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,309 @@
1
+ /**
2
+ * MetadataManager handles persistence of project and thread metadata
3
+ *
4
+ * This manager provides JSON file-based storage with atomic writes
5
+ * to ensure data consistency even if the process crashes during write operations.
6
+ */
7
+ import { promises as fs } from 'fs';
8
+ import { join, dirname } from 'path';
9
+ export class MetadataManager {
10
+ projectsFile;
11
+ threadsFile;
12
+ stateFile;
13
+ metadataDir;
14
+ /**
15
+ * Create a new MetadataManager
16
+ * @param rootFolder - Base directory where metadata will be stored
17
+ */
18
+ constructor(rootFolder) {
19
+ this.metadataDir = join(rootFolder, '.metadata');
20
+ this.projectsFile = join(this.metadataDir, 'projects.json');
21
+ this.threadsFile = join(this.metadataDir, 'threads.json');
22
+ this.stateFile = join(this.metadataDir, 'state.json');
23
+ }
24
+ /**
25
+ * Initialize metadata directory if it doesn't exist
26
+ */
27
+ async initialize() {
28
+ try {
29
+ await fs.mkdir(this.metadataDir, { recursive: true });
30
+ // Create empty files if they don't exist
31
+ try {
32
+ await fs.access(this.projectsFile);
33
+ }
34
+ catch {
35
+ await this.saveProjects([]);
36
+ }
37
+ try {
38
+ await fs.access(this.threadsFile);
39
+ }
40
+ catch {
41
+ await this.saveThreads([]);
42
+ }
43
+ try {
44
+ await fs.access(this.stateFile);
45
+ }
46
+ catch {
47
+ await this.saveState({ selectedThreadId: null, providerKeys: {}, enabledModels: {} });
48
+ }
49
+ }
50
+ catch (error) {
51
+ throw new Error(`Failed to initialize metadata directory: ${error}`);
52
+ }
53
+ }
54
+ /**
55
+ * Save projects to disk using atomic write
56
+ * @param projects - Array of projects to save
57
+ */
58
+ async saveProjects(projects) {
59
+ await this.atomicWrite(this.projectsFile, projects);
60
+ }
61
+ /**
62
+ * Load projects from disk
63
+ * @returns Array of projects
64
+ */
65
+ async loadProjects() {
66
+ try {
67
+ const data = await fs.readFile(this.projectsFile, 'utf-8');
68
+ const projects = JSON.parse(data);
69
+ // Convert date strings back to Date objects
70
+ return projects.map((project) => ({
71
+ ...project,
72
+ createdAt: new Date(project.createdAt)
73
+ }));
74
+ }
75
+ catch (error) {
76
+ if (error.code === 'ENOENT') {
77
+ // File doesn't exist yet, return empty array
78
+ return [];
79
+ }
80
+ throw new Error(`Failed to load projects: ${error}`);
81
+ }
82
+ }
83
+ /**
84
+ * Save threads to disk using atomic write
85
+ * @param threads - Array of threads to save
86
+ */
87
+ async saveThreads(threads) {
88
+ console.log('[MetadataManager] Saving threads:', threads.map(t => ({
89
+ id: t.id,
90
+ title: t.title,
91
+ })));
92
+ await this.atomicWrite(this.threadsFile, threads);
93
+ }
94
+ /**
95
+ * Load threads from disk
96
+ * @returns Array of threads
97
+ */
98
+ async loadThreads() {
99
+ try {
100
+ const data = await fs.readFile(this.threadsFile, 'utf-8');
101
+ const threads = JSON.parse(data);
102
+ // Convert date strings back to Date objects
103
+ const result = threads.map((thread) => ({
104
+ ...thread,
105
+ createdAt: new Date(thread.createdAt)
106
+ }));
107
+ console.log('[MetadataManager] Loaded threads:', result.map((t) => ({
108
+ id: t.id,
109
+ title: t.title,
110
+ })));
111
+ return result;
112
+ }
113
+ catch (error) {
114
+ if (error.code === 'ENOENT') {
115
+ // File doesn't exist yet, return empty array
116
+ return [];
117
+ }
118
+ throw new Error(`Failed to load threads: ${error}`);
119
+ }
120
+ }
121
+ /**
122
+ * Perform atomic write using temp file
123
+ *
124
+ * This ensures that if the process crashes during write,
125
+ * we don't end up with corrupted or partial data.
126
+ *
127
+ * @param filePath - Target file path
128
+ * @param data - Data to write
129
+ */
130
+ async atomicWrite(filePath, data) {
131
+ const tempFile = `${filePath}.tmp`;
132
+ try {
133
+ // Ensure directory exists
134
+ await fs.mkdir(dirname(filePath), { recursive: true });
135
+ // Write to temp file
136
+ const jsonData = JSON.stringify(data, null, 2);
137
+ await fs.writeFile(tempFile, jsonData, 'utf-8');
138
+ // Atomic rename (overwrites target file)
139
+ await fs.rename(tempFile, filePath);
140
+ }
141
+ catch (error) {
142
+ // Clean up temp file if it exists
143
+ try {
144
+ await fs.unlink(tempFile);
145
+ }
146
+ catch {
147
+ // Ignore cleanup errors
148
+ }
149
+ throw new Error(`Failed to write ${filePath}: ${error}`);
150
+ }
151
+ }
152
+ /**
153
+ * Get the metadata directory path
154
+ */
155
+ getMetadataDir() {
156
+ return this.metadataDir;
157
+ }
158
+ /**
159
+ * Get the projects file path
160
+ */
161
+ getProjectsFile() {
162
+ return this.projectsFile;
163
+ }
164
+ /**
165
+ * Get the threads file path
166
+ */
167
+ getThreadsFile() {
168
+ return this.threadsFile;
169
+ }
170
+ /**
171
+ * Save application state to disk
172
+ * @param state - Application state to save
173
+ */
174
+ async saveState(state) {
175
+ await this.atomicWrite(this.stateFile, state);
176
+ }
177
+ /**
178
+ * Load application state from disk
179
+ * @returns Application state
180
+ */
181
+ async loadState() {
182
+ try {
183
+ const data = await fs.readFile(this.stateFile, 'utf-8');
184
+ const state = JSON.parse(data);
185
+ // Ensure providerKeys exists
186
+ if (!state.providerKeys) {
187
+ state.providerKeys = {};
188
+ }
189
+ // Ensure enabledModels exists
190
+ if (!state.enabledModels) {
191
+ state.enabledModels = {};
192
+ }
193
+ return state;
194
+ }
195
+ catch (error) {
196
+ if (error.code === 'ENOENT') {
197
+ return { selectedThreadId: null, providerKeys: {}, enabledModels: {} };
198
+ }
199
+ throw new Error(`Failed to load state: ${error}`);
200
+ }
201
+ }
202
+ /**
203
+ * Update all provider keys at once
204
+ * @param keys - Object mapping provider names to API keys
205
+ */
206
+ async saveAllProviderKeys(keys) {
207
+ const state = await this.loadState();
208
+ state.providerKeys = { ...state.providerKeys, ...keys };
209
+ await this.saveState(state);
210
+ }
211
+ /**
212
+ * Update provider keys
213
+ * @param providerName - Name of the provider
214
+ * @param apiKey - API key to save
215
+ */
216
+ async saveProviderKey(providerName, apiKey) {
217
+ const state = await this.loadState();
218
+ state.providerKeys[providerName] = apiKey;
219
+ await this.saveState(state);
220
+ }
221
+ /**
222
+ * Get all provider keys
223
+ * @returns Record of provider names to API keys
224
+ */
225
+ async getProviderKeys() {
226
+ const state = await this.loadState();
227
+ return state.providerKeys;
228
+ }
229
+ /**
230
+ * Set the selected thread ID
231
+ * @param threadId - Thread ID to select (or null to deselect)
232
+ */
233
+ async setSelectedThread(threadId) {
234
+ const state = await this.loadState();
235
+ state.selectedThreadId = threadId;
236
+ await this.saveState(state);
237
+ }
238
+ /**
239
+ * Get the selected thread ID
240
+ * @returns The selected thread ID or null
241
+ */
242
+ async getSelectedThread() {
243
+ const state = await this.loadState();
244
+ return state.selectedThreadId;
245
+ }
246
+ /**
247
+ * Enable a model for a provider
248
+ * @param provider - Provider name
249
+ * @param modelId - Model ID to enable
250
+ */
251
+ async enableModel(provider, modelId) {
252
+ const state = await this.loadState();
253
+ if (!state.enabledModels[provider]) {
254
+ state.enabledModels[provider] = [];
255
+ }
256
+ if (!state.enabledModels[provider].includes(modelId)) {
257
+ state.enabledModels[provider].push(modelId);
258
+ }
259
+ await this.saveState(state);
260
+ }
261
+ /**
262
+ * Disable a model for a provider
263
+ * @param provider - Provider name
264
+ * @param modelId - Model ID to disable
265
+ */
266
+ async disableModel(provider, modelId) {
267
+ const state = await this.loadState();
268
+ if (state.enabledModels[provider]) {
269
+ state.enabledModels[provider] = state.enabledModels[provider].filter((id) => id !== modelId);
270
+ if (state.enabledModels[provider].length === 0) {
271
+ delete state.enabledModels[provider];
272
+ }
273
+ }
274
+ await this.saveState(state);
275
+ }
276
+ /**
277
+ * Get enabled models for a provider
278
+ * @param provider - Provider name
279
+ * @returns Array of enabled model IDs
280
+ */
281
+ async getEnabledModels(provider) {
282
+ const state = await this.loadState();
283
+ return state.enabledModels[provider] || [];
284
+ }
285
+ /**
286
+ * Get all enabled models across all providers
287
+ * @returns Object mapping provider to array of model IDs
288
+ */
289
+ async getAllEnabledModels() {
290
+ const state = await this.loadState();
291
+ return state.enabledModels;
292
+ }
293
+ /**
294
+ * Set enabled models for a provider
295
+ * @param provider - Provider name
296
+ * @param modelIds - Array of model IDs to enable
297
+ */
298
+ async setEnabledModels(provider, modelIds) {
299
+ const state = await this.loadState();
300
+ if (modelIds.length === 0) {
301
+ delete state.enabledModels[provider];
302
+ }
303
+ else {
304
+ state.enabledModels[provider] = modelIds;
305
+ }
306
+ await this.saveState(state);
307
+ }
308
+ }
309
+ //# sourceMappingURL=MetadataManager.js.map
@@ -0,0 +1,57 @@
1
+ /**
2
+ * ModelManager
3
+ *
4
+ * Manages available and enabled models across different providers
5
+ */
6
+ import { Model } from '../types/models.js';
7
+ import { MetadataManager } from './MetadataManager.js';
8
+ /**
9
+ * ModelManager handles model availability and selection
10
+ */
11
+ export declare class ModelManager {
12
+ private metadataManager;
13
+ /**
14
+ * Create a new ModelManager
15
+ * @param metadataManager - MetadataManager instance for persistence
16
+ */
17
+ constructor(metadataManager: MetadataManager);
18
+ /**
19
+ * Get available models for a provider
20
+ * @param provider - Provider name (e.g., "openrouter", "openai")
21
+ * @returns Array of Model objects
22
+ * @throws Error if provider is not supported
23
+ */
24
+ getAvailableModels(provider: string): Promise<Model[]>;
25
+ /**
26
+ * Get enabled models for a provider
27
+ * @param provider - Provider name
28
+ * @returns Array of Model objects that are enabled
29
+ */
30
+ getEnabledModels(provider: string): Promise<Model[]>;
31
+ /**
32
+ * Get a specific model by ID from a provider
33
+ * @param provider - Provider name
34
+ * @param modelId - Model ID
35
+ * @returns Model object or null if not found
36
+ */
37
+ getModel(provider: string, modelId: string): Promise<Model | null>;
38
+ /**
39
+ * Enable a model for a provider
40
+ * @param provider - Provider name
41
+ * @param modelId - Model ID to enable
42
+ * @throws Error if model is not found
43
+ */
44
+ enableModel(provider: string, modelId: string): Promise<void>;
45
+ /**
46
+ * Disable a model for a provider
47
+ * @param provider - Provider name
48
+ * @param modelId - Model ID to disable
49
+ */
50
+ disableModel(provider: string, modelId: string): Promise<void>;
51
+ /**
52
+ * Get all enabled models across all providers
53
+ * @returns Object mapping provider to array of enabled Models
54
+ */
55
+ getAllEnabledModels(): Promise<Record<string, Model[]>>;
56
+ }
57
+ //# sourceMappingURL=ModelManager.d.ts.map
@@ -0,0 +1,129 @@
1
+ /**
2
+ * ModelManager
3
+ *
4
+ * Manages available and enabled models across different providers
5
+ */
6
+ import { PROVIDER_DATA } from '../provider-data.js';
7
+ /**
8
+ * Convert provider model names to Model interface
9
+ * @param provider - Provider ID
10
+ * @param modelNames - Array of model name strings
11
+ * @returns Array of Model objects
12
+ */
13
+ function convertProvidersToModels(provider, modelNames) {
14
+ return modelNames.map((modelId) => ({
15
+ id: modelId,
16
+ name: modelId, // Use model ID as name since provider-data doesn't have human-readable names
17
+ description: `${provider} model: ${modelId}`,
18
+ provider: provider,
19
+ pricing: {
20
+ prompt: 0,
21
+ completion: 0,
22
+ },
23
+ }));
24
+ }
25
+ /**
26
+ * ModelManager handles model availability and selection
27
+ */
28
+ export class ModelManager {
29
+ metadataManager;
30
+ /**
31
+ * Create a new ModelManager
32
+ * @param metadataManager - MetadataManager instance for persistence
33
+ */
34
+ constructor(metadataManager) {
35
+ this.metadataManager = metadataManager;
36
+ }
37
+ /**
38
+ * Get available models for a provider
39
+ * @param provider - Provider name (e.g., "openrouter", "openai")
40
+ * @returns Array of Model objects
41
+ * @throws Error if provider is not supported
42
+ */
43
+ async getAvailableModels(provider) {
44
+ const providerData = PROVIDER_DATA.find(p => p.id === provider.toLowerCase());
45
+ if (!providerData) {
46
+ throw new Error(`Provider "${provider}" is not supported`);
47
+ }
48
+ return convertProvidersToModels(provider, providerData.models);
49
+ }
50
+ /**
51
+ * Get enabled models for a provider
52
+ * @param provider - Provider name
53
+ * @returns Array of Model objects that are enabled
54
+ */
55
+ async getEnabledModels(provider) {
56
+ const enabledModelIds = await this.metadataManager.getEnabledModels(provider);
57
+ if (enabledModelIds.length === 0) {
58
+ return [];
59
+ }
60
+ try {
61
+ const availableModels = await this.getAvailableModels(provider);
62
+ return availableModels.filter((model) => enabledModelIds.includes(model.id));
63
+ }
64
+ catch (error) {
65
+ // If we can't fetch available models, return empty
66
+ console.error(`Failed to get enabled models for ${provider}:`, error);
67
+ return [];
68
+ }
69
+ }
70
+ /**
71
+ * Get a specific model by ID from a provider
72
+ * @param provider - Provider name
73
+ * @param modelId - Model ID
74
+ * @returns Model object or null if not found
75
+ */
76
+ async getModel(provider, modelId) {
77
+ try {
78
+ const availableModels = await this.getAvailableModels(provider);
79
+ return availableModels.find((m) => m.id === modelId) || null;
80
+ }
81
+ catch (error) {
82
+ console.error(`Failed to get model ${modelId} from ${provider}:`, error);
83
+ return null;
84
+ }
85
+ }
86
+ /**
87
+ * Enable a model for a provider
88
+ * @param provider - Provider name
89
+ * @param modelId - Model ID to enable
90
+ * @throws Error if model is not found
91
+ */
92
+ async enableModel(provider, modelId) {
93
+ // Verify the model exists
94
+ const model = await this.getModel(provider, modelId);
95
+ if (!model) {
96
+ throw new Error(`Model "${modelId}" not found in provider "${provider}"`);
97
+ }
98
+ await this.metadataManager.enableModel(provider, modelId);
99
+ }
100
+ /**
101
+ * Disable a model for a provider
102
+ * @param provider - Provider name
103
+ * @param modelId - Model ID to disable
104
+ */
105
+ async disableModel(provider, modelId) {
106
+ await this.metadataManager.disableModel(provider, modelId);
107
+ }
108
+ /**
109
+ * Get all enabled models across all providers
110
+ * @returns Object mapping provider to array of enabled Models
111
+ */
112
+ async getAllEnabledModels() {
113
+ const enabledByProvider = await this.metadataManager.getAllEnabledModels();
114
+ const result = {};
115
+ for (const provider of Object.keys(enabledByProvider)) {
116
+ try {
117
+ const models = await this.getEnabledModels(provider);
118
+ if (models.length > 0) {
119
+ result[provider] = models;
120
+ }
121
+ }
122
+ catch (error) {
123
+ console.error(`Failed to get enabled models for ${provider}:`, error);
124
+ }
125
+ }
126
+ return result;
127
+ }
128
+ }
129
+ //# sourceMappingURL=ModelManager.js.map
@@ -0,0 +1,40 @@
1
+ /**
2
+ * NeovateExecutor handles execution of neovate commands via the @neovate/code SDK
3
+ *
4
+ * This manager is responsible for:
5
+ * - Executing streaming sessions via the SDK
6
+ * - Streaming result messages back to the caller
7
+ * - Handling execution errors
8
+ */
9
+ import { NeovateEvent, ExecutionContext } from '../types/models.js';
10
+ /**
11
+ * NeovateExecutor interface defines the contract for neovate command execution
12
+ */
13
+ export interface NeovateExecutor {
14
+ /**
15
+ * Executes a neovate command with the given prompt and context
16
+ * @param prompt - The user's message/prompt to send to neovate
17
+ * @param context - ExecutionContext containing thread info and options
18
+ * @yields NeovateEvent objects for system, message, result, and error events
19
+ */
20
+ execute(prompt: string, context: ExecutionContext): AsyncGenerator<NeovateEvent>;
21
+ }
22
+ /**
23
+ * NeovateExecutorImpl provides the implementation for neovate command execution
24
+ * using the @neovate/code SDK with streaming sessions.
25
+ */
26
+ export declare class NeovateExecutorImpl implements NeovateExecutor {
27
+ /**
28
+ * Executes a neovate prompt using the SDK via streaming sessions
29
+ *
30
+ * @param userPrompt - The user's message/prompt to send to neovate
31
+ * @param context - ExecutionContext with threadId, threadPath, model, and attachments
32
+ * @yields NeovateEvent objects for message, result, and error events
33
+ *
34
+ * Requirements:
35
+ * - 5.2 - WHEN the CLI receives a chat message, THE CLI SHALL execute the Neovate command
36
+ * - 5.4 - WHEN the Neovate command executes, THE CLI SHALL stream the output back to the App
37
+ */
38
+ execute(userPrompt: string, context: ExecutionContext): AsyncGenerator<NeovateEvent>;
39
+ }
40
+ //# sourceMappingURL=NeovateExecutor.d.ts.map
@@ -0,0 +1,138 @@
1
+ /**
2
+ * NeovateExecutor handles execution of neovate commands via the @neovate/code SDK
3
+ *
4
+ * This manager is responsible for:
5
+ * - Executing streaming sessions via the SDK
6
+ * - Streaming result messages back to the caller
7
+ * - Handling execution errors
8
+ */
9
+ import { createSession } from '@neovate/code';
10
+ import { resolve } from 'path';
11
+ const getErrorCode = (error) => {
12
+ if (error && typeof error === 'object' && 'code' in error) {
13
+ const code = error.code;
14
+ if (typeof code === 'string') {
15
+ return code;
16
+ }
17
+ }
18
+ return undefined;
19
+ };
20
+ /**
21
+ * NeovateExecutorImpl provides the implementation for neovate command execution
22
+ * using the @neovate/code SDK with streaming sessions.
23
+ */
24
+ export class NeovateExecutorImpl {
25
+ /**
26
+ * Executes a neovate prompt using the SDK via streaming sessions
27
+ *
28
+ * @param userPrompt - The user's message/prompt to send to neovate
29
+ * @param context - ExecutionContext with threadId, threadPath, model, and attachments
30
+ * @yields NeovateEvent objects for message, result, and error events
31
+ *
32
+ * Requirements:
33
+ * - 5.2 - WHEN the CLI receives a chat message, THE CLI SHALL execute the Neovate command
34
+ * - 5.4 - WHEN the Neovate command executes, THE CLI SHALL stream the output back to the App
35
+ */
36
+ async *execute(userPrompt, context) {
37
+ let session = null;
38
+ try {
39
+ // Ensure model is always defined
40
+ // The model is passed from the frontend (e.g., "openrouter/minimax/minimax-m2.1")
41
+ // We'll validate and ensure it's properly formatted for the SDK
42
+ let model = context.model?.trim();
43
+ if (!model) {
44
+ console.warn('[NeovateExecutor] No model provided in context, using default');
45
+ model = 'openrouter/minimax/minimax-m2.1';
46
+ }
47
+ const cwd = resolve(context.threadPath);
48
+ console.log('[NeovateExecutor] Execution context:', { model, cwd, promptLength: userPrompt.length });
49
+ // CRITICAL FIX: Ensure model is passed correctly to createSession
50
+ // The model MUST be a non-empty string, not null or undefined
51
+ const sessionConfig = {
52
+ model, // This is the critical parameter
53
+ cwd,
54
+ productName: 'Tarsk.io'
55
+ };
56
+ console.log('[NeovateExecutor] Creating session with model:', model);
57
+ console.log('[NeovateExecutor] Session config has model:', !!sessionConfig.model);
58
+ // Create a streaming session - MUST have model defined
59
+ session = await createSession(sessionConfig);
60
+ if (!session) {
61
+ throw new Error('Failed to create session: createSession returned falsy value');
62
+ }
63
+ console.log('[NeovateExecutor] Session created:', session.sessionId);
64
+ // Send the user prompt to the session
65
+ console.log('[NeovateExecutor] Sending prompt to session...');
66
+ await session.send(userPrompt);
67
+ console.log('[NeovateExecutor] Prompt sent, waiting for responses...');
68
+ // Stream messages from the session
69
+ for await (const msg of session.receive()) {
70
+ const contentLength = typeof msg?.content === 'string' ? msg.content.length : undefined;
71
+ console.log('[NeovateExecutor] Received msg:', { type: msg?.type, contentLength });
72
+ if (msg?.type === 'message') {
73
+ // Yield conversation messages (assistant responses)
74
+ yield {
75
+ type: 'message',
76
+ role: msg.role || 'assistant',
77
+ content: typeof msg.content === 'string' ? msg.content : JSON.stringify(msg.content),
78
+ };
79
+ }
80
+ else if (msg?.type === 'result') {
81
+ // Yield the final result
82
+ yield {
83
+ type: 'result',
84
+ content: typeof msg.content === 'string' ? msg.content : JSON.stringify(msg.content),
85
+ };
86
+ break; // Exit the loop after receiving the result
87
+ }
88
+ }
89
+ }
90
+ catch (error) {
91
+ console.error('[NeovateExecutor] Error during execution:', error);
92
+ let errCode;
93
+ let errMessage;
94
+ let errStack;
95
+ let errDetails;
96
+ if (error instanceof Error) {
97
+ errMessage = error.message || 'Unknown error';
98
+ errStack = error.stack;
99
+ errCode = getErrorCode(error);
100
+ }
101
+ else if (typeof error === 'object' && error !== null) {
102
+ errMessage = error.message
103
+ ? String(error.message)
104
+ : JSON.stringify(error);
105
+ errCode = getErrorCode(error);
106
+ errDetails = error;
107
+ }
108
+ else if (typeof error === 'string') {
109
+ errMessage = error;
110
+ }
111
+ else {
112
+ errMessage = String(error);
113
+ }
114
+ console.error('[NeovateExecutor] Error details:', { errCode, errMessage, errStack });
115
+ yield {
116
+ type: 'error',
117
+ error: {
118
+ code: errCode || 'EXECUTION_ERROR',
119
+ message: errMessage || 'An error occurred during execution',
120
+ details: { stack: errStack, originalError: errDetails }
121
+ },
122
+ };
123
+ }
124
+ finally {
125
+ // Ensure the session is properly closed
126
+ if (session) {
127
+ try {
128
+ await session.close?.();
129
+ console.log('[NeovateExecutor] Session closed');
130
+ }
131
+ catch (closeError) {
132
+ console.error('[NeovateExecutor] Error closing session:', closeError);
133
+ }
134
+ }
135
+ }
136
+ }
137
+ }
138
+ //# sourceMappingURL=NeovateExecutor.js.map