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,465 @@
1
+ /**
2
+ * ProjectManager handles project lifecycle and metadata management
3
+ *
4
+ * This manager is responsible for:
5
+ * - Creating new projects from git URLs
6
+ * - Managing project metadata
7
+ * - Coordinating with GitManager for repository cloning
8
+ * - Providing CRUD operations for projects
9
+ */
10
+ import { randomUUID } from 'crypto';
11
+ import { join, relative } from 'path';
12
+ import { realpathSync } from 'fs';
13
+ /**
14
+ * ProjectManagerImpl provides the implementation for project operations
15
+ */
16
+ export class ProjectManagerImpl {
17
+ rootFolder;
18
+ metadataManager;
19
+ gitManager;
20
+ /**
21
+ * Create a new ProjectManager
22
+ * @param rootFolder - Base directory where projects will be stored
23
+ * @param metadataManager - Manager for persisting metadata
24
+ * @param gitManager - Manager for git operations
25
+ *
26
+ * Requirements:
27
+ * - 1.1 - WHEN a user provides a git URL to create a new Project, THE CLI SHALL clone the repository into a folder under the Root_Folder
28
+ * - 1.4 - THE CLI SHALL determine the storage path for each Project folder
29
+ */
30
+ constructor(rootFolder, metadataManager, gitManager) {
31
+ this.rootFolder = rootFolder;
32
+ this.metadataManager = metadataManager;
33
+ this.gitManager = gitManager;
34
+ }
35
+ /**
36
+ * Creates a new project from a git URL
37
+ *
38
+ * This method:
39
+ * 1. Validates the git URL
40
+ * 2. Generates a unique project ID
41
+ * 3. Derives the project name from the git URL
42
+ * 4. Generates the project path
43
+ * 5. Delegates to GitManager for cloning
44
+ * 6. Saves project metadata
45
+ * 7. Yields progress events during the operation
46
+ * 8. Creates an initial thread automatically
47
+ *
48
+ * @param gitUrl - The git repository URL
49
+ * @yields ProjectEvent objects during the creation process
50
+ *
51
+ * Requirements:
52
+ * - 1.1 - WHEN a user provides a git URL to create a new Project, THE CLI SHALL clone the repository into a folder under the Root_Folder
53
+ * - 1.2 - WHEN a Project is created, THE App SHALL display the Project in the Side_Panel with its associated Thread
54
+ * - 1.4 - THE CLI SHALL determine the storage path for each Project folder
55
+ * - 1.5 - WHEN a Project folder is created, THE System SHALL associate it with the provided git URL
56
+ */
57
+ async *createProject(gitUrl) {
58
+ // Validate git URL
59
+ if (!this.gitManager.validateGitUrl(gitUrl)) {
60
+ yield {
61
+ type: 'error',
62
+ message: `Invalid git URL format: ${gitUrl}`
63
+ };
64
+ return;
65
+ }
66
+ try {
67
+ // Generate unique project ID
68
+ const projectId = randomUUID();
69
+ // Derive project name from git URL
70
+ const projectName = this.deriveProjectName(gitUrl);
71
+ // Generate project path
72
+ const projectPath = this.generateProjectPath(projectName);
73
+ yield {
74
+ type: 'progress',
75
+ message: `Creating project "${projectName}" from ${gitUrl}...`
76
+ };
77
+ // Generate unique thread ID for the initial thread
78
+ const initialThreadId = randomUUID();
79
+ const firstThreadPath = join(projectPath, initialThreadId);
80
+ yield {
81
+ type: 'progress',
82
+ message: `Cloning repository to ${firstThreadPath}...`
83
+ };
84
+ // Stream git clone events
85
+ for await (const gitEvent of this.gitManager.cloneRepository(gitUrl, firstThreadPath)) {
86
+ if (gitEvent.type === 'error') {
87
+ yield {
88
+ type: 'error',
89
+ message: `Git clone failed: ${gitEvent.message}`
90
+ };
91
+ return;
92
+ }
93
+ else if (gitEvent.type === 'stdout' || gitEvent.type === 'stderr') {
94
+ yield {
95
+ type: 'progress',
96
+ message: gitEvent.data
97
+ };
98
+ }
99
+ }
100
+ // Create and checkout branch for initial thread
101
+ const initialThreadTitle = 'Thread 1';
102
+ let branchName = this.gitManager.sanitizeBranchName(initialThreadTitle);
103
+ yield {
104
+ type: 'progress',
105
+ message: `Creating initial branch "${branchName}"...`
106
+ };
107
+ // Check if branch exists and find a unique name if needed
108
+ let branchExists = await this.gitManager.checkBranchExists(firstThreadPath, branchName);
109
+ let counter = 2;
110
+ const baseBranchName = branchName;
111
+ while (branchExists) {
112
+ branchName = `${baseBranchName}-${counter}`;
113
+ branchExists = await this.gitManager.checkBranchExists(firstThreadPath, branchName);
114
+ counter++;
115
+ }
116
+ if (branchName !== baseBranchName) {
117
+ yield {
118
+ type: 'progress',
119
+ message: `Branch "${baseBranchName}" exists, using "${branchName}" instead`
120
+ };
121
+ }
122
+ // Create and checkout the new branch
123
+ for await (const gitEvent of this.gitManager.createAndCheckoutBranch(firstThreadPath, branchName)) {
124
+ if (gitEvent.type === 'error') {
125
+ yield {
126
+ type: 'error',
127
+ message: `Failed to create initial branch: ${gitEvent.message}`
128
+ };
129
+ return;
130
+ }
131
+ else if (gitEvent.type === 'stdout' || gitEvent.type === 'stderr') {
132
+ yield {
133
+ type: 'progress',
134
+ message: gitEvent.data
135
+ };
136
+ }
137
+ }
138
+ yield {
139
+ type: 'progress',
140
+ message: `Branch "${branchName}" created and checked out`
141
+ };
142
+ // Create project metadata
143
+ const project = {
144
+ id: projectId,
145
+ name: projectName,
146
+ gitUrl,
147
+ path: projectPath,
148
+ createdAt: new Date(),
149
+ threads: [initialThreadId] // Add initial thread ID
150
+ };
151
+ // Create initial thread metadata
152
+ const initialThread = {
153
+ id: initialThreadId,
154
+ projectId,
155
+ title: initialThreadTitle,
156
+ path: firstThreadPath,
157
+ currentBranch: branchName,
158
+ createdAt: new Date()
159
+ };
160
+ // Save project and thread metadata
161
+ const projects = await this.metadataManager.loadProjects();
162
+ projects.push(project);
163
+ await this.metadataManager.saveProjects(projects);
164
+ const threads = await this.metadataManager.loadThreads();
165
+ threads.push(initialThread);
166
+ await this.metadataManager.saveThreads(threads);
167
+ yield {
168
+ type: 'progress',
169
+ message: `Project "${projectName}" created successfully with initial thread`
170
+ };
171
+ // Yield complete event with project data
172
+ yield {
173
+ type: 'complete',
174
+ message: 'Project creation complete',
175
+ project
176
+ };
177
+ }
178
+ catch (error) {
179
+ yield {
180
+ type: 'error',
181
+ message: `Failed to create project: ${error instanceof Error ? error.message : String(error)}`
182
+ };
183
+ }
184
+ }
185
+ /**
186
+ * Gets a project by ID
187
+ * @param projectId - The project ID
188
+ * @returns The project or null if not found
189
+ */
190
+ async getProject(projectId) {
191
+ const projects = await this.metadataManager.loadProjects();
192
+ return projects.find(p => p.id === projectId) || null;
193
+ }
194
+ /**
195
+ * Lists all projects
196
+ * @returns Array of all projects
197
+ */
198
+ async listProjects() {
199
+ return await this.metadataManager.loadProjects();
200
+ }
201
+ /**
202
+ * Deletes a project and all its threads (cascade delete)
203
+ *
204
+ * This method:
205
+ * 1. Finds the project by ID
206
+ * 2. Removes all associated threads from metadata
207
+ * 3. Removes the project directory from filesystem
208
+ * 4. Removes the project from metadata
209
+ *
210
+ * @param projectId - The project ID to delete
211
+ * @throws Error if project not found
212
+ *
213
+ * Requirements:
214
+ * - 1.1 - Cascade delete for projects (remove all threads)
215
+ */
216
+ async deleteProject(projectId) {
217
+ const projects = await this.metadataManager.loadProjects();
218
+ const projectIndex = projects.findIndex(p => p.id === projectId);
219
+ if (projectIndex === -1) {
220
+ throw new Error(`Project not found: ${projectId}`);
221
+ }
222
+ const project = projects[projectIndex];
223
+ // Load threads and remove all threads associated with this project
224
+ const threads = await this.metadataManager.loadThreads();
225
+ const remainingThreads = threads.filter(t => t.projectId !== projectId);
226
+ await this.metadataManager.saveThreads(remainingThreads);
227
+ // Remove project directory from filesystem
228
+ try {
229
+ const { rm } = await import('fs/promises');
230
+ await rm(project.path, { recursive: true, force: true });
231
+ }
232
+ catch (error) {
233
+ throw new Error(`Failed to remove project directory: ${error instanceof Error ? error.message : String(error)}`);
234
+ }
235
+ // Remove project from metadata
236
+ projects.splice(projectIndex, 1);
237
+ await this.metadataManager.saveProjects(projects);
238
+ }
239
+ /**
240
+ * Derives a project name from a git URL
241
+ *
242
+ * Examples:
243
+ * - https://github.com/user/repo.git -> repo
244
+ * - https://github.com/user/repo -> repo
245
+ * - git@github.com:user/repo.git -> repo
246
+ *
247
+ * @param gitUrl - The git URL
248
+ * @returns The derived project name
249
+ */
250
+ deriveProjectName(gitUrl) {
251
+ // Remove .git suffix if present
252
+ let name = gitUrl.replace(/\.git$/, '');
253
+ // Extract the last part of the path
254
+ const parts = name.split(/[/:]/).filter(p => p.length > 0);
255
+ name = parts[parts.length - 1] || 'project';
256
+ // Sanitize the name (remove special characters)
257
+ name = name.replace(/[^a-zA-Z0-9._-]/g, '-');
258
+ return name;
259
+ }
260
+ /**
261
+ * Generates a project path under the root folder
262
+ *
263
+ * @param projectName - The project name
264
+ * @returns The absolute path to the project folder
265
+ *
266
+ * Requirements:
267
+ * - 1.4 - THE CLI SHALL determine the storage path for each Project folder
268
+ */
269
+ generateProjectPath(projectName) {
270
+ return join(this.rootFolder, projectName);
271
+ }
272
+ /**
273
+ * Gets the root folder path
274
+ * @returns The root folder path
275
+ */
276
+ getRootFolder() {
277
+ return this.rootFolder;
278
+ }
279
+ /**
280
+ * Opens a project in the specified program
281
+ *
282
+ * @param projectId - The project ID
283
+ * @param program - The program to open the project in (VS Code, Cursor, Windsurf, Xcode, Android Studio, Kiro)
284
+ */
285
+ async openWith(projectId, program) {
286
+ const project = await this.getProject(projectId);
287
+ if (!project) {
288
+ throw new Error(`Project not found: ${projectId}`);
289
+ }
290
+ const { spawn } = await import('child_process');
291
+ const projectPath = project.path;
292
+ let command;
293
+ let args = [];
294
+ switch (program) {
295
+ case 'VS Code':
296
+ command = 'code';
297
+ args = [projectPath];
298
+ break;
299
+ case 'Cursor':
300
+ command = 'cursor';
301
+ args = [projectPath];
302
+ break;
303
+ case 'Windsurf':
304
+ command = 'windsurf';
305
+ args = [projectPath];
306
+ break;
307
+ case 'Xcode':
308
+ command = 'open';
309
+ args = [projectPath, '-a', 'Xcode'];
310
+ break;
311
+ case 'Android Studio':
312
+ command = 'open';
313
+ args = [projectPath, '-a', 'Android Studio'];
314
+ break;
315
+ case 'Kiro':
316
+ command = 'kiro';
317
+ args = [projectPath];
318
+ break;
319
+ default:
320
+ throw new Error(`Unsupported program: ${program}`);
321
+ }
322
+ return new Promise((resolve, reject) => {
323
+ const process = spawn(command, args, {
324
+ detached: true,
325
+ stdio: 'ignore'
326
+ });
327
+ process.on('error', (error) => {
328
+ reject(new Error(`Failed to open ${program}: ${error.message}`));
329
+ });
330
+ // Detach the child process so it doesn't block
331
+ process.unref();
332
+ // Resolve immediately as the IDE will open asynchronously
333
+ resolve();
334
+ });
335
+ }
336
+ /**
337
+ * Updates the project's open-with program preference
338
+ *
339
+ * @param projectId - The project ID
340
+ * @param program - The program name to set
341
+ */
342
+ async updateOpenWith(projectId, program) {
343
+ const projects = await this.metadataManager.loadProjects();
344
+ const projectIndex = projects.findIndex(p => p.id === projectId);
345
+ if (projectIndex === -1) {
346
+ throw new Error(`Project not found: ${projectId}`);
347
+ }
348
+ // Update the project's open-with program preference
349
+ projects[projectIndex].openWith = program;
350
+ // Save the updated projects back to metadata
351
+ await this.metadataManager.saveProjects(projects);
352
+ }
353
+ /**
354
+ * Saves (adds or updates) a command for a project
355
+ * @param projectId - The project ID
356
+ * @param command - The command to save
357
+ */
358
+ async saveCommand(projectId, command) {
359
+ const projects = await this.metadataManager.loadProjects();
360
+ const projectIndex = projects.findIndex(p => p.id === projectId);
361
+ if (projectIndex === -1) {
362
+ throw new Error(`Project not found: ${projectId}`);
363
+ }
364
+ const project = projects[projectIndex];
365
+ if (!project.commands) {
366
+ project.commands = [];
367
+ }
368
+ const commandIndex = project.commands.findIndex(c => c.id === command.id);
369
+ if (commandIndex !== -1) {
370
+ project.commands[commandIndex] = command;
371
+ }
372
+ else {
373
+ project.commands.push(command);
374
+ }
375
+ await this.metadataManager.saveProjects(projects);
376
+ }
377
+ /**
378
+ * Deletes a command from a project
379
+ * @param projectId - The project ID
380
+ * @param commandId - The ID of the command to delete
381
+ */
382
+ async deleteCommand(projectId, commandId) {
383
+ const projects = await this.metadataManager.loadProjects();
384
+ const projectIndex = projects.findIndex(p => p.id === projectId);
385
+ if (projectIndex === -1) {
386
+ throw new Error(`Project not found: ${projectId}`);
387
+ }
388
+ const project = projects[projectIndex];
389
+ if (project.commands) {
390
+ project.commands = project.commands.filter(c => c.id !== commandId);
391
+ }
392
+ await this.metadataManager.saveProjects(projects);
393
+ }
394
+ /**
395
+ * Runs a command in a thread's directory
396
+ * @param threadId - The thread ID where to run the command
397
+ * @param commandLine - The command line to execute
398
+ */
399
+ async *runCommand(threadId, commandLine, cwd) {
400
+ const threads = await this.metadataManager.loadThreads();
401
+ const thread = threads.find(t => t.id === threadId);
402
+ if (!thread) {
403
+ throw new Error(`Thread not found: ${threadId}`);
404
+ }
405
+ const { spawn } = await import('child_process');
406
+ const workingDir = cwd ? (cwd.startsWith('/') ? cwd : join(thread.path, cwd)) : thread.path;
407
+ // Use shell for complex command lines
408
+ // Append a command to output the final working directory
409
+ const child = spawn(`${commandLine}; printf "\\n___CWD___%s\\n" "$(pwd)"`, {
410
+ shell: true,
411
+ cwd: workingDir,
412
+ });
413
+ const decoder = new TextDecoder();
414
+ const outputBuffer = [];
415
+ let isDone = false;
416
+ child.stdout.on('data', (data) => {
417
+ const text = decoder.decode(data);
418
+ // Check if this chunk contains our CWD marker
419
+ if (text.includes("___CWD___")) {
420
+ const parts = text.split("___CWD___");
421
+ if (parts[0])
422
+ outputBuffer.push(parts[0]);
423
+ const newCwd = parts[1].trim();
424
+ if (newCwd) {
425
+ try {
426
+ const realThreadPath = realpathSync(thread.path);
427
+ const realNewCwd = realpathSync(newCwd);
428
+ let relativeCwd = relative(realThreadPath, realNewCwd);
429
+ if (!relativeCwd)
430
+ relativeCwd = ".";
431
+ outputBuffer.push({ type: 'cwd', path: relativeCwd });
432
+ }
433
+ catch {
434
+ outputBuffer.push({ type: 'cwd', path: "." });
435
+ }
436
+ }
437
+ }
438
+ else {
439
+ outputBuffer.push(text);
440
+ }
441
+ });
442
+ child.stderr.on('data', (data) => {
443
+ outputBuffer.push({ type: 'error', message: decoder.decode(data) });
444
+ });
445
+ child.on('close', (code) => {
446
+ if (code !== 0) {
447
+ outputBuffer.push({ type: 'error', message: `Process exited with code ${code}` });
448
+ }
449
+ isDone = true;
450
+ });
451
+ child.on('error', (err) => {
452
+ outputBuffer.push({ type: 'error', message: err.message });
453
+ isDone = true;
454
+ });
455
+ while (!isDone || outputBuffer.length > 0) {
456
+ if (outputBuffer.length > 0) {
457
+ yield outputBuffer.shift();
458
+ }
459
+ else {
460
+ await new Promise(resolve => setTimeout(resolve, 50));
461
+ }
462
+ }
463
+ }
464
+ }
465
+ //# sourceMappingURL=project-manager.js.map
@@ -0,0 +1,193 @@
1
+ /**
2
+ * ThreadManager handles thread lifecycle and metadata management
3
+ *
4
+ * This manager is responsible for:
5
+ * - Creating new threads for existing projects
6
+ * - Managing thread metadata
7
+ * - Coordinating with GitManager for repository cloning
8
+ * - Providing CRUD operations for threads
9
+ * - Ensuring thread path uniqueness
10
+ */
11
+ import { Thread, ThreadEvent } from '../types/models.js';
12
+ import { MetadataManager } from './metadata-manager.js';
13
+ import { GitManager } from './git-manager.js';
14
+ /**
15
+ * ThreadManager interface defines the contract for thread operations
16
+ */
17
+ export interface ThreadManager {
18
+ /**
19
+ * Creates a new thread for an existing project
20
+ * @param projectId - The parent project ID
21
+ * @param title - Optional thread title (auto-generated if not provided)
22
+ * @yields ThreadEvent objects during the creation process
23
+ */
24
+ createThread(projectId: string, title?: string): AsyncGenerator<ThreadEvent>;
25
+ /**
26
+ * Gets a thread by ID
27
+ * @param threadId - The thread ID
28
+ * @returns The thread or null if not found
29
+ */
30
+ getThread(threadId: string): Promise<Thread | null>;
31
+ /**
32
+ * Lists all threads for a specific project
33
+ * @param projectId - The project ID to filter threads
34
+ * @returns Array of threads for the project
35
+ */
36
+ listThreads(projectId: string): Promise<Thread[]>;
37
+ /**
38
+ * Deletes a thread and removes its directory
39
+ * @param threadId - The thread ID to delete
40
+ */
41
+ deleteThread(threadId: string): Promise<void>;
42
+ /**
43
+ * Updates a thread's metadata with partial data
44
+ * @param threadId - The thread ID to update
45
+ * @param updates - Partial thread data to merge
46
+ */
47
+ updateThread(threadId: string, updates: Partial<Omit<Thread, 'id'>>): Promise<void>;
48
+ /**
49
+ * Selects a thread as the active thread
50
+ * @param threadId - The thread ID to select
51
+ */
52
+ selectThread(threadId: string): Promise<void>;
53
+ /**
54
+ * Gets the currently selected thread ID
55
+ * @returns The selected thread ID or null
56
+ */
57
+ getSelectedThreadId(): Promise<string | null>;
58
+ /**
59
+ * Lists all files in a thread's directory (tracked and untracked, but not ignored)
60
+ * @param threadId - The thread ID
61
+ * @returns Array of file paths relative to the thread root
62
+ */
63
+ listFiles(threadId: string): Promise<string[]>;
64
+ }
65
+ /**
66
+ * ThreadManagerImpl provides the implementation for thread operations
67
+ */
68
+ export declare class ThreadManagerImpl implements ThreadManager {
69
+ private metadataManager;
70
+ private gitManager;
71
+ /**
72
+ * Create a new ThreadManager
73
+ * @param metadataManager - Manager for persisting metadata
74
+ * @param gitManager - Manager for git operations
75
+ *
76
+ * Requirements:
77
+ * - 2.1 - WHEN a user creates a new Thread for a Project, THE CLI SHALL create a new clone of the Project's git repository
78
+ * - 2.4 - THE System SHALL maintain a title for each Thread
79
+ */
80
+ constructor(metadataManager: MetadataManager, gitManager: GitManager);
81
+ /**
82
+ * Creates a new thread for an existing project
83
+ *
84
+ * This method:
85
+ * 1. Validates that the project exists
86
+ * 2. Generates a unique thread ID
87
+ * 3. Gets the project's git URL
88
+ * 4. Generates a unique thread path
89
+ * 5. Delegates to GitManager for cloning
90
+ * 6. Saves thread metadata
91
+ * 7. Updates the project's thread list
92
+ * 8. Yields progress events during the operation
93
+ *
94
+ * @param projectId - The parent project ID
95
+ * @param title - Optional thread title (auto-generated if not provided)
96
+ * @yields ThreadEvent objects during the creation process
97
+ *
98
+ * Requirements:
99
+ * - 2.1 - WHEN a user creates a new Thread for a Project, THE CLI SHALL create a new clone of the Project's git repository
100
+ * - 2.2 - WHEN a Thread is created, THE App SHALL display it under its parent Project in the Side_Panel
101
+ * - 2.4 - THE System SHALL maintain a title for each Thread
102
+ * - 7.4 - THE CLI SHALL ensure each Thread clone is stored in a unique directory path
103
+ */
104
+ createThread(projectId: string, title?: string): AsyncGenerator<ThreadEvent>;
105
+ /**
106
+ * Gets a thread by ID
107
+ * @param threadId - The thread ID
108
+ * @returns The thread or null if not found
109
+ */
110
+ getThread(threadId: string): Promise<Thread | null>;
111
+ /**
112
+ * Lists all threads for a specific project
113
+ * @param projectId - The project ID to filter threads
114
+ * @returns Array of threads for the project
115
+ *
116
+ * Requirements:
117
+ * - 2.1 - WHEN a Thread is created, THE App SHALL display it under its parent Project in the Side_Panel
118
+ */
119
+ listThreads(projectId: string): Promise<Thread[]>;
120
+ /**
121
+ * Deletes a thread and removes its directory
122
+ *
123
+ * This method:
124
+ * 1. Finds the thread by ID
125
+ * 2. Removes the thread directory from filesystem
126
+ * 3. Removes the thread from metadata
127
+ * 4. Updates the parent project's thread list
128
+ *
129
+ * @param threadId - The thread ID to delete
130
+ * @throws Error if thread not found
131
+ *
132
+ * Requirements:
133
+ * - 2.3 - WHEN a user deletes a Thread, THE System SHALL remove the Thread's folder and update the Side_Panel display
134
+ * - 7.5 - WHEN a Thread is deleted, THE CLI SHALL remove the associated git repository clone from the filesystem
135
+ */
136
+ deleteThread(threadId: string): Promise<void>;
137
+ /**
138
+ * Updates a thread's metadata with partial data
139
+ *
140
+ * This method loads all threads, finds the target, merges the updates,
141
+ * and persists the result.
142
+ *
143
+ * @param threadId - The thread ID to update
144
+ * @param updates - Partial thread data to merge
145
+ * @throws Error if thread not found
146
+ */
147
+ updateThread(threadId: string, updates: Partial<Omit<Thread, 'id'>>): Promise<void>;
148
+ /**
149
+ * Selects a thread as the active thread
150
+ *
151
+ * @param threadId - The thread ID to select
152
+ */
153
+ selectThread(threadId: string): Promise<void>;
154
+ /**
155
+ * Gets the currently selected thread ID
156
+ *
157
+ * @returns The selected thread ID or null
158
+ */
159
+ getSelectedThreadId(): Promise<string | null>;
160
+ /**
161
+ * Generates a unique thread path
162
+ *
163
+ * Path format: {projectPath}/{threadId}
164
+ *
165
+ * This ensures thread paths are unique across all projects and threads.
166
+ *
167
+ * @param projectPath - The parent project path
168
+ * @param threadId - The thread ID
169
+ * @returns The absolute path to the thread folder
170
+ *
171
+ * Requirements:
172
+ * - 7.4 - THE CLI SHALL ensure each Thread clone is stored in a unique directory path
173
+ */
174
+ private generateThreadPath;
175
+ /**
176
+ * Generates a thread title if not provided
177
+ *
178
+ * Format: project-name Thread word1-word2
179
+ *
180
+ * @param existingTitles - Set of titles already in use
181
+ * @param threadId - Thread ID used as a fallback
182
+ * @param projectName - Optional project name to include in title
183
+ * @returns The generated thread title
184
+ */
185
+ private generateThreadTitle;
186
+ /**
187
+ * Lists all files in a thread's directory (tracked and untracked, but not ignored)
188
+ * @param threadId - The thread ID
189
+ * @returns Array of file paths relative to the thread root
190
+ */
191
+ listFiles(threadId: string): Promise<string[]>;
192
+ }
193
+ //# sourceMappingURL=thread-manager.d.ts.map