UNPKG

@pimzino/claude-code-spec-workflow

Version:

Automated workflows for Claude Code. Includes spec-driven development (Requirements → Design → Tasks → Implementation) with intelligent task execution, optional steering documents and streamlined bug fix workflow (Report → Analyze → Fix → Verify). We have

166 lines 7.95 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.TunnelErrorHandler = void 0; const types_1 = require("./types"); const logger_1 = require("../logger"); class TunnelErrorHandler { constructor() { this.recoveryStrategies = []; // Register default recovery strategies this.registerStrategy(new ProviderFailoverStrategy()); this.registerStrategy(new ConfigurationErrorStrategy()); this.registerStrategy(new NetworkErrorStrategy()); } registerStrategy(strategy) { this.recoveryStrategies.push(strategy); } async handleError(error) { (0, logger_1.debug)(`Handling tunnel error: ${error.code}`, error); // Try recovery strategies for (const strategy of this.recoveryStrategies) { if (strategy.canRecover(error)) { try { await strategy.recover(error); (0, logger_1.debug)(`Successfully recovered from error using ${strategy.constructor.name}`); return error; // Recovery successful } catch (recoveryError) { (0, logger_1.debug)(`Recovery strategy ${strategy.constructor.name} failed:`, recoveryError); } } } // If no recovery worked, enhance the error with user-friendly messages return this.enhanceErrorMessage(error); } enhanceErrorMessage(error) { const enhancements = this.getErrorEnhancements(error); return new types_1.TunnelProviderError(error.provider, error.code, error.message, enhancements.userMessage, enhancements.troubleshooting); } getErrorEnhancements(error) { const errorMappings = { 'NO_AVAILABLE_PROVIDERS': { userMessage: 'No tunnel providers are available. Please install at least one tunnel provider.', troubleshooting: [ 'Install Cloudflare tunnel: https://developers.cloudflare.com/cloudflare-one/connections/connect-apps/install-and-setup/installation/', 'Install ngrok: https://ngrok.com/download or run "npm install ngrok"', 'Check that the installed provider binaries are in your PATH', 'Restart your terminal after installation' ] }, 'CLOUDFLARED_NOT_FOUND': { userMessage: 'Cloudflare tunnel (cloudflared) is not installed or not found in PATH.', troubleshooting: [ 'Download cloudflared from: https://developers.cloudflare.com/cloudflare-one/connections/connect-apps/install-and-setup/installation/', 'Make sure cloudflared is in your PATH environment variable', 'Try running "cloudflared --version" to verify installation', 'On macOS, you can install with: brew install cloudflared' ] }, 'NGROK_NOT_FOUND': { userMessage: 'ngrok is not installed or not found.', troubleshooting: [ 'Download ngrok from: https://ngrok.com/download', 'Install via npm: npm install -g ngrok', 'Make sure ngrok is in your PATH environment variable', 'Try running "ngrok --version" to verify installation' ] }, 'NGROK_AUTH_REQUIRED': { userMessage: 'ngrok requires authentication. Please configure an auth token.', troubleshooting: [ 'Sign up for a free ngrok account at: https://ngrok.com/signup', 'Get your auth token from: https://dashboard.ngrok.com/get-started/your-authtoken', 'Set the auth token: ngrok config add-authtoken YOUR_TOKEN', 'Or set the NGROK_AUTHTOKEN environment variable' ] }, 'CLOUDFLARED_TIMEOUT': { userMessage: 'Cloudflare tunnel took too long to start. This might be a network or configuration issue.', troubleshooting: [ 'Check your internet connection', 'Verify that port is not already in use', 'Try running cloudflared manually: cloudflared tunnel --url http://localhost:3000', 'Check firewall settings - cloudflared needs outbound HTTPS access' ] }, 'NGROK_TIMEOUT': { userMessage: 'ngrok tunnel took too long to start. This might be a network or configuration issue.', troubleshooting: [ 'Check your internet connection', 'Verify your ngrok auth token is valid', 'Try running ngrok manually: ngrok http 3000', 'Check if you have reached your ngrok account limits' ] }, 'PROVIDER_FAILURES': { userMessage: 'All tunnel providers failed to create a tunnel. Please check your configuration and network connection.', troubleshooting: [ 'Check your internet connection', 'Verify that your firewall allows outbound connections', 'Try creating tunnels manually to test provider configurations', 'Check provider-specific documentation for troubleshooting' ] } }; const enhancement = errorMappings[error.code]; if (enhancement) { return enhancement; } // Default enhancement for unknown errors return { userMessage: `Tunnel error: ${error.message}`, troubleshooting: [ 'Check your internet connection', 'Verify tunnel provider is properly installed', 'Try restarting the tunnel', 'Check provider documentation for specific error details' ] }; } } exports.TunnelErrorHandler = TunnelErrorHandler; class ProviderFailoverStrategy { canRecover(error) { // Can recover from single provider failures if other providers might be available return error.code !== 'NO_AVAILABLE_PROVIDERS' && error.provider !== 'all'; } async recover(_error) { (0, logger_1.debug)(`Attempting provider failover from ${_error.provider}`); // The actual failover logic is handled by TunnelManager's provider iteration // This strategy just indicates that failover should be attempted } } class ConfigurationErrorStrategy { canRecover(error) { const recoverableCodes = [ 'CLOUDFLARED_NOT_FOUND', 'NGROK_NOT_FOUND', 'NGROK_AUTH_REQUIRED' ]; return recoverableCodes.includes(error.code); } async recover(error) { (0, logger_1.debug)(`Configuration error detected: ${error.code}`); // Configuration errors typically require manual intervention // We enhance the error message instead of automatic recovery throw new Error('Configuration errors require manual intervention'); } } class NetworkErrorStrategy { canRecover(error) { const networkErrorCodes = [ 'CLOUDFLARED_TIMEOUT', 'NGROK_TIMEOUT', 'TUNNEL_CONNECTION_FAILED' ]; return networkErrorCodes.includes(error.code); } async recover(error) { (0, logger_1.debug)(`Network error detected: ${error.code}, implementing retry with backoff`); // Implement exponential backoff for network errors const delay = Math.min(1000 * Math.pow(2, 0), 5000); // Start with 1s, max 5s await new Promise(resolve => setTimeout(resolve, delay)); // The actual retry logic is handled by the caller } } //# sourceMappingURL=error-handler.js.map