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
237 lines • 8.36 kB
JavaScript
export class TidewaveIntegration {
capabilities = new Map();
/**
* Detect if a URL has Tidewave enabled and what capabilities it has
*/
async detectTidewave(url) {
try {
// Try Phoenix endpoint first
const phoenixEndpoint = `${url}/tidewave/mcp`;
let response = await this.testEndpoint(phoenixEndpoint);
if (response) {
const capabilities = {
framework: 'phoenix',
endpoint: phoenixEndpoint,
available_tools: response.tools || [],
version: response.version
};
this.capabilities.set(url, capabilities);
return capabilities;
}
// Try Rails endpoint
const railsEndpoint = `${url}/tidewave`;
response = await this.testEndpoint(railsEndpoint);
if (response) {
const capabilities = {
framework: 'rails',
endpoint: railsEndpoint,
available_tools: response.tools || [],
version: response.version
};
this.capabilities.set(url, capabilities);
return capabilities;
}
return null;
}
catch (error) {
// console.error('Tidewave detection failed:', error);
return null;
}
}
/**
* Test if a Tidewave endpoint is accessible
*/
async testEndpoint(endpoint) {
const { AbortSignalManager } = await import('./utils/abort-signal-manager.js');
try {
// Use centralized AbortSignalManager to prevent EventTarget memory leaks
const { controller, timeoutId } = AbortSignalManager.createWithTimeout(5000);
const response = await fetch(`${endpoint}/capabilities`, {
method: 'GET',
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json'
},
signal: controller.signal
});
clearTimeout(timeoutId);
if (response.ok) {
return await response.json();
}
return null;
}
catch {
return null;
}
}
/**
* Execute a Tidewave tool for enhanced debugging/testing
*/
async executeTool(url, request) {
const capabilities = this.capabilities.get(url);
if (!capabilities) {
return {
success: false,
error: 'Tidewave not available for this URL'
};
}
if (!capabilities.available_tools.includes(request.tool)) {
return {
success: false,
error: `Tool '${request.tool}' not available. Available: ${capabilities.available_tools.join(', ')}`
};
}
try {
const { AbortSignalManager } = await import('./utils/abort-signal-manager.js');
// Use centralized AbortSignalManager to prevent EventTarget memory leaks
const { controller, timeoutId } = AbortSignalManager.createWithTimeout(30000);
const response = await fetch(`${capabilities.endpoint}/${request.tool}`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json'
},
body: JSON.stringify(request.params || {}),
signal: controller.signal
});
clearTimeout(timeoutId);
const data = await response.json();
return {
success: response.ok,
data: response.ok ? data : undefined,
error: response.ok ? undefined : data.error || `HTTP ${response.status}`,
metadata: {
execution_time: data.execution_time,
framework_version: capabilities.version
}
};
}
catch (error) {
return {
success: false,
error: `Tidewave execution failed: ${error instanceof Error ? error.message : String(error)}`
};
}
}
/**
* Get application logs through Tidewave
*/
async getLogs(url, options = {}) {
return this.executeTool(url, {
tool: 'logs',
params: options
});
}
/**
* Execute custom code for testing/debugging
*/
async evaluateCode(url, code, context) {
return this.executeTool(url, {
tool: 'eval',
params: { code, context }
});
}
/**
* Get application documentation
*/
async getDocumentation(url, path) {
return this.executeTool(url, {
tool: 'documentation',
params: { path }
});
}
/**
* Execute SQL queries for database testing
*/
async executeSQL(url, query, params) {
return this.executeTool(url, {
tool: 'sql',
params: { query, params }
});
}
/**
* Trace application processes
*/
async traceProcesses(url, pattern) {
return this.executeTool(url, {
tool: 'processes',
params: { pattern }
});
}
/**
* Search project dependencies
*/
async searchDependencies(url, query) {
return this.executeTool(url, {
tool: 'dependencies',
params: { query }
});
}
/**
* Enhanced debugging state with Tidewave data
*/
async enhanceDebugState(url, debugState) {
const capabilities = this.capabilities.get(url);
if (!capabilities) {
return debugState;
}
// Add Tidewave-specific information to debug state
const tidewaveData = {
framework: capabilities.framework,
available_tools: capabilities.available_tools,
version: capabilities.version
};
// Get logs if available
if (capabilities.available_tools.includes('logs')) {
const logs = await this.getLogs(url, { limit: 50 });
if (logs.success) {
tidewaveData.recent_logs = logs.data;
}
}
// Get process information if available
if (capabilities.available_tools.includes('processes')) {
const processes = await this.traceProcesses(url);
if (processes.success) {
tidewaveData.processes = processes.data;
}
}
return {
...debugState,
tidewave: tidewaveData
};
}
/**
* Generate test assertions using Tidewave application knowledge
*/
async generateTestAssertions(url, scenario) {
const capabilities = this.capabilities.get(url);
if (!capabilities) {
return [];
}
const framework = capabilities.framework;
const assertions = [];
// Framework-specific test generation
if (framework === 'phoenix') {
assertions.push(`# Phoenix LiveView test assertions for: ${scenario}`);
assertions.push('assert has_element?(view, "[data-testid=\\"#{scenario}\\"]")');
assertions.push('refute has_element?(view, ".error")');
}
else if (framework === 'rails') {
assertions.push(`# Rails system test assertions for: ${scenario}`);
assertions.push(`expect(page).to have_content("${scenario}")`);
assertions.push('expect(page).not_to have_css(".error")');
}
// Use Tidewave documentation to enhance assertions
if (capabilities.available_tools.includes('documentation')) {
const docs = await this.getDocumentation(url, scenario);
if (docs.success && docs.data) {
// Parse documentation to generate more specific assertions
assertions.push(`# Generated from application documentation`);
// Add doc-based assertions here
}
}
return assertions;
}
}
export const tidewave = new TidewaveIntegration();
//# sourceMappingURL=tidewave-integration.js.map