@cloudcli-ai/cloudcli 1.29.5 → 1.30.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 (179) hide show
  1. package/README.de.md +1 -1
  2. package/README.ja.md +1 -1
  3. package/README.ko.md +1 -1
  4. package/README.md +1 -1
  5. package/README.ru.md +1 -1
  6. package/README.tr.md +252 -0
  7. package/README.zh-CN.md +1 -1
  8. package/dist/assets/index-DI22MZMb.css +32 -0
  9. package/dist/assets/index-RX-W_g_Q.js +1262 -0
  10. package/dist/index.html +2 -2
  11. package/dist-server/server/claude-sdk.js +13 -8
  12. package/dist-server/server/claude-sdk.js.map +1 -1
  13. package/dist-server/server/cursor-cli.js +7 -7
  14. package/dist-server/server/cursor-cli.js.map +1 -1
  15. package/dist-server/server/gemini-cli.js +5 -5
  16. package/dist-server/server/gemini-cli.js.map +1 -1
  17. package/dist-server/server/gemini-response-handler.js +2 -2
  18. package/dist-server/server/gemini-response-handler.js.map +1 -1
  19. package/dist-server/server/index.js +27 -25
  20. package/dist-server/server/index.js.map +1 -1
  21. package/dist-server/server/modules/providers/list/claude/claude-auth.provider.js +103 -0
  22. package/dist-server/server/modules/providers/list/claude/claude-auth.provider.js.map +1 -0
  23. package/dist-server/server/modules/providers/list/claude/claude-mcp.provider.js +103 -0
  24. package/dist-server/server/modules/providers/list/claude/claude-mcp.provider.js.map +1 -0
  25. package/dist-server/server/modules/providers/list/claude/claude-sessions.provider.js +266 -0
  26. package/dist-server/server/modules/providers/list/claude/claude-sessions.provider.js.map +1 -0
  27. package/dist-server/server/modules/providers/list/claude/claude.provider.js +13 -0
  28. package/dist-server/server/modules/providers/list/claude/claude.provider.js.map +1 -0
  29. package/dist-server/server/modules/providers/list/codex/codex-auth.provider.js +84 -0
  30. package/dist-server/server/modules/providers/list/codex/codex-auth.provider.js.map +1 -0
  31. package/dist-server/server/modules/providers/list/codex/codex-mcp.provider.js +107 -0
  32. package/dist-server/server/modules/providers/list/codex/codex-mcp.provider.js.map +1 -0
  33. package/dist-server/server/modules/providers/list/codex/codex-sessions.provider.js +282 -0
  34. package/dist-server/server/modules/providers/list/codex/codex-sessions.provider.js.map +1 -0
  35. package/dist-server/server/modules/providers/list/codex/codex.provider.js +13 -0
  36. package/dist-server/server/modules/providers/list/codex/codex.provider.js.map +1 -0
  37. package/dist-server/server/modules/providers/list/cursor/cursor-auth.provider.js +118 -0
  38. package/dist-server/server/modules/providers/list/cursor/cursor-auth.provider.js.map +1 -0
  39. package/dist-server/server/modules/providers/list/cursor/cursor-mcp.provider.js +80 -0
  40. package/dist-server/server/modules/providers/list/cursor/cursor-mcp.provider.js.map +1 -0
  41. package/dist-server/server/modules/providers/list/cursor/cursor-sessions.provider.js +369 -0
  42. package/dist-server/server/modules/providers/list/cursor/cursor-sessions.provider.js.map +1 -0
  43. package/dist-server/server/modules/providers/list/cursor/cursor.provider.js +13 -0
  44. package/dist-server/server/modules/providers/list/cursor/cursor.provider.js.map +1 -0
  45. package/dist-server/server/modules/providers/list/gemini/gemini-auth.provider.js +131 -0
  46. package/dist-server/server/modules/providers/list/gemini/gemini-auth.provider.js.map +1 -0
  47. package/dist-server/server/modules/providers/list/gemini/gemini-mcp.provider.js +82 -0
  48. package/dist-server/server/modules/providers/list/gemini/gemini-mcp.provider.js.map +1 -0
  49. package/dist-server/server/modules/providers/list/gemini/gemini-sessions.provider.js +207 -0
  50. package/dist-server/server/modules/providers/list/gemini/gemini-sessions.provider.js.map +1 -0
  51. package/dist-server/server/modules/providers/list/gemini/gemini.provider.js +13 -0
  52. package/dist-server/server/modules/providers/list/gemini/gemini.provider.js.map +1 -0
  53. package/dist-server/server/modules/providers/provider.registry.js +31 -0
  54. package/dist-server/server/modules/providers/provider.registry.js.map +1 -0
  55. package/dist-server/server/modules/providers/provider.routes.js +159 -0
  56. package/dist-server/server/modules/providers/provider.routes.js.map +1 -0
  57. package/dist-server/server/modules/providers/services/mcp.service.js +69 -0
  58. package/dist-server/server/modules/providers/services/mcp.service.js.map +1 -0
  59. package/dist-server/server/modules/providers/services/provider-auth.service.js +25 -0
  60. package/dist-server/server/modules/providers/services/provider-auth.service.js.map +1 -0
  61. package/dist-server/server/modules/providers/services/sessions.service.js +29 -0
  62. package/dist-server/server/modules/providers/services/sessions.service.js.map +1 -0
  63. package/dist-server/server/modules/providers/shared/base/abstract.provider.js +14 -0
  64. package/dist-server/server/modules/providers/shared/base/abstract.provider.js.map +1 -0
  65. package/dist-server/server/modules/providers/shared/mcp/mcp.provider.js +102 -0
  66. package/dist-server/server/modules/providers/shared/mcp/mcp.provider.js.map +1 -0
  67. package/dist-server/server/modules/providers/tests/mcp.test.js +250 -0
  68. package/dist-server/server/modules/providers/tests/mcp.test.js.map +1 -0
  69. package/dist-server/server/openai-codex.js +5 -5
  70. package/dist-server/server/openai-codex.js.map +1 -1
  71. package/dist-server/server/routes/codex.js +2 -278
  72. package/dist-server/server/routes/codex.js.map +1 -1
  73. package/dist-server/server/routes/commands.js +0 -44
  74. package/dist-server/server/routes/commands.js.map +1 -1
  75. package/dist-server/server/routes/cursor.js +9 -489
  76. package/dist-server/server/routes/cursor.js.map +1 -1
  77. package/dist-server/server/routes/mcp-utils.js +1 -18
  78. package/dist-server/server/routes/mcp-utils.js.map +1 -1
  79. package/dist-server/server/routes/messages.js +6 -6
  80. package/dist-server/server/routes/messages.js.map +1 -1
  81. package/dist-server/server/routes/settings.js +10 -0
  82. package/dist-server/server/routes/settings.js.map +1 -1
  83. package/dist-server/server/routes/taskmaster.js +0 -459
  84. package/dist-server/server/routes/taskmaster.js.map +1 -1
  85. package/dist-server/server/shared/interfaces.js +2 -0
  86. package/dist-server/server/shared/interfaces.js.map +1 -0
  87. package/dist-server/server/shared/types.js +3 -0
  88. package/dist-server/server/shared/types.js.map +1 -0
  89. package/dist-server/server/shared/utils.js +150 -0
  90. package/dist-server/server/shared/utils.js.map +1 -0
  91. package/dist-server/server/utils/mcp-detector.js +0 -49
  92. package/dist-server/server/utils/mcp-detector.js.map +1 -1
  93. package/dist-server/shared/modelConstants.js +1 -0
  94. package/dist-server/shared/modelConstants.js.map +1 -1
  95. package/package.json +5 -2
  96. package/server/claude-sdk.js +14 -8
  97. package/server/cursor-cli.js +7 -7
  98. package/server/gemini-cli.js +5 -5
  99. package/server/gemini-response-handler.js +2 -2
  100. package/server/index.js +33 -29
  101. package/server/modules/providers/list/claude/claude-auth.provider.ts +123 -0
  102. package/server/modules/providers/list/claude/claude-mcp.provider.ts +135 -0
  103. package/server/modules/providers/list/claude/claude-sessions.provider.ts +306 -0
  104. package/server/modules/providers/list/claude/claude.provider.ts +15 -0
  105. package/server/modules/providers/list/codex/codex-auth.provider.ts +100 -0
  106. package/server/modules/providers/list/codex/codex-mcp.provider.ts +135 -0
  107. package/server/modules/providers/list/codex/codex-sessions.provider.ts +319 -0
  108. package/server/modules/providers/list/codex/codex.provider.ts +15 -0
  109. package/server/modules/providers/list/cursor/cursor-auth.provider.ts +143 -0
  110. package/server/modules/providers/list/cursor/cursor-mcp.provider.ts +108 -0
  111. package/server/modules/providers/list/cursor/cursor-sessions.provider.ts +421 -0
  112. package/server/modules/providers/list/cursor/cursor.provider.ts +15 -0
  113. package/server/modules/providers/list/gemini/gemini-auth.provider.ts +151 -0
  114. package/server/modules/providers/list/gemini/gemini-mcp.provider.ts +110 -0
  115. package/server/modules/providers/list/gemini/gemini-sessions.provider.ts +227 -0
  116. package/server/modules/providers/list/gemini/gemini.provider.ts +15 -0
  117. package/server/modules/providers/provider.registry.ts +36 -0
  118. package/server/modules/providers/provider.routes.ts +217 -0
  119. package/server/modules/providers/services/mcp.service.ts +94 -0
  120. package/server/modules/providers/services/provider-auth.service.ts +26 -0
  121. package/server/modules/providers/services/sessions.service.ts +45 -0
  122. package/server/modules/providers/shared/base/abstract.provider.ts +20 -0
  123. package/server/modules/providers/shared/mcp/mcp.provider.ts +151 -0
  124. package/server/modules/providers/tests/mcp.test.ts +293 -0
  125. package/server/openai-codex.js +5 -5
  126. package/server/routes/codex.js +2 -312
  127. package/server/routes/commands.js +0 -49
  128. package/server/routes/cursor.js +15 -527
  129. package/server/routes/mcp-utils.js +2 -19
  130. package/server/routes/messages.js +6 -6
  131. package/server/routes/settings.js +10 -0
  132. package/server/routes/taskmaster.js +0 -492
  133. package/server/shared/interfaces.ts +54 -0
  134. package/server/shared/types.ts +172 -0
  135. package/server/shared/utils.ts +193 -0
  136. package/server/tsconfig.json +6 -3
  137. package/server/utils/mcp-detector.js +0 -51
  138. package/shared/modelConstants.js +1 -0
  139. package/dist/assets/index-BBAE1OJ_.css +0 -32
  140. package/dist/assets/index-Ci1GOyV7.js +0 -1262
  141. package/dist-server/server/providers/claude/adapter.js +0 -266
  142. package/dist-server/server/providers/claude/adapter.js.map +0 -1
  143. package/dist-server/server/providers/claude/status.js +0 -121
  144. package/dist-server/server/providers/claude/status.js.map +0 -1
  145. package/dist-server/server/providers/codex/adapter.js +0 -232
  146. package/dist-server/server/providers/codex/adapter.js.map +0 -1
  147. package/dist-server/server/providers/codex/status.js +0 -70
  148. package/dist-server/server/providers/codex/status.js.map +0 -1
  149. package/dist-server/server/providers/cursor/adapter.js +0 -342
  150. package/dist-server/server/providers/cursor/adapter.js.map +0 -1
  151. package/dist-server/server/providers/cursor/status.js +0 -118
  152. package/dist-server/server/providers/cursor/status.js.map +0 -1
  153. package/dist-server/server/providers/gemini/adapter.js +0 -174
  154. package/dist-server/server/providers/gemini/adapter.js.map +0 -1
  155. package/dist-server/server/providers/gemini/status.js +0 -104
  156. package/dist-server/server/providers/gemini/status.js.map +0 -1
  157. package/dist-server/server/providers/registry.js +0 -58
  158. package/dist-server/server/providers/registry.js.map +0 -1
  159. package/dist-server/server/providers/types.js +0 -117
  160. package/dist-server/server/providers/types.js.map +0 -1
  161. package/dist-server/server/providers/utils.js +0 -28
  162. package/dist-server/server/providers/utils.js.map +0 -1
  163. package/dist-server/server/routes/cli-auth.js +0 -25
  164. package/dist-server/server/routes/cli-auth.js.map +0 -1
  165. package/dist-server/server/routes/mcp.js +0 -480
  166. package/dist-server/server/routes/mcp.js.map +0 -1
  167. package/server/providers/claude/adapter.js +0 -278
  168. package/server/providers/claude/status.js +0 -136
  169. package/server/providers/codex/adapter.js +0 -248
  170. package/server/providers/codex/status.js +0 -78
  171. package/server/providers/cursor/adapter.js +0 -348
  172. package/server/providers/cursor/status.js +0 -128
  173. package/server/providers/gemini/adapter.js +0 -186
  174. package/server/providers/gemini/status.js +0 -111
  175. package/server/providers/registry.js +0 -67
  176. package/server/providers/types.js +0 -132
  177. package/server/providers/utils.js +0 -29
  178. package/server/routes/cli-auth.js +0 -27
  179. package/server/routes/mcp.js +0 -552
