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
JavaScript
/**
* 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