UNPKG

mcp-quiz-server

Version:

🧠 AI-Powered Quiz Management via Model Context Protocol (MCP) - Create, manage, and take quizzes directly from VS Code, Claude, and other AI agents.

413 lines (412 loc) • 21.3 kB
"use strict"; /** * ASCII Animations and Graphics for MCP Quiz Server Setup * Uses only built-in Node.js modules for maximum compatibility */ Object.defineProperty(exports, "__esModule", { value: true }); exports.AsciiAnimations = void 0; const timers_1 = require("timers"); const process_1 = require("process"); class AsciiAnimations { /** * Clear all running animations */ static clearAllAnimations() { this.activeAnimations.forEach(timer => (0, timers_1.clearTimeout)(timer)); this.activeAnimations.clear(); } /** * Apply color to text if color support is enabled */ static colorize(text, color, useColor = true) { if (!useColor) return text; return `${color}${text}${this.COLORS.reset}`; } /** * Move cursor and clear line */ static moveCursor(x, y) { process_1.stdout.write(`\x1b[${y};${x}H`); } static clearLine() { process_1.stdout.write('\x1b[2K'); } static hideCursor() { process_1.stdout.write('\x1b[?25l'); } static showCursor() { process_1.stdout.write('\x1b[?25h'); } /** * Welcome banner with ASCII art */ static displayWelcomeBanner(useColor = true) { const banner = ` ╔═══════════════════════════════════════════════════════════════════════════════╗ ā•‘ ā•‘ ā•‘ ā–ˆā–ˆā–ˆā•— ā–ˆā–ˆā–ˆā•— ā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā•—ā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā•— ā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā•— ā–ˆā–ˆā•— ā–ˆā–ˆā•—ā–ˆā–ˆā•—ā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā•— ā•‘ ā•‘ ā–ˆā–ˆā–ˆā–ˆā•— ā–ˆā–ˆā–ˆā–ˆā•‘ā–ˆā–ˆā•”ā•ā•ā•ā•ā•ā–ˆā–ˆā•”ā•ā•ā–ˆā–ˆā•— ā–ˆā–ˆā•”ā•ā•ā•ā–ˆā–ˆā•—ā–ˆā–ˆā•‘ ā–ˆā–ˆā•‘ā–ˆā–ˆā•‘ā•šā•ā•ā–ˆā–ˆā–ˆā•”ā• ā•‘ ā•‘ ā–ˆā–ˆā•”ā–ˆā–ˆā–ˆā–ˆā•”ā–ˆā–ˆā•‘ā–ˆā–ˆā•‘ ā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā•”ā• ā–ˆā–ˆā•‘ ā–ˆā–ˆā•‘ā–ˆā–ˆā•‘ ā–ˆā–ˆā•‘ā–ˆā–ˆā•‘ ā–ˆā–ˆā–ˆā•”ā• ā•‘ ā•‘ ā–ˆā–ˆā•‘ā•šā–ˆā–ˆā•”ā•ā–ˆā–ˆā•‘ā–ˆā–ˆā•‘ ā–ˆā–ˆā•”ā•ā•ā•ā• ā–ˆā–ˆā•‘ā–„ā–„ ā–ˆā–ˆā•‘ā–ˆā–ˆā•‘ ā–ˆā–ˆā•‘ā–ˆā–ˆā•‘ ā–ˆā–ˆā–ˆā•”ā• ā•‘ ā•‘ ā–ˆā–ˆā•‘ ā•šā•ā• ā–ˆā–ˆā•‘ā•šā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā•—ā–ˆā–ˆā•‘ ā•šā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā•”ā•ā•šā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā•”ā•ā–ˆā–ˆā•‘ā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā•— ā•‘ ā•‘ ā•šā•ā• ā•šā•ā• ā•šā•ā•ā•ā•ā•ā•ā•šā•ā• ā•šā•ā•ā–€ā–€ā•ā• ā•šā•ā•ā•ā•ā•ā• ā•šā•ā•ā•šā•ā•ā•ā•ā•ā•ā• ā•‘ ā•‘ ā•‘ ā•‘ ā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā•—ā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā•—ā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā•— ā–ˆā–ˆā•— ā–ˆā–ˆā•—ā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā•—ā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā•— ā•‘ ā•‘ ā–ˆā–ˆā•”ā•ā•ā•ā•ā•ā–ˆā–ˆā•”ā•ā•ā•ā•ā•ā–ˆā–ˆā•”ā•ā•ā–ˆā–ˆā•—ā–ˆā–ˆā•‘ ā–ˆā–ˆā•‘ā–ˆā–ˆā•”ā•ā•ā•ā•ā•ā–ˆā–ˆā•”ā•ā•ā–ˆā–ˆā•— ā•‘ ā•‘ ā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā•—ā–ˆā–ˆā–ˆā–ˆā–ˆā•— ā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā•”ā•ā–ˆā–ˆā•‘ ā–ˆā–ˆā•‘ā–ˆā–ˆā–ˆā–ˆā–ˆā•— ā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā•”ā• ā•‘ ā•‘ ā•šā•ā•ā•ā•ā–ˆā–ˆā•‘ā–ˆā–ˆā•”ā•ā•ā• ā–ˆā–ˆā•”ā•ā•ā–ˆā–ˆā•—ā•šā–ˆā–ˆā•— ā–ˆā–ˆā•”ā•ā–ˆā–ˆā•”ā•ā•ā• ā–ˆā–ˆā•”ā•ā•ā–ˆā–ˆā•— ā•‘ ā•‘ ā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā•‘ā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā•—ā–ˆā–ˆā•‘ ā–ˆā–ˆā•‘ ā•šā–ˆā–ˆā–ˆā–ˆā•”ā• ā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā•—ā–ˆā–ˆā•‘ ā–ˆā–ˆā•‘ ā•‘ ā•‘ ā•šā•ā•ā•ā•ā•ā•ā•ā•šā•ā•ā•ā•ā•ā•ā•ā•šā•ā• ā•šā•ā• ā•šā•ā•ā•ā• ā•šā•ā•ā•ā•ā•ā•ā•ā•šā•ā• ā•šā•ā• ā•‘ ā•‘ ā•‘ ā•‘ ā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā•—ā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā•—ā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā•—ā–ˆā–ˆā•— ā–ˆā–ˆā•—ā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā•— ā•‘ ā•‘ ā–ˆā–ˆā•”ā•ā•ā•ā•ā•ā–ˆā–ˆā•”ā•ā•ā•ā•ā•ā•šā•ā•ā–ˆā–ˆā•”ā•ā•ā•ā–ˆā–ˆā•‘ ā–ˆā–ˆā•‘ā–ˆā–ˆā•”ā•ā•ā–ˆā–ˆā•— ā•‘ ā•‘ ā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā•—ā–ˆā–ˆā–ˆā–ˆā–ˆā•— ā–ˆā–ˆā•‘ ā–ˆā–ˆā•‘ ā–ˆā–ˆā•‘ā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā•”ā• ā•‘ ā•‘ ā•šā•ā•ā•ā•ā–ˆā–ˆā•‘ā–ˆā–ˆā•”ā•ā•ā• ā–ˆā–ˆā•‘ ā–ˆā–ˆā•‘ ā–ˆā–ˆā•‘ā–ˆā–ˆā•”ā•ā•ā•ā• ā•‘ ā•‘ ā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā•‘ā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā•— ā–ˆā–ˆā•‘ ā•šā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā•”ā•ā–ˆā–ˆā•‘ ā•‘ ā•‘ ā•šā•ā•ā•ā•ā•ā•ā•ā•šā•ā•ā•ā•ā•ā•ā• ā•šā•ā• ā•šā•ā•ā•ā•ā•ā• ā•šā•ā• ā•‘ ā•‘ ā•‘ ā•‘ Welcome to the Interactive Setup Wizard! ā•‘ ā•‘ ā•‘ ā•šā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā• `; if (useColor) { const coloredBanner = banner .replace(/ā•‘/g, this.colorize('ā•‘', this.COLORS.blue)) .replace(/ā•”|ā•—|ā•š|ā•|═/g, match => this.colorize(match, this.COLORS.blue)) .replace(/ā–ˆā–ˆā–ˆ/g, this.colorize('ā–ˆā–ˆā–ˆ', this.COLORS.cyan)) .replace(/Welcome to the Interactive Setup Wizard!/g, this.colorize('Welcome to the Interactive Setup Wizard!', this.COLORS.green + this.COLORS.bright)); console.log(coloredBanner); } else { console.log(banner); } } /** * Loading spinner animation */ static startSpinner(message, options = {}) { const frames = ['ā ‹', 'ā ™', 'ā ¹', 'ā ø', 'ā ¼', 'ā “', 'ā ¦', 'ā §', 'ā ‡', 'ā ']; const { interval = 100, color = true } = options; let frameIndex = 0; this.hideCursor(); const timer = setInterval(() => { this.clearLine(); process_1.stdout.write('\r'); const spinner = this.colorize(frames[frameIndex], this.COLORS.cyan, color); const text = this.colorize(message, this.COLORS.white, color); process_1.stdout.write(`${spinner} ${text}`); frameIndex = (frameIndex + 1) % frames.length; }, interval); this.activeAnimations.add(timer); return () => { clearInterval(timer); this.activeAnimations.delete(timer); this.clearLine(); process_1.stdout.write('\r'); this.showCursor(); }; } /** * Progress bar animation */ static createProgressBar(total, options = {}) { const { color = true } = options; const width = 40; const update = (current, message = '') => { const percentage = Math.min(100, Math.max(0, (current / total) * 100)); const filled = Math.floor((percentage / 100) * width); const empty = width - filled; const filledBar = 'ā–ˆ'.repeat(filled); const emptyBar = 'ā–‘'.repeat(empty); this.clearLine(); process_1.stdout.write('\r'); const bar = this.colorize(filledBar, this.COLORS.green, color) + this.colorize(emptyBar, this.COLORS.dim, color); const percent = this.colorize(`${percentage.toFixed(1)}%`, this.COLORS.bright, color); const text = this.colorize(message, this.COLORS.white, color); process_1.stdout.write(`[${bar}] ${percent} ${text}`); }; const complete = (message = 'Complete!') => { update(total, message); process_1.stdout.write('\n'); }; return { update, complete }; } /** * Step-by-step progress indicators */ static displayStepProgress(steps, currentStep, options = {}) { const { color = true } = options; console.log('\n' + this.colorize('Setup Progress:', this.COLORS.bright + this.COLORS.white, color)); console.log(this.colorize('═'.repeat(50), this.COLORS.blue, color)); steps.forEach((step, index) => { let icon; let stepColor; if (index < currentStep) { icon = 'āœ“'; stepColor = this.COLORS.green; } else if (index === currentStep) { icon = 'ā–¶'; stepColor = this.COLORS.yellow; } else { icon = 'ā—‹'; stepColor = this.COLORS.dim; } const coloredIcon = this.colorize(icon, stepColor, color); const coloredStep = this.colorize(step, stepColor, color); console.log(` ${coloredIcon} ${coloredStep}`); }); console.log(''); } /** * Password generation animation */ static animatePasswordGeneration(options = {}) { return new Promise(resolve => { const { duration = 3000, interval = 100, color = true } = options; const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*()_+-=[]{}|;:,.<>?'; const length = 16; let password = new Array(length).fill('?'); let revealedCount = 0; this.hideCursor(); const timer = setInterval(() => { // Randomly change unrevealed characters for (let i = revealedCount; i < length; i++) { password[i] = chars[Math.floor(Math.random() * chars.length)]; } // Occasionally reveal a character if (revealedCount < length && Math.random() < 0.3) { password[revealedCount] = chars[Math.floor(Math.random() * chars.length)]; revealedCount++; } this.clearLine(); process_1.stdout.write('\r'); const displayPassword = password .map((char, index) => { if (index < revealedCount) { return this.colorize(char, this.COLORS.green, color); } else { return this.colorize(char, this.COLORS.dim, color); } }) .join(''); const message = this.colorize('Generating secure password: ', this.COLORS.cyan, color); process_1.stdout.write(`${message}[${displayPassword}]`); if (revealedCount >= length) { clearInterval(timer); this.activeAnimations.delete(timer); process_1.stdout.write('\n'); this.showCursor(); resolve(password.join('')); } }, interval); this.activeAnimations.add(timer); // Force completion after duration (0, timers_1.setTimeout)(() => { if (revealedCount < length) { clearInterval(timer); this.activeAnimations.delete(timer); const finalPassword = new Array(length) .fill(null) .map(() => chars[Math.floor(Math.random() * chars.length)]) .join(''); this.clearLine(); process_1.stdout.write('\r'); const message = this.colorize('Generated secure password: ', this.COLORS.green, color); const displayPassword = this.colorize(finalPassword, this.COLORS.bright, color); process_1.stdout.write(`${message}[${displayPassword}]\n`); this.showCursor(); resolve(finalPassword); } }, duration); }); } /** * Success animation */ static displaySuccess(message, options = {}) { const { color = true } = options; const successArt = ` ╔═══════════════════════════════════════╗ ā•‘ ā•‘ ā•‘ āœ“ SUCCESS! ā•‘ ā•‘ ā•‘ ā•‘ .-~-.-~-.-~-.-~-.-~-. ā•‘ ā•‘ ( S U C C E S S F U L ) ā•‘ ā•‘ \`-~-^-~-^-~-^-~-^-~-^-' ā•‘ ā•‘ ā•‘ ā•‘ šŸŽ‰ Well done! šŸŽ‰ ā•‘ ā•‘ ā•‘ ā•šā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā• `; if (color) { const coloredArt = successArt .replace(/ā•”|ā•—|ā•š|ā•|═|ā•‘/g, match => this.colorize(match, this.COLORS.green)) .replace(/āœ“ SUCCESS!/g, this.colorize('āœ“ SUCCESS!', this.COLORS.green + this.COLORS.bright)) .replace(/šŸŽ‰ Well done! šŸŽ‰/g, this.colorize('šŸŽ‰ Well done! šŸŽ‰', this.COLORS.yellow + this.COLORS.bright)); console.log(coloredArt); } else { console.log(successArt.replace(/šŸŽ‰/g, '*')); } console.log(this.colorize(` ${message}`, this.COLORS.green + this.COLORS.bright, color)); console.log(''); } /** * Error animation */ static displayError(message, options = {}) { const { color = true } = options; const errorArt = ` ╔═══════════════════════════════════════╗ ā•‘ ā•‘ ā•‘ āœ— ERROR! ā•‘ ā•‘ ā•‘ ā•‘ .-~-.-~-.-~-.-~-.-~-. ā•‘ ā•‘ ( S O M E T H I N G ) ā•‘ ā•‘ ( W E N T W R O N G ) ā•‘ ā•‘ \`-~-^-~-^-~-^-~-^-~-^-' ā•‘ ā•‘ ā•‘ ā•‘ āš ļø Please retry āš ļø ā•‘ ā•‘ ā•‘ ā•šā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā• `; if (color) { const coloredArt = errorArt .replace(/ā•”|ā•—|ā•š|ā•|═|ā•‘/g, match => this.colorize(match, this.COLORS.red)) .replace(/āœ— ERROR!/g, this.colorize('āœ— ERROR!', this.COLORS.red + this.COLORS.bright)) .replace(/āš ļø Please retry āš ļø/g, this.colorize('āš ļø Please retry āš ļø', this.COLORS.yellow + this.COLORS.bright)); console.log(coloredArt); } else { console.log(errorArt.replace(/āš ļø/g, '!')); } console.log(this.colorize(` ${message}`, this.COLORS.red + this.COLORS.bright, color)); console.log(''); } /** * Fun ASCII graphics for different setup stages */ static displayStageGraphic(stage, options = {}) { const { color = true } = options; let graphic = ''; switch (stage) { case 'database': graphic = ` ╔════════════════════════════════════════╗ ā•‘ DATABASE SETUP ā•‘ ā•‘ ā•‘ ā•‘ ā”Œā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā” ā•‘ ā•‘ │ ā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆ │ ā•‘ ā•‘ │ ā–ˆā–ˆ Tables ā–ˆā–ˆ Schemas ā–ˆā–ˆ Data │ ā•‘ ā•‘ │ ā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆ │ ā•‘ ā•‘ ā””ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”˜ ā•‘ ā•‘ ā•‘ ā•‘ Configuring data storage... ā•‘ ā•šā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā• `; break; case 'server': graphic = ` ╔════════════════════════════════════════╗ ā•‘ SERVER SETUP ā•‘ ā•‘ ā•‘ ā•‘ ā–² ā–² ā–² ā–² ā–² ā–² ā–² ā–² ā–² ā–² ā•‘ ā•‘ ā–ˆ ā–ˆ ā–ˆ ā–ˆ ā–ˆ ā–ˆ ā–ˆ ā–ˆ ā–ˆ ā–ˆ ā•‘ ā•‘ ā”Œā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā” ā•‘ ā•‘ │ MCP Quiz Server │ ā•‘ ā•‘ │ Port: 3000 │ ā•‘ ā•‘ ā””ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”˜ ā•‘ ā•‘ ā•‘ ā•‘ Starting server configuration... ā•‘ ā•šā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā• `; break; case 'security': graphic = ` ╔════════════════════════════════════════╗ ā•‘ SECURITY SETUP ā•‘ ā•‘ ā•‘ ā•‘ šŸ”’šŸ”šŸ”‘šŸ›”ļøšŸ”“šŸ”’šŸ” ā•‘ ā•‘ ā•‘ ā•‘ ā”Œā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā” ā•‘ ā•‘ │ Generating keys... │ ā•‘ ā•‘ │ Setting permissions │ ā•‘ ā•‘ │ Configuring auth... │ ā•‘ ā•‘ ā””ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”˜ ā•‘ ā•‘ ā•‘ ā•‘ Securing your application... ā•‘ ā•šā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā• `; break; case 'final': graphic = ` ╔════════════════════════════════════════╗ ā•‘ FINAL TOUCHES ā•‘ ā•‘ ā•‘ ā•‘ šŸŽØāœØšŸŽÆšŸš€ā­šŸŽŖšŸŽ­ ā•‘ ā•‘ ā•‘ ā•‘ ā”Œā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā” ā•‘ ā•‘ │ Applying finishing │ ā•‘ ā•‘ │ touches and cleanup │ ā•‘ ā•‘ │ Verifying setup... │ ā•‘ ā•‘ ā””ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”˜ ā•‘ ā•‘ ā•‘ ā•‘ Almost ready to launch! ā•‘ ā•šā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā• `; break; } if (color) { const coloredGraphic = graphic .replace(/ā•”|ā•—|ā•š|ā•|═|ā•‘/g, match => this.colorize(match, this.COLORS.blue)) .replace(/(DATABASE|SERVER|SECURITY|FINAL)( SETUP| TOUCHES)/g, match => this.colorize(match, this.COLORS.cyan + this.COLORS.bright)) .replace(/šŸ”’šŸ”šŸ”‘šŸ›”ļøšŸ”“šŸ”’šŸ”|šŸŽØāœØšŸŽÆšŸš€ā­šŸŽŖšŸŽ­/g, match => this.colorize(match, this.COLORS.yellow)); console.log(coloredGraphic); } else { console.log(graphic.replace(/šŸ”’šŸ”šŸ”‘šŸ›”ļøšŸ”“šŸ”’šŸ”|šŸŽØāœØšŸŽÆšŸš€ā­šŸŽŖšŸŽ­/g, '***')); } } /** * Clean up and restore terminal */ static cleanup() { this.clearAllAnimations(); this.showCursor(); console.log(''); // Add final newline } } exports.AsciiAnimations = AsciiAnimations; AsciiAnimations.COLORS = { reset: '\x1b[0m', bright: '\x1b[1m', dim: '\x1b[2m', red: '\x1b[31m', green: '\x1b[32m', yellow: '\x1b[33m', blue: '\x1b[34m', magenta: '\x1b[35m', cyan: '\x1b[36m', white: '\x1b[37m', bgRed: '\x1b[41m', bgGreen: '\x1b[42m', bgYellow: '\x1b[43m', bgBlue: '\x1b[44m', }; AsciiAnimations.activeAnimations = new Set(); // Auto-cleanup on process exit process.on('exit', () => AsciiAnimations.cleanup()); process.on('SIGINT', () => { AsciiAnimations.cleanup(); process.exit(0); }); process.on('SIGTERM', () => { AsciiAnimations.cleanup(); process.exit(0); }); exports.default = AsciiAnimations;