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

159 lines 6.23 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || (function () { var ownKeys = function(o) { ownKeys = Object.getOwnPropertyNames || function (o) { var ar = []; for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; return ar; }; return ownKeys(o); }; return function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); __setModuleDefault(result, mod); return result; }; })(); Object.defineProperty(exports, "__esModule", { value: true }); exports.NgrokProvider = void 0; const ngrok = __importStar(require("@ngrok/ngrok")); const types_1 = require("./types"); const events_1 = require("events"); class NgrokTunnelInstance extends events_1.EventEmitter { constructor(_url, listener) { super(); this._url = _url; this.listener = listener; this.status = 'active'; this.createdAt = new Date(); this.provider = 'ngrok'; } get url() { return this._url; } async close() { if (this.status === 'closing') { return; } this.status = 'closing'; try { await this.listener.close(); this.status = 'closing'; } catch (error) { this.status = 'error'; throw error; } } async getHealth() { if (this.status !== 'active') { return { healthy: false, error: `Tunnel is ${this.status}` }; } return { healthy: true, latency: 0 }; } } class NgrokProvider { constructor(_config) { this._config = _config; this.name = 'ngrok'; // Config is used in validateConfig and createTunnel } async isAvailable() { try { // Check if we can import ngrok (it's already installed) const ngrokModule = await Promise.resolve().then(() => __importStar(require('@ngrok/ngrok'))); return !!ngrokModule; } catch { return false; } } async validateConfig() { const available = await this.isAvailable(); if (!available) { throw new types_1.TunnelProviderError(this.name, 'NGROK_NOT_FOUND', '@ngrok/ngrok package not found. Please install it: npm install @ngrok/ngrok'); } // Try to read auth token from ngrok config file if not provided if (!this._config?.authToken && !process.env.NGROK_AUTHTOKEN) { try { const os = await Promise.resolve().then(() => __importStar(require('os'))); const fs = await Promise.resolve().then(() => __importStar(require('fs/promises'))); const path = await Promise.resolve().then(() => __importStar(require('path'))); const configPath = path.join(os.homedir(), 'Library/Application Support/ngrok/ngrok.yml'); const configContent = await fs.readFile(configPath, 'utf8'); // Simple regex to extract authtoken const authTokenMatch = configContent.match(/authtoken:\s*([^\s]+)/); if (authTokenMatch && authTokenMatch[1]) { process.env.NGROK_AUTHTOKEN = authTokenMatch[1]; } } catch (error) { // Ignore error - ngrok might work without auth token console.log('Note: Running ngrok without auth token. Some features may be limited.'); } } } async createTunnel(port, _options) { await this.validateConfig(); try { // Configure ngrok with auth token if provided if (this._config?.authToken) { process.env.NGROK_AUTHTOKEN = this._config.authToken; } // Create tunnel using native ngrok library const listener = await ngrok.connect({ addr: port, authtoken: this._config?.authToken || process.env.NGROK_AUTHTOKEN, region: this._config?.region, // Set a custom metadata metadata: JSON.stringify({ name: 'claude-code-spec-workflow', readOnly: 'true' }) }); // Get the public URL const url = listener.url(); if (!url) { throw new types_1.TunnelProviderError(this.name, 'NGROK_NO_URL', 'Failed to get tunnel URL from ngrok'); } const instance = new NgrokTunnelInstance(url, listener); return instance; } catch (error) { if (error instanceof types_1.TunnelProviderError) { throw error; } throw new types_1.TunnelProviderError(this.name, 'NGROK_START_ERROR', `Failed to start ngrok: ${error instanceof Error ? error.message : String(error)}`, 'Could not start ngrok tunnel. This might be a configuration or authentication issue.', [ 'Check your ngrok auth token', 'Verify your internet connection', 'Check if you have reached your ngrok account limits' ]); } } } exports.NgrokProvider = NgrokProvider; //# sourceMappingURL=ngrok-provider-native.js.map