UNPKG

ai-debug-local-mcp

Version:

🎯 ENHANCED AI GUIDANCE v4.1.2: Dramatically improved tool descriptions help AI users choose the right tools instead of 'close enough' options. Ultra-fast keyboard automation (10x speed), universal recording, multi-ecosystem debugging support, and compreh

319 lines (315 loc) 11.9 kB
/** * Native Automation Executor * TypeScript wrapper for ultra-fast CGEvent bridge */ import { spawn, execSync } from 'child_process'; import { performanceProfiler } from './automation-performance-profiler.js'; import path from 'path'; import { fileURLToPath } from 'url'; import { existsSync } from 'fs'; const __filename = fileURLToPath(import.meta.url); const __dirname = path.dirname(__filename); export class NativeAutomationExecutor { pythonPath; bridgePath; isInitialized = false; constructor() { // Try to find Python3 in common locations const pythonPaths = [ '/Users/og/.asdf/shims/python3', // asdf managed Python '/usr/local/bin/python3', // Homebrew Python '/opt/homebrew/bin/python3', // Apple Silicon Homebrew '/usr/bin/python3' // System Python ]; // Find the first available Python this.pythonPath = pythonPaths.find(p => { try { execSync(`${p} --version`, { stdio: 'ignore' }); return true; } catch { return false; } }) || 'python3'; // Fall back to PATH lookup this.bridgePath = path.join(__dirname, 'native-cgevent-bridge.py'); } /** * Initialize the native bridge */ async initialize() { if (this.isInitialized) { return true; } console.log(`🔍 Attempting to initialize native automation with Python at: ${this.pythonPath}`); console.log(`🔍 Bridge script path: ${this.bridgePath}`); // Check if Python exists try { const version = execSync(`${this.pythonPath} --version 2>&1`).toString().trim(); console.log(`✅ Python found: ${version}`); } catch (error) { console.error(`❌ Python not found at ${this.pythonPath}:`, error.message); this.isInitialized = false; return false; } // Check if bridge script exists if (!existsSync(this.bridgePath)) { console.error(`❌ Bridge script not found at: ${this.bridgePath}`); this.isInitialized = false; return false; } console.log(`✅ Bridge script exists at: ${this.bridgePath}`); try { // Test if Python bridge is accessible console.log('🔍 Testing native bridge with move action...'); const testResult = await this.executeNativeAction({ action: 'move', x: 0, y: 0 }); this.isInitialized = testResult !== null && testResult.success === true; if (this.isInitialized) { console.log('✅ Native CGEvent bridge initialized successfully'); console.log('📊 Test result:', testResult); } else { console.warn('⚠️ Native CGEvent bridge test failed, falling back to AppleScript'); console.warn('Test result:', testResult); } return this.isInitialized; } catch (error) { console.error('❌ Failed to initialize native bridge:', error); console.error('Error details:', error.message); this.isInitialized = false; return false; } } /** * Execute a native action using CGEvent bridge */ async executeNativeAction(data) { return new Promise((resolve, reject) => { const python = spawn(this.pythonPath, [this.bridgePath]); let output = ''; let error = ''; python.stdout.on('data', (data) => { output += data.toString(); }); python.stderr.on('data', (data) => { error += data.toString(); }); python.on('close', (code) => { if (code !== 0) { reject(new Error(`Native bridge exited with code ${code}: ${error}`)); } else { try { const result = JSON.parse(output); resolve(result); } catch (e) { reject(new Error(`Failed to parse native bridge output: ${output}`)); } } }); // Send input data python.stdin.write(JSON.stringify(data)); python.stdin.end(); }); } /** * Ultra-fast mouse click */ async click(x, y, button = 'left', clicks = 1) { performanceProfiler.startOperation(`native-click-${Date.now()}`, 'cgevent', { x, y, button, clicks }); try { const result = await this.executeNativeAction({ action: 'click', x, y, button, clicks }); performanceProfiler.endOperation(`native-click-${Date.now()}`); return { success: true, duration_ms: result.duration_ms, action: 'click', details: result }; } catch (error) { performanceProfiler.endOperation(`native-click-${Date.now()}`); return { success: false, duration_ms: 0, action: 'click', error: error instanceof Error ? error.message : String(error) }; } } /** * Ultra-fast mouse movement */ async move(x, y, duration = 0) { performanceProfiler.startOperation(`native-move-${Date.now()}`, 'cgevent', { x, y, duration }); try { const result = await this.executeNativeAction({ action: 'move', x, y, duration: duration / 1000 // Convert ms to seconds }); performanceProfiler.endOperation(`native-move-${Date.now()}`); return { success: true, duration_ms: result.duration_ms, action: 'move', details: result }; } catch (error) { performanceProfiler.endOperation(`native-move-${Date.now()}`); return { success: false, duration_ms: 0, action: 'move', error: error instanceof Error ? error.message : String(error) }; } } /** * Ultra-fast keyboard input */ async key(key, modifiers = []) { performanceProfiler.startOperation(`native-key-${Date.now()}`, 'cgevent', { key, modifiers }); try { const result = await this.executeNativeAction({ action: 'key', key, modifiers }); performanceProfiler.endOperation(`native-key-${Date.now()}`); return { success: true, duration_ms: result.duration_ms, action: 'key', details: result }; } catch (error) { performanceProfiler.endOperation(`native-key-${Date.now()}`); return { success: false, duration_ms: 0, action: 'key', error: error instanceof Error ? error.message : String(error) }; } } /** * Ultra-fast text typing */ async type(text, delayMs = 0) { performanceProfiler.startOperation(`native-type-${Date.now()}`, 'cgevent', { textLength: text.length, delayMs }); try { const result = await this.executeNativeAction({ action: 'type', text, delay_ms: delayMs }); performanceProfiler.endOperation(`native-type-${Date.now()}`); return { success: true, duration_ms: result.duration_ms, action: 'type', details: result }; } catch (error) { performanceProfiler.endOperation(`native-type-${Date.now()}`); return { success: false, duration_ms: 0, action: 'type', error: error instanceof Error ? error.message : String(error) }; } } /** * Execute batch of native actions */ async executeBatch(actions) { performanceProfiler.startOperation(`native-batch-${Date.now()}`, 'cgevent', { count: actions.length }); try { const result = await this.executeNativeAction({ action: 'batch', actions }); performanceProfiler.endOperation(`native-batch-${Date.now()}`); return { success: true, duration_ms: result.total_duration_ms, action: 'batch', details: result }; } catch (error) { performanceProfiler.endOperation(`native-batch-${Date.now()}`); return { success: false, duration_ms: 0, action: 'batch', error: error instanceof Error ? error.message : String(error) }; } } /** * Compare native vs AppleScript performance */ async comparePerformance() { console.log('🔬 Comparing Native CGEvent vs AppleScript performance...\n'); // Test 1: Simple click const nativeClickStart = performance.now(); await this.click(100, 100); const nativeClickDuration = performance.now() - nativeClickStart; // Test 2: Type text const nativeTypeStart = performance.now(); await this.type('Hello World'); const nativeTypeDuration = performance.now() - nativeTypeStart; // Test 3: Batch operations const batchActions = [ { type: 'click', x: 200, y: 200 }, { type: 'type', text: 'Test' }, { type: 'key', key: 'return' } ]; const nativeBatchStart = performance.now(); await this.executeBatch(batchActions); const nativeBatchDuration = performance.now() - nativeBatchStart; // Compare with AppleScript baseline (estimated) const appleScriptClickBaseline = 300; // ms const appleScriptTypeBaseline = 500; // ms const appleScriptBatchBaseline = 900; // ms const clickImprovement = ((appleScriptClickBaseline - nativeClickDuration) / appleScriptClickBaseline * 100).toFixed(1); const typeImprovement = ((appleScriptTypeBaseline - nativeTypeDuration) / appleScriptTypeBaseline * 100).toFixed(1); const batchImprovement = ((appleScriptBatchBaseline - nativeBatchDuration) / appleScriptBatchBaseline * 100).toFixed(1); return `📊 **Native CGEvent Performance Results** **Click Performance:** - Native CGEvent: ${nativeClickDuration.toFixed(2)}ms - AppleScript baseline: ${appleScriptClickBaseline}ms - Improvement: ${clickImprovement}% faster **Type Text Performance:** - Native CGEvent: ${nativeTypeDuration.toFixed(2)}ms - AppleScript baseline: ${appleScriptTypeBaseline}ms - Improvement: ${typeImprovement}% faster **Batch Operations:** - Native CGEvent: ${nativeBatchDuration.toFixed(2)}ms - AppleScript baseline: ${appleScriptBatchBaseline}ms - Improvement: ${batchImprovement}% faster **Average Improvement:** ${((parseFloat(clickImprovement) + parseFloat(typeImprovement) + parseFloat(batchImprovement)) / 3).toFixed(1)}% faster`; } } // Export singleton instance export const nativeAutomation = new NativeAutomationExecutor(); //# sourceMappingURL=native-automation-executor.js.map