@@ -273,4 +273,14 @@ router.post('/push/unsubscribe', async (req, res) => {
273
273
  }
274
274
  });
275
275
 
276
+ // Host OS for UI (e.g. hide Cursor agent when the backend runs on Windows).
277
+ router.get('/server-env', async (req, res) => {
278
+ try {
279
+ res.json({ platform: process.platform });
280
+ } catch (error) {
281
+ console.error('Error reading server environment:', error);
282
+ res.status(500).json({ error: 'Failed to read server environment' });
283
+ }
284
+ });
285
+
276
286
  export default router;
@@ -13,16 +13,10 @@ import fs from 'fs';
13
13
  import path from 'path';
14
14
  import { promises as fsPromises } from 'fs';
15
15
  import { spawn } from 'child_process';
16
- import { fileURLToPath } from 'url';
17
- import { dirname } from 'path';
18
- import os from 'os';
19
16
  import { extractProjectDirectory } from '../projects.js';
20
17
  import { detectTaskMasterMCPServer } from '../utils/mcp-detector.js';
21
18
  import { broadcastTaskMasterProjectUpdate, broadcastTaskMasterTasksUpdate } from '../utils/taskmaster-websocket.js';
22
19
 
23
- const __filename = fileURLToPath(import.meta.url);
24
- const __dirname = dirname(__filename);
25
-
26
20
  const router = express.Router();
