UNPKG

task-engine-ai-core

Version:

Revolutionary AI-driven task management system with complete transformation trilogy: Frontend v0.1.0, Backend v0.2.0, CLI v0.3.0 - Enterprise-grade performance with 95% improvements

319 lines (285 loc) 11.7 kB
/** * IDE Detection Utilities * Provides utilities for detecting and connecting to various IDEs */ import fs from 'fs/promises'; import path from 'path'; import os from 'os'; import { spawn } from 'child_process'; import logger from '../../mcp-server/src/logger.js'; export class IDEDetection { constructor() { this.detectionCache = new Map(); this.cacheTimeout = 30000; // 30 seconds } /** * Auto-detect available IDEs */ async detectAvailableIDEs() { const cacheKey = 'available_ides'; const cached = this.detectionCache.get(cacheKey); if (cached && Date.now() - cached.timestamp < this.cacheTimeout) { return cached.data; } const detectionResults = { cursor: await this.detectCursor(), vscode: await this.detectVSCode(), windsurf: await this.detectWindsurf() }; // Cache results this.detectionCache.set(cacheKey, { data: detectionResults, timestamp: Date.now() }); return detectionResults; } /** * Detect Cursor IDE */ async detectCursor() { try { const homeDir = os.homedir(); const possiblePaths = [ path.join(homeDir, '.cursor'), path.join(homeDir, 'Library', 'Application Support', 'Cursor'), // macOS path.join(homeDir, 'AppData', 'Roaming', 'Cursor'), // Windows path.join(homeDir, '.config', 'cursor') // Linux ]; for (const cursorPath of possiblePaths) { try { const stats = await fs.stat(cursorPath); if (stats.isDirectory()) { // Check for config file const configPath = path.join(cursorPath, 'config.json'); try { await fs.access(configPath); const config = JSON.parse(await fs.readFile(configPath, 'utf8')); return { detected: true, path: cursorPath, configPath, config, version: config.version || 'unknown', apiPort: config.apiPort || 42000, confidence: 0.9 }; } catch (configError) { // Directory exists but no config - still likely Cursor return { detected: true, path: cursorPath, configPath: null, config: null, version: 'unknown', apiPort: 42000, confidence: 0.7 }; } } } catch (error) { continue; } } // Try to detect running Cursor process const runningCursor = await this.detectRunningProcess('cursor'); if (runningCursor) { return { detected: true, path: null, configPath: null, config: null, version: 'unknown', apiPort: 42000, confidence: 0.6, processInfo: runningCursor }; } return { detected: false, confidence: 0 }; } catch (error) { logger.debug('Error detecting Cursor:', error); return { detected: false, confidence: 0, error: error.message }; } } /** * Detect VS Code */ async detectVSCode() { try { const homeDir = os.homedir(); const possiblePaths = [ path.join(homeDir, '.vscode'), path.join(homeDir, 'Library', 'Application Support', 'Code'), // macOS path.join(homeDir, 'AppData', 'Roaming', 'Code'), // Windows path.join(homeDir, '.config', 'Code') // Linux ]; for (const vscodePath of possiblePaths) { try { const stats = await fs.stat(vscodePath); if (stats.isDirectory()) { // Check for extensions directory const extensionsPath = path.join(vscodePath, 'extensions'); try { const extensions = await fs.readdir(extensionsPath); const aiExtensions = extensions.filter(ext => ext.includes('github.copilot') || ext.includes('ms-vscode.vscode-ai') || ext.includes('continue.continue') ); return { detected: true, path: vscodePath, extensionsPath, aiExtensions, confidence: aiExtensions.length > 0 ? 0.9 : 0.6 }; } catch (extError) { return { detected: true, path: vscodePath, extensionsPath: null, aiExtensions: [], confidence: 0.5 }; } } } catch (error) { continue; } } // Try to detect running VS Code process const runningVSCode = await this.detectRunningProcess('code'); if (runningVSCode) { return { detected: true, path: null, extensionsPath: null, aiExtensions: [], confidence: 0.4, processInfo: runningVSCode }; } return { detected: false, confidence: 0 }; } catch (error) { logger.debug('Error detecting VS Code:', error); return { detected: false, confidence: 0, error: error.message }; } } /** * Detect Windsurf IDE */ async detectWindsurf() { try { const homeDir = os.homedir(); const possiblePaths = [ path.join(homeDir, '.windsurf'), path.join(homeDir, 'Library', 'Application Support', 'Windsurf'), // macOS path.join(homeDir, 'AppData', 'Roaming', 'Windsurf'), // Windows path.join(homeDir, '.config', 'windsurf') // Linux ]; for (const windsurfPath of possiblePaths) { try { const stats = await fs.stat(windsurfPath); if (stats.isDirectory()) { // Check for config file const configPath = path.join(windsurfPath, 'config.json'); try { await fs.access(configPath); const config = JSON.parse(await fs.readFile(configPath, 'utf8')); return { detected: true, path: windsurfPath, configPath, config, version: config.version || 'unknown', cascadePort: config.cascadePort || 43000, confidence: 0.9 }; } catch (configError) { return { detected: true, path: windsurfPath, configPath: null, config: null, version: 'unknown', cascadePort: 43000, confidence: 0.7 }; } } } catch (error) { continue; } } // Try to detect running Windsurf process const runningWindsurf = await this.detectRunningProcess('windsurf'); if (runningWindsurf) { return { detected: true, path: null, configPath: null, config: null, version: 'unknown', cascadePort: 43000, confidence: 0.6, processInfo: runningWindsurf }; } return { detected: false, confidence: 0 }; } catch (error) { logger.debug('Error detecting Windsurf:', error); return { detected: false, confidence: 0, error: error.message }; } } /** * Detect running process by name */ async detectRunningProcess(processName) { return new Promise((resolve) => { const isWindows = process.platform === 'win32'; const command = isWindows ? 'tasklist' : 'ps'; const args = isWindows ? ['/FI', `IMAGENAME eq ${processName}*`] : ['aux']; const proc = spawn(command, args, { stdio: 'pipe' }); let output = ''; proc.stdout.on('data', (data) => { output += data.toString(); }); proc.on('close', (code) => { if (code === 0 && output.toLowerCase().includes(processName.toLowerCase())) { resolve({ found: true, processName, output: output.split('\n').filter(line => line.toLowerCase().includes(processName.toLowerCase()) ) }); } else { resolve(null); } }); proc.on('error', () => { resolve(null); }); // Timeout after 5 seconds setTimeout(() => { proc.kill(); resolve(null); }, 5000); }); } /** * Get the best IDE candidate */ async getBestIDE() { const ides = await this.detectAvailableIDEs(); // Sort by confidence score const candidates = Object.entries(ides) .filter(([_, info]) => info.detected) .sort(([_, a], [__, b]) => b.confidence - a.confidence); if (candidates.length === 0) { return { type: null, info: null }; } const [type, info] = candidates[0]; return { type, info }; } } export default IDEDetection;