UNPKG

doclyft

Version:

CLI for DocLyft - Interactive documentation generator with hosted documentation support

449 lines (448 loc) â€ĸ 19.3 kB
"use strict"; /** * Interactive CLI session service * Provides an interactive session loop with slash commands */ 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; }; })(); var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.InteractiveSession = void 0; const prompts_1 = __importDefault(require("prompts")); const chalk_1 = __importDefault(require("chalk")); const auth_1 = __importStar(require("../middleware/auth")); const slash_command_handler_1 = require("./slash-command-handler"); const visual_1 = require("../utils/visual"); class InteractiveSession { constructor() { this.isRunning = false; this.commandHandler = new slash_command_handler_1.SlashCommandHandler(); this.sessionStartTime = new Date(); } /** * Start the interactive session */ async start(options = {}) { if (this.isRunning) { console.log(chalk_1.default.yellow('Session is already running.')); return; } this.isRunning = true; try { // Show welcome banner if (options.showWelcome !== false) { this.showWelcomeBanner(); } // Auto-login if needed and requested if (options.autoLogin) { await this.ensureAuthenticated(); } // Start the command loop await this.commandLoop(); } catch (error) { if (error instanceof Error && error.message === 'USER_EXIT') { // User intentionally exited - already handled in command loop } else { console.log('\n' + (0, visual_1.createBox)([ 'đŸ’Ĩ Session Error', '', error instanceof Error ? error.message : 'Unknown session error occurred', '', '🔧 What you can do:', ' â€ĸ Restart the interactive session', ' â€ĸ Check your network connection', ' â€ĸ Try individual commands instead' ], { title: '🚨 Critical Error', style: 'double', color: 'red', padding: 1, width: 70 })); } } finally { this.isRunning = false; } } /** * Stop the interactive session */ stop() { this.isRunning = false; } /** * Show welcome banner and session info */ showWelcomeBanner() { console.log('\n'); console.log((0, visual_1.createHeader)('🚀 DocLyft Interactive CLI', { style: 'banner', color: 'blue', width: 75 })); // Welcome message in a beautiful box console.log((0, visual_1.createBox)([ 'đŸŽ¯ Welcome to the enhanced DocLyft CLI experience!', '', '✨ Features:', ' â€ĸ Type "/" to discover all available commands', ' â€ĸ Smart command suggestions as you type', ' â€ĸ Beautiful visual feedback throughout', ' â€ĸ Enhanced error handling and guidance' ], { title: '💡 Getting Started', style: 'single', color: 'cyan', padding: 1, width: 75 })); // Check authentication status const authInfo = auth_1.default.getAuthInfo(); const authData = []; if (authInfo.token && authInfo.user_email) { authData.push({ key: '🔐 Status', value: (0, visual_1.createStatus)('success', 'Authenticated').replace('✅ ', '') }); authData.push({ key: '👤 Email', value: authInfo.user_email }); authData.push({ key: 'đŸŽ¯ Ready', value: 'All features available' }); } else { authData.push({ key: '🔐 Status', value: (0, visual_1.createStatus)('warning', 'Not authenticated').replace('âš ī¸ ', '') }); authData.push({ key: '🔑 Login', value: 'Type /login to authenticate' }); authData.push({ key: '🌐 API Key', value: 'Get yours at: https://doclyft.com/dashboard/api-keys' }); } console.log('\n' + (0, visual_1.createTable)(authData, { title: '🔐 Authentication Status', keyColor: 'blue', valueColor: 'white', separatorColor: 'gray' })); // Quick start commands const quickCommands = [ { name: '/help', description: 'Show comprehensive command help' }, { name: '/status', description: 'View detailed system status' }, { name: '/analyze repo', description: 'Analyze a GitHub repository' }, { name: '/generate readme', description: 'Generate professional README' }, { name: '/', description: 'Show all available commands' } ]; console.log('\n' + (0, visual_1.createCommandList)(quickCommands, { title: '⚡ Quick Start Commands', nameColor: 'green', descColor: 'gray' })); console.log('\n' + (0, visual_1.createDivider)('Ready to get started!', { color: 'cyan', char: '═', width: 75 })); console.log('\n'); } /** * Main command loop */ async commandLoop() { while (this.isRunning) { try { const response = await (0, prompts_1.default)({ type: 'text', name: 'command', message: chalk_1.default.cyan.bold('doclyft') + chalk_1.default.gray(' â€ē '), validate: (value) => { if (!value.trim()) { return chalk_1.default.yellow('💡 Please enter a command (try "/" to see all commands)'); } return true; }, format: (value) => value.trim() }); if (!response.command) { // User cancelled (Ctrl+C) console.log('\n' + (0, visual_1.createStatus)('info', 'Session interrupted. Goodbye! 👋')); throw new Error('USER_EXIT'); } const command = response.command.trim(); // Handle exit commands if (command === '/exit' || command === '/quit' || command === 'exit' || command === 'quit') { console.log('\n' + (0, visual_1.createStatus)('success', 'Thanks for using DocLyft CLI! 🚀')); throw new Error('USER_EXIT'); } // Show command list when user types just "/" or show suggestions for partial commands if (command === '/') { console.log(''); this.showAvailableCommands(); console.log(''); continue; // Don't process, just show commands and continue loop } else if (command.startsWith('/') && command.length > 1) { const suggestions = this.getSuggestions(command); if (suggestions.length > 0 && !suggestions.some(s => s.value === command)) { console.log(''); this.showFilteredCommands(command, suggestions); console.log(''); } } // Process the command await this.processCommand(command); // Add spacing between commands console.log(''); } catch (error) { if (error instanceof Error && error.message === 'USER_EXIT') { throw error; // Re-throw to exit the loop } // Enhanced error display console.log('\n' + (0, visual_1.createBox)([ '❌ Command Error', '', error instanceof Error ? error.message : 'Unknown error occurred', '', '💡 Suggestions:', ' â€ĸ Check command syntax', ' â€ĸ Type /help for available commands', ' â€ĸ Use / to see command suggestions' ], { title: 'âš ī¸ Error', style: 'single', color: 'red', padding: 1, width: 60 })); console.log(''); } } } /** * Get command suggestions for autocomplete */ getCommandSuggestions() { return [ { title: '/help', value: '/help', description: 'Show all available commands' }, { title: '/status', value: '/status', description: 'Show current status' }, { title: '/login', value: '/login', description: 'Authenticate with DocLyft' }, { title: '/logout', value: '/logout', description: 'Remove authentication' }, { title: '/analyze repo', value: '/analyze repo ', description: 'Analyze a GitHub repository' }, { title: '/analyze list', value: '/analyze list', description: 'List analyzed repositories' }, { title: '/analyze select', value: '/analyze select', description: 'Select a previous analysis' }, { title: '/generate readme', value: '/generate readme', description: 'Generate README file' }, { title: '/generate docs', value: '/generate docs', description: 'Generate full documentation' }, { title: '/push', value: '/push', description: 'Push documentation to GitHub' }, { title: '/repos', value: '/repos', description: 'List your GitHub repositories' }, { title: '/config list', value: '/config list', description: 'List configuration' }, { title: '/config set', value: '/config set ', description: 'Set configuration value' }, { title: '/config get', value: '/config get ', description: 'Get configuration value' }, { title: '/history', value: '/history', description: 'View activity history' }, { title: '/github-token', value: '/github-token', description: 'Set GitHub token' }, { title: '/test', value: '/test', description: 'Test GitHub connectivity' }, { title: '/analyses', value: '/analyses', description: 'View previous analyses' }, { title: '/exit', value: '/exit', description: 'Exit interactive session' } ]; } /** * Get command suggestions based on partial input */ getSuggestions(input) { const commands = this.getCommandSuggestions(); return commands.filter(cmd => cmd.value.toLowerCase().startsWith(input.toLowerCase())); } /** * Show all available commands in beautiful categorized display */ showAvailableCommands() { console.log((0, visual_1.createHeader)('📋 Available Commands', { style: 'decorated', color: 'blue', width: 70 })); const commands = this.getCommandSuggestions(); // Group commands by category with icons const categories = { '🔐 Authentication': commands.filter(cmd => ['/login', '/logout'].includes(cmd.value)), '🔍 Analysis': commands.filter(cmd => cmd.value.startsWith('/analyze')), '📝 Generation': commands.filter(cmd => cmd.value.startsWith('/generate')), '🔧 GitHub': commands.filter(cmd => ['/push', '/repos', '/github-token', '/test'].includes(cmd.value)), 'âš™ī¸ Configuration': commands.filter(cmd => cmd.value.startsWith('/config')), 'â„šī¸ Information': commands.filter(cmd => ['/help', '/status', '/history', '/analyses'].includes(cmd.value)), 'đŸšĒ Session': commands.filter(cmd => ['/exit'].includes(cmd.value)) }; const categoryEntries = Object.entries(categories).filter(([_, cmds]) => cmds.length > 0); categoryEntries.forEach(([category, cmds], categoryIndex) => { // Create command list for this category const categoryCommands = cmds.map(cmd => ({ name: cmd.value, description: cmd.description || '' })); console.log('\n' + (0, visual_1.createCommandList)(categoryCommands, { title: category, nameColor: 'cyan', descColor: 'gray' })); // Add spacing between categories (except for the last one) if (categoryIndex < categoryEntries.length - 1) { console.log(chalk_1.default.dim('\n' + '─'.repeat(50))); } }); // Usage tips in a nice box console.log('\n' + (0, visual_1.createBox)([ '💡 Usage Tips:', '', 'â€ĸ Type a command name and press Enter to execute', 'â€ĸ Start typing for smart suggestions (e.g., "/ana" shows analysis commands)', 'â€ĸ Use Tab or arrow keys for command history', 'â€ĸ Type "/exit" or press Ctrl+C to leave interactive mode' ], { title: 'đŸŽ¯ How to Use', style: 'single', color: 'yellow', padding: 1, width: 70 })); } /** * Show filtered commands based on user input with enhanced styling */ showFilteredCommands(input, suggestions) { if (suggestions.length === 0) { console.log((0, visual_1.createBox)([ `🔍 No commands found matching "${input}"`, '', '💡 Try:', ' â€ĸ Check your spelling', ' â€ĸ Type "/" to see all available commands', ' â€ĸ Use partial matching (e.g., "/gen" for generate)' ], { title: '❌ No Matches', style: 'single', color: 'yellow', padding: 1, width: 60 })); return; } // Create command suggestions const commandList = suggestions.map(cmd => ({ name: cmd.value, description: cmd.description || '' })); console.log((0, visual_1.createCommandList)(commandList, { title: `💡 Commands matching "${input}"`, nameColor: 'green', descColor: 'gray' })); // Show usage hint const hintMessage = suggestions.length === 1 ? '✨ Perfect match! Press Enter to execute this command' : `đŸŽ¯ Found ${suggestions.length} matches. Continue typing or select a command`; console.log('\n' + (0, visual_1.createStatus)('info', hintMessage)); } /** * Process a user command */ async processCommand(command) { // Normalize command - add slash if missing let normalizedCommand = command.trim(); if (!normalizedCommand.startsWith('/')) { normalizedCommand = '/' + normalizedCommand; } // Parse command and arguments const parts = normalizedCommand.slice(1).split(' '); // Remove '/' and split const commandName = parts[0].toLowerCase(); const args = parts.slice(1); try { // Route to appropriate handler await this.commandHandler.execute(commandName, args); } catch (error) { if (error instanceof auth_1.AuthError) { console.log('\n' + (0, visual_1.createBox)([ '🔐 Authentication Required', '', error.message, '', '🔑 To get started:', ' 1. Type /login to authenticate', ' 2. Get your API key from: https://doclyft.com/dashboard/api-keys', ' 3. Paste your key when prompted', '', '✨ Once authenticated, you\'ll have access to all features!' ], { title: 'âš ī¸ Access Required', style: 'single', color: 'yellow', padding: 1, width: 70 })); console.log(''); return; } throw error; // Re-throw other errors } } /** * Ensure user is authenticated */ async ensureAuthenticated() { try { await auth_1.default.requireAuth(); } catch (error) { if (error instanceof auth_1.AuthError) { console.log('\n' + (0, visual_1.createBox)([ '🔐 Authentication Available', '', 'Some features require authentication for full functionality.', '', '🎆 When you\'re ready:', ' â€ĸ Type /login to unlock all features', ' â€ĸ Visit https://doclyft.com/dashboard/api-keys for your API key', '', 'You can still use basic commands without authentication!' ], { title: '💡 Pro Tip', style: 'single', color: 'blue', padding: 1, width: 70 })); console.log(''); } } } /** * Get session statistics */ getSessionStats() { return { startTime: this.sessionStartTime, duration: Date.now() - this.sessionStartTime.getTime(), isRunning: this.isRunning }; } } exports.InteractiveSession = InteractiveSession; exports.default = InteractiveSession;