27
21
 
28
22
  /**
@@ -100,140 +94,6 @@ async function checkTaskMasterInstallation() {
100
94
  });
101
95
  }
102
96
 
103
- /**
104
- * Detect .taskmaster folder presence in a given project directory
105
- * @param {string} projectPath - Absolute path to project directory
106
- * @returns {Promise<Object>} Detection result with status and metadata
107
- */
108
- async function detectTaskMasterFolder(projectPath) {
109
- try {
110
- const taskMasterPath = path.join(projectPath, '.taskmaster');
111
-
112
- // Check if .taskmaster directory exists
113
- try {
114
- const stats = await fsPromises.stat(taskMasterPath);
115
- if (!stats.isDirectory()) {
116
- return {
117
- hasTaskmaster: false,
118
- reason: '.taskmaster exists but is not a directory'
119
- };
120
- }
121
- } catch (error) {
122
- if (error.code === 'ENOENT') {
123
- return {
124
- hasTaskmaster: false,
125
- reason: '.taskmaster directory not found'
126
- };
127
- }
128
- throw error;
129
- }
130
-
131
- // Check for key TaskMaster files
132
- const keyFiles = [
133
- 'tasks/tasks.json',
134
- 'config.json'
135
- ];
136
-
137
- const fileStatus = {};
138
- let hasEssentialFiles = true;
139
-
140
- for (const file of keyFiles) {
141
- const filePath = path.join(taskMasterPath, file);
142
- try {
143
- await fsPromises.access(filePath, fs.constants.R_OK);
144
- fileStatus[file] = true;
145
- } catch (error) {
146
- fileStatus[file] = false;
147
- if (file === 'tasks/tasks.json') {
148
- hasEssentialFiles = false;
149
- }
150
- }
151
- }
152
-
153
- // Parse tasks.json if it exists for metadata
154
- let taskMetadata = null;
155
- if (fileStatus['tasks/tasks.json']) {
156
- try {
157
- const tasksPath = path.join(taskMasterPath, 'tasks/tasks.json');
158
- const tasksContent = await fsPromises.readFile(tasksPath, 'utf8');
159
- const tasksData = JSON.parse(tasksContent);
160
-
161
- // Handle both tagged and legacy formats
162
- let tasks = [];
163
- if (tasksData.tasks) {
164
- // Legacy format
165
- tasks = tasksData.tasks;
166
- } else {
167
- // Tagged format - get tasks from all tags
168
- Object.values(tasksData).forEach(tagData => {
169
- if (tagData.tasks) {
170
- tasks = tasks.concat(tagData.tasks);
171
- }
172
- });
173
- }
174
-
175
- // Calculate task statistics
176
- const stats = tasks.reduce((acc, task) => {
177
- acc.total++;
178
- acc[task.status] = (acc[task.status] || 0) + 1;
179
-
180
- // Count subtasks
181
- if (task.subtasks) {
182
- task.subtasks.forEach(subtask => {
183
- acc.subtotalTasks++;
184
- acc.subtasks = acc.subtasks || {};
185
- acc.subtasks[subtask.status] = (acc.subtasks[subtask.status] || 0) + 1;
186
- });
187
- }
188
-
189
- return acc;
190
- }, {
191
- total: 0,
192
- subtotalTasks: 0,
193
- pending: 0,
194
- 'in-progress': 0,
195
- done: 0,
196
- review: 0,
197
- deferred: 0,
198
- cancelled: 0,
199
- subtasks: {}
200
- });
201
-
202
- taskMetadata = {
203
- taskCount: stats.total,
204
- subtaskCount: stats.subtotalTasks,
205
- completed: stats.done || 0,
206
- pending: stats.pending || 0,
207
- inProgress: stats['in-progress'] || 0,
208
- review: stats.review || 0,
209
- completionPercentage: stats.total > 0 ? Math.round((stats.done / stats.total) * 100) : 0,
210
- lastModified: (await fsPromises.stat(tasksPath)).mtime.toISOString()
211
- };
212
- } catch (parseError) {
213
- console.warn('Failed to parse tasks.json:', parseError.message);
214
- taskMetadata = { error: 'Failed to parse tasks.json' };
215
- }
216
- }
217
-
218
- return {
219
- hasTaskmaster: true,
220
- hasEssentialFiles,
221
- files: fileStatus,
222
- metadata: taskMetadata,
223
- path: taskMasterPath
224
- };
225
-
226
- } catch (error) {
227
- console.error('Error detecting TaskMaster folder:', error);
228
- return {
229
- hasTaskmaster: false,
230
- reason: `Error checking directory: ${error.message}`
231
- };
232
- }
233
- }
234
-
235
- // MCP detection is now handled by the centralized utility
236
-
237
97
  // API Routes
238
98
 
239
99
  /**
@@ -271,298 +131,6 @@ router.get('/installation-status', async (req, res) => {
271
131
  }
272
132
  });
273
133
 
274
- /**
275
- * GET /api/taskmaster/detect/:projectName
276
- * Detect TaskMaster configuration for a specific project
277
- */
278
- router.get('/detect/:projectName', async (req, res) => {
279
- try {
280
- const { projectName } = req.params;
281
-
282
- // Use the existing extractProjectDirectory function to get actual project path
283
- let projectPath;
284
- try {
285
- projectPath = await extractProjectDirectory(projectName);
286
- } catch (error) {
287
- console.error('Error extracting project directory:', error);
288
- return res.status(404).json({
289
- error: 'Project path not found',
290
- projectName,
291
- message: error.message
292
- });
293
- }
294
-
295
- // Verify the project path exists
296
- try {
297
- await fsPromises.access(projectPath, fs.constants.R_OK);
298
- } catch (error) {
299
- return res.status(404).json({
300
- error: 'Project path not accessible',
301
- projectPath,
302
- projectName,
303
- message: error.message
304
- });
305
- }
306
-
307
- // Run detection in parallel
308
- const [taskMasterResult, mcpResult] = await Promise.all([
309
- detectTaskMasterFolder(projectPath),
310
- detectTaskMasterMCPServer()
311
- ]);
312
-
313
- // Determine overall status
314
- let status = 'not-configured';
315
- if (taskMasterResult.hasTaskmaster && taskMasterResult.hasEssentialFiles) {
316
- if (mcpResult.hasMCPServer && mcpResult.isConfigured) {
317
- status = 'fully-configured';
318
- } else {
319
- status = 'taskmaster-only';
320
- }
321
- } else if (mcpResult.hasMCPServer && mcpResult.isConfigured) {
322
- status = 'mcp-only';
323
- }
324
-
325
- const responseData = {
326
- projectName,
327
- projectPath,
328
- status,
329
- taskmaster: taskMasterResult,
330
- mcp: mcpResult,
331
- timestamp: new Date().toISOString()
332
- };
333
-
334
- res.json(responseData);
335
-
336
- } catch (error) {
337
- console.error('TaskMaster detection error:', error);
338
- res.status(500).json({
339
- error: 'Failed to detect TaskMaster configuration',
340
- message: error.message
341
- });
342
- }
343
- });
344
-
345
- /**
346
- * GET /api/taskmaster/detect-all
347
- * Detect TaskMaster configuration for all known projects
348
- * This endpoint works with the existing projects system
349
- */
350
- router.get('/detect-all', async (req, res) => {
351
- try {
352
- // Import getProjects from the projects module
353
- const { getProjects } = await import('../projects.js');
354
- const projects = await getProjects();
355
-
356
- // Run detection for all projects in parallel
357
- const detectionPromises = projects.map(async (project) => {
358
- try {
359
- // Use the project's fullPath if available, otherwise extract the directory
360
- let projectPath;
361
- if (project.fullPath) {
362
- projectPath = project.fullPath;
363
- } else {
364
- try {
365
- projectPath = await extractProjectDirectory(project.name);
366
- } catch (error) {
367
- throw new Error(`Failed to extract project directory: ${error.message}`);
368
- }
369
- }
370
-
371
- const [taskMasterResult, mcpResult] = await Promise.all([
372
- detectTaskMasterFolder(projectPath),
373
- detectTaskMasterMCPServer()
374
- ]);
375
-
376
- // Determine status
377
- let status = 'not-configured';
378
- if (taskMasterResult.hasTaskmaster && taskMasterResult.hasEssentialFiles) {
379
- if (mcpResult.hasMCPServer && mcpResult.isConfigured) {
380
- status = 'fully-configured';
381
- } else {
382
- status = 'taskmaster-only';
383
- }
384
- } else if (mcpResult.hasMCPServer && mcpResult.isConfigured) {
385
- status = 'mcp-only';
386
- }
387
-
388
- return {
389
- projectName: project.name,
390
- displayName: project.displayName,
391
- projectPath,
392
- status,
393
- taskmaster: taskMasterResult,
394
- mcp: mcpResult
395
- };
396
- } catch (error) {
397
- return {
398
- projectName: project.name,
399
- displayName: project.displayName,
400
- status: 'error',
401
- error: error.message
402
- };
403
- }
404
- });
405
-
406
- const results = await Promise.all(detectionPromises);
407
-
408
- res.json({
409
- projects: results,
410
- summary: {
411
- total: results.length,
412
- fullyConfigured: results.filter(p => p.status === 'fully-configured').length,
413
- taskmasterOnly: results.filter(p => p.status === 'taskmaster-only').length,
414
- mcpOnly: results.filter(p => p.status === 'mcp-only').length,
415
- notConfigured: results.filter(p => p.status === 'not-configured').length,
416
- errors: results.filter(p => p.status === 'error').length
417
- },
418
- timestamp: new Date().toISOString()
419
- });
420
-
421
- } catch (error) {
422
- console.error('Bulk TaskMaster detection error:', error);
423
- res.status(500).json({
424
- error: 'Failed to detect TaskMaster configuration for projects',
425
- message: error.message
426
- });
427
- }
428
- });
429
-
430
- /**
431
- * POST /api/taskmaster/initialize/:projectName
432
- * Initialize TaskMaster in a project (placeholder for future CLI integration)
433
- */
434
- router.post('/initialize/:projectName', async (req, res) => {
435
- try {
436
- const { projectName } = req.params;
437
- const { rules } = req.body; // Optional rule profiles
438
-
439
- // This will be implemented in a later subtask with CLI integration
440
- res.status(501).json({
441
- error: 'TaskMaster initialization not yet implemented',
442
- message: 'This endpoint will execute task-master init via CLI in a future update',
443
- projectName,
444
- rules
445
- });
446
-
447
- } catch (error) {
448
- console.error('TaskMaster initialization error:', error);
449
- res.status(500).json({
450
- error: 'Failed to initialize TaskMaster',
451
- message: error.message
452
- });
453
- }
454
- });
455
-
456
- /**
457
- * GET /api/taskmaster/next/:projectName
458
- * Get the next recommended task using task-master CLI
459
- */
460
- router.get('/next/:projectName', async (req, res) => {
461
- try {
462
- const { projectName } = req.params;
463
-
464
- // Get project path
465
- let projectPath;
466
- try {
467
- projectPath = await extractProjectDirectory(projectName);
468
- } catch (error) {
469
- return res.status(404).json({
470
- error: 'Project not found',
471
- message: `Project "${projectName}" does not exist`
472
- });
473
- }
474
-
475
- // Try to execute task-master next command
476
- try {
477
- const { spawn } = await import('child_process');
478
-
479
- const nextTaskCommand = spawn('task-master', ['next'], {
480
- cwd: projectPath,
481
- stdio: ['pipe', 'pipe', 'pipe']
482
- });
483
-
484
- let stdout = '';
485
- let stderr = '';
486
-
487
- nextTaskCommand.stdout.on('data', (data) => {
488
- stdout += data.toString();
489
- });
490
-
491
- nextTaskCommand.stderr.on('data', (data) => {
492
- stderr += data.toString();
493
- });
494
-
495
- await new Promise((resolve, reject) => {
496
- nextTaskCommand.on('close', (code) => {
497
- if (code === 0) {
498
- resolve();
499
- } else {
500
- reject(new Error(`task-master next failed with code ${code}: ${stderr}`));
501
- }
502
- });
503
-
504
- nextTaskCommand.on('error', (error) => {
505
- reject(error);
506
- });
507
- });
508
-
509
- // Parse the output - task-master next usually returns JSON
510
- let nextTaskData = null;
511
- if (stdout.trim()) {
512
- try {
513
- nextTaskData = JSON.parse(stdout);
514
- } catch (parseError) {
515
- // If not JSON, treat as plain text
516
- nextTaskData = { message: stdout.trim() };
517
- }
518
- }
519
-
520
- res.json({
521
- projectName,
522
- projectPath,
523
- nextTask: nextTaskData,
524
- timestamp: new Date().toISOString()
525
- });
526
-
527
- } catch (cliError) {
528
- console.warn('Failed to execute task-master CLI:', cliError.message);
529
-
530
- // Fallback to loading tasks and finding next one locally
531
- // Use localhost to bypass proxy for internal server-to-server calls
532
- const tasksResponse = await fetch(`http://localhost:${process.env.SERVER_PORT || process.env.PORT || '3001'}/api/taskmaster/tasks/${encodeURIComponent(projectName)}`, {
533
- headers: {
534
- 'Authorization': req.headers.authorization
535
- }
536
- });
537
-
538
- if (tasksResponse.ok) {
539
- const tasksData = await tasksResponse.json();
540
- const nextTask = tasksData.tasks?.find(task =>
541
- task.status === 'pending' || task.status === 'in-progress'
542
- ) || null;
543
-
544
- res.json({
545
- projectName,
546
- projectPath,
547
- nextTask,
548
- fallback: true,
549
- message: 'Used fallback method (CLI not available)',
550
- timestamp: new Date().toISOString()
551
- });
552
- } else {
553
- throw new Error('Failed to load tasks via fallback method');
554
- }
555
- }
556
-
557
- } catch (error) {
558
- console.error('TaskMaster next task error:', error);
559
- res.status(500).json({
560
- error: 'Failed to get next task',
561
- message: error.message
562
- });
563
- }
564
- });
565
-
566
134
  /**
567
135
  * GET /api/taskmaster/tasks/:projectName
568
136
  * Load actual tasks from .taskmaster/tasks/tasks.json
@@ -904,66 +472,6 @@ router.get('/prd/:projectName/:fileName', async (req, res) => {
904
472
  }
905
473
  });
906
474
 
907
- /**
908
- * DELETE /api/taskmaster/prd/:projectName/:fileName
909
- * Delete a specific PRD file
910
- */
911
- router.delete('/prd/:projectName/:fileName', async (req, res) => {
912
- try {
913
- const { projectName, fileName } = req.params;
914
-
915
- // Get project path
916
- let projectPath;
917
- try {
918
- projectPath = await extractProjectDirectory(projectName);
919
- } catch (error) {
920
- return res.status(404).json({
921
- error: 'Project not found',
922
- message: `Project "${projectName}" does not exist`
923
- });
924
- }
925
-
926
- const filePath = path.join(projectPath, '.taskmaster', 'docs', fileName);
927
-
928
- // Check if file exists
929
- try {
930
- await fsPromises.access(filePath, fs.constants.F_OK);
931
- } catch (error) {
932
- return res.status(404).json({
933
- error: 'PRD file not found',
934
- message: `File "${fileName}" does not exist`
935
- });
936
- }
937
-
938
- // Delete the file
939
- try {
940
- await fsPromises.unlink(filePath);
941
-
942
- res.json({
943
- projectName,
944
- projectPath,
945
- fileName,
946
- message: 'PRD file deleted successfully',
947
- timestamp: new Date().toISOString()
948
- });
949
-
950
- } catch (deleteError) {
951
- console.error('Failed to delete PRD file:', deleteError);
952
- return res.status(500).json({
953
- error: 'Failed to delete PRD file',
954
- message: deleteError.message
955
- });
956
- }
957
-
958
- } catch (error) {
959
- console.error('PRD delete error:', error);
960
- res.status(500).json({
961
- error: 'Failed to delete PRD file',
962
- message: error.message
963
- });
964
- }
965
- });
966
-
967
475
  /**
968
476
  * POST /api/taskmaster/init/:projectName
969
477
  * Initialize TaskMaster in a project
@@ -0,0 +1,54 @@
1
+ import type {
2
+ FetchHistoryOptions,
3
+ FetchHistoryResult,
4
+ LLMProvider,
5
+ McpScope,
6
+ NormalizedMessage,
7
+ ProviderAuthStatus,
8
+ ProviderMcpServer,
9
+ UpsertProviderMcpServerInput,
10
+ } from '@/shared/types.js';
11
+
12
+ /**
13
+ * Main provider contract for CLI and SDK integrations.
14
+ *
15
+ * Each concrete provider owns its MCP/auth handlers plus the provider-specific
16
+ * logic for converting native events/history into the app's normalized shape.
17
+ */
18
+ export interface IProvider {
19
+ readonly id: LLMProvider;
20
+ readonly mcp: IProviderMcp;
21
+ readonly auth: IProviderAuth;
22
+ readonly sessions: IProviderSessions;
23
+ }
24
+
25
+
26
+ /**
27
+ * Auth contract for one provider.
28
+ */
29
+ export interface IProviderAuth {
30
+ /**
31
+ * Checks whether the provider is installed and has usable credentials.
32
+ */
33
+ getStatus(): Promise<ProviderAuthStatus>;
34
+ }
35
+
36
+ /**
37
+ * MCP contract for one provider.
38
+ */
39
+ export interface IProviderMcp {
40
+ listServers(options?: { workspacePath?: string }): Promise<Record<McpScope, ProviderMcpServer[]>>;
41
+ listServersForScope(scope: McpScope, options?: { workspacePath?: string }): Promise<ProviderMcpServer[]>;
42
+ upsertServer(input: UpsertProviderMcpServerInput): Promise<ProviderMcpServer>;
43
+ removeServer(
44
+ input: { name: string; scope?: McpScope; workspacePath?: string },
45
+ ): Promise<{ removed: boolean; provider: LLMProvider; name: string; scope: McpScope }>;
46
+ }
47
+
48
+ /**
49
+ * Session/history contract for one provider.
50
+ */
51
+ export interface IProviderSessions {
52
+ normalizeMessage(raw: unknown, sessionId: string | null): NormalizedMessage[];
53
+ fetchHistory(sessionId: string, options?: FetchHistoryOptions): Promise<FetchHistoryResult>;
54
+ }