UNPKG

neex

Version:

Neex - Modern Fullstack Framework Built on Express and Next.js. Fast to Start, Easy to Build, Ready to Deploy

760 lines (757 loc) 37.7 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 (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); __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.addProcessCommands = void 0; const process_manager_js_1 = require("../process-manager.js"); const chalk_1 = __importDefault(require("chalk")); const figures_1 = __importDefault(require("figures")); const path = __importStar(require("path")); const fs = __importStar(require("fs")); const fs_1 = require("fs"); // Helper function to format uptime function formatUptime(seconds) { if (seconds < 60) { return `${seconds}s`; } else if (seconds < 3600) { const minutes = Math.floor(seconds / 60); const remainingSeconds = seconds % 60; return `${minutes}m ${remainingSeconds}s`; } else { const hours = Math.floor(seconds / 3600); const minutes = Math.floor((seconds % 3600) / 60); return `${hours}h ${minutes}m`; } } // Helper function to format memory function formatMemory(bytes) { if (bytes === 0) return '0B'; const k = 1024; const sizes = ['B', 'KB', 'MB', 'GB']; const i = Math.floor(Math.log(bytes) / Math.log(k)); return parseFloat((bytes / Math.pow(k, i)).toFixed(1)) + sizes[i]; } // Helper function to format CPU function formatCpu(cpu) { return `${cpu.toFixed(1)}%`; } function addProcessCommands(program) { let processManager = null; const getOrCreateProcessManager = async () => { if (!processManager) { processManager = new process_manager_js_1.ProcessManager(); await processManager.load(); } return processManager; }; // Start command - اجرای برنامه program .command('start <script>') .description('Start a new process') .option('-n, --name <name>', 'Process name') .option('-i, --instances <number>', 'Number of instances', parseInt) .option('--cwd <path>', 'Working directory') .option('--env <env>', 'Environment variables (JSON string)') .option('--no-autorestart', 'Disable auto-restart') .option('--max-restarts <number>', 'Maximum restarts', parseInt) .option('--restart-delay <ms>', 'Restart delay in ms', parseInt) .option('--watch', 'Enable file watching') .option('--ignore-watch <patterns...>', 'Patterns to ignore when watching') .option('--max-memory <size>', 'Max memory before restart (e.g., 1G, 500M)') .option('--interpreter <interpreter>', 'Interpreter to use (node, ts-node, etc.)') .option('--interpreter-args <args>', 'Interpreter arguments') .option('--log <path>', 'Log file path') .option('--error <path>', 'Error log file path') .option('--time', 'Prefix logs with timestamp') .option('--merge-logs', 'Merge logs and errors') .option('--typescript', 'Script is TypeScript (will use ts-node)') .option('--build-dir <dir>', 'Build directory for TypeScript projects', 'dist') .action(async (script, options) => { try { const pm = await getOrCreateProcessManager(); // Resolve script path const scriptPath = path.resolve(script); if (!fs.existsSync(scriptPath)) { console.error(chalk_1.default.red(`${figures_1.default.cross} Script file not found: ${scriptPath}`)); process.exit(1); } // If TypeScript flag is set, use ts-node const interpreter = options.typescript ? 'ts-node' : options.interpreter || 'node'; const interpreterArgs = options.typescript ? ['--project', 'tsconfig.json'] : options.interpreterArgs ? options.interpreterArgs.split(' ') : undefined; const config = { id: '', name: options.name || path.basename(script, path.extname(script)), script: scriptPath, cwd: options.cwd ? path.resolve(options.cwd) : process.cwd(), env: options.env ? JSON.parse(options.env) : undefined, instances: options.instances || 1, autorestart: options.autorestart !== false, max_restarts: options.maxRestarts || 10, restart_delay: options.restartDelay || 1000, watch: options.watch || false, ignore_watch: options.ignoreWatch, max_memory_restart: options.maxMemory, interpreter, interpreter_args: interpreterArgs, log_file: options.log, error_file: options.error, out_file: options.log, time: options.time || false, merge_logs: options.mergeLogs || false }; const id = await pm.start(config); console.log(chalk_1.default.green(`${figures_1.default.tick} Process started successfully`)); console.log(chalk_1.default.blue(`${figures_1.default.info} Process ID: ${id}`)); console.log(chalk_1.default.blue(`${figures_1.default.info} Process Name: ${config.name}`)); console.log(chalk_1.default.blue(`${figures_1.default.info} Script: ${scriptPath}`)); console.log(chalk_1.default.blue(`${figures_1.default.info} Interpreter: ${interpreter}`)); } catch (error) { if (error instanceof Error) { console.error(chalk_1.default.red(`${figures_1.default.cross} Start Error: ${error.message}`)); } else { console.error(chalk_1.default.red(`${figures_1.default.cross} An unknown start error occurred`)); } process.exit(1); } }); // Stop command - توقف برنامه program .command('stop <id>') .description('Stop a process (use "all" to stop all processes)') .action(async (id) => { try { const pm = await getOrCreateProcessManager(); if (id === 'all') { await pm.stopAll(); console.log(chalk_1.default.green(`${figures_1.default.tick} All processes stopped`)); } else { await pm.stop(id); console.log(chalk_1.default.green(`${figures_1.default.tick} Process ${id} stopped`)); } } catch (error) { if (error instanceof Error) { console.error(chalk_1.default.red(`${figures_1.default.cross} Stop Error: ${error.message}`)); } else { console.error(chalk_1.default.red(`${figures_1.default.cross} An unknown stop error occurred`)); } process.exit(1); } }); // Restart command - راه‌اندازی مجدد program .command('restart <id>') .description('Restart a process (use "all" to restart all processes)') .action(async (id) => { try { const pm = await getOrCreateProcessManager(); if (id === 'all') { await pm.restartAll(); console.log(chalk_1.default.green(`${figures_1.default.tick} All processes restarted`)); } else { await pm.restart(id); console.log(chalk_1.default.green(`${figures_1.default.tick} Process ${id} restarted`)); } } catch (error) { if (error instanceof Error) { console.error(chalk_1.default.red(`${figures_1.default.cross} Restart Error: ${error.message}`)); } else { console.error(chalk_1.default.red(`${figures_1.default.cross} An unknown restart error occurred`)); } process.exit(1); } }); // Delete command - حذف برنامه program .command('delete <id>') .alias('del') .description('Delete a process (use "all" to delete all processes)') .action(async (id) => { try { const pm = await getOrCreateProcessManager(); if (id === 'all') { await pm.deleteAll(); console.log(chalk_1.default.green(`${figures_1.default.tick} All processes deleted`)); } else { await pm.delete(id); console.log(chalk_1.default.green(`${figures_1.default.tick} Process ${id} deleted`)); } } catch (error) { if (error instanceof Error) { console.error(chalk_1.default.red(`${figures_1.default.cross} Delete Error: ${error.message}`)); } else { console.error(chalk_1.default.red(`${figures_1.default.cross} An unknown delete error occurred`)); } process.exit(1); } }); // List/Status command - نمایش وضعیت program .command('list') .alias('status') .alias('ls') .description('List all processes with detailed information') .action(async () => { try { const pm = await getOrCreateProcessManager(); const processes = await pm.list(); if (processes.length === 0) { console.log(chalk_1.default.yellow(`${figures_1.default.info} No processes found`)); console.log(chalk_1.default.blue(`${figures_1.default.info} Use 'neex start <script>' to start a new process`)); return; } // Print enhanced table console.log('\n' + chalk_1.default.bold.cyan('Neex Process Monitor')); console.log(chalk_1.default.gray('─'.repeat(100))); const header = `${chalk_1.default.bold('ID'.padEnd(12))} ${chalk_1.default.bold('Name'.padEnd(15))} ${chalk_1.default.bold('Status'.padEnd(10))} ${chalk_1.default.bold('PID'.padEnd(8))} ${chalk_1.default.bold('Uptime'.padEnd(10))} ${chalk_1.default.bold('Restarts'.padEnd(8))} ${chalk_1.default.bold('CPU'.padEnd(8))} ${chalk_1.default.bold('Memory'.padEnd(10))}`; console.log(header); console.log(chalk_1.default.gray('─'.repeat(100))); // Print process information processes.forEach(proc => { const statusColor = proc.status === 'online' ? chalk_1.default.green : proc.status === 'stopped' ? chalk_1.default.gray : proc.status === 'errored' ? chalk_1.default.red : proc.status === 'launching' ? chalk_1.default.yellow : chalk_1.default.blue; const uptime = formatUptime(proc.uptime); const pid = proc.pid ? proc.pid.toString() : 'N/A'; const cpu = proc.status === 'online' ? formatCpu(proc.cpu) : 'N/A'; const memory = proc.status === 'online' ? formatMemory(proc.memory) : 'N/A'; const row = `${proc.id.padEnd(12)} ${proc.name.padEnd(15)} ${statusColor(proc.status.padEnd(10))} ${pid.padEnd(8)} ${uptime.padEnd(10)} ${proc.restarts.toString().padEnd(8)} ${cpu.padEnd(8)} ${memory.padEnd(10)}`; console.log(row); }); console.log(chalk_1.default.gray('─'.repeat(100))); const online = processes.filter(p => p.status === 'online').length; const stopped = processes.filter(p => p.status === 'stopped').length; const errored = processes.filter(p => p.status === 'errored').length; console.log(`\n${chalk_1.default.blue(`${figures_1.default.info} Total: ${processes.length} processes`)} | ${chalk_1.default.green(`Online: ${online}`)} | ${chalk_1.default.gray(`Stopped: ${stopped}`)} | ${chalk_1.default.red(`Errored: ${errored}`)}`); } catch (error) { if (error instanceof Error) { console.error(chalk_1.default.red(`${figures_1.default.cross} List Error: ${error.message}`)); } else { console.error(chalk_1.default.red(`${figures_1.default.cross} An unknown list error occurred`)); } process.exit(1); } }); // Logs command - نمایش لاگ‌ها program .command('logs <id>') .alias('log') .description('Show process logs') .option('-l, --lines <number>', 'Number of lines to show', parseInt, 15) .option('-f, --follow', 'Follow log output') .action(async (id, options) => { try { const pm = await getOrCreateProcessManager(); const processInfo = pm.getProcess(id); if (!processInfo) { console.error(chalk_1.default.red(`${figures_1.default.cross} Process ${id} not found`)); process.exit(1); } console.log(chalk_1.default.blue(`${figures_1.default.info} Showing logs for process: ${processInfo.name} (${id})`)); console.log(chalk_1.default.gray('─'.repeat(60))); if (options.follow) { // Follow logs const logFollower = pm.followLogs(id, (logLine) => { console.log(logLine); }); if (!logFollower) { console.error(chalk_1.default.red(`${figures_1.default.cross} Failed to follow logs for process ${id}`)); process.exit(1); } // Handle Ctrl+C to stop following process.on('SIGINT', () => { console.log(chalk_1.default.yellow(`\n${figures_1.default.info} Stopping log follow...`)); logFollower.stop(); process.exit(0); }); console.log(chalk_1.default.green(`${figures_1.default.tick} Following logs... Press Ctrl+C to stop`)); } else { // Show recent logs const logs = await pm.logs(id, options.lines); if (logs.length === 0) { console.log(chalk_1.default.yellow(`${figures_1.default.info} No logs found for process ${id}`)); } else { logs.forEach(log => console.log(log)); } } } catch (error) { if (error instanceof Error) { console.error(chalk_1.default.red(`${figures_1.default.cross} Logs Error: ${error.message}`)); } else { console.error(chalk_1.default.red(`${figures_1.default.cross} An unknown logs error occurred`)); } process.exit(1); } }); // Save command - ذخیره وضعیت program .command('save') .description('Save current process configuration') .action(async () => { try { const pm = await getOrCreateProcessManager(); await pm.save(); console.log(chalk_1.default.green(`${figures_1.default.tick} Process configuration saved successfully`)); } catch (error) { if (error instanceof Error) { console.error(chalk_1.default.red(`${figures_1.default.cross} Save Error: ${error.message}`)); } else { console.error(chalk_1.default.red(`${figures_1.default.cross} An unknown save error occurred`)); } process.exit(1); } }); // Resurrect command - بازیابی برنامه‌ها program .command('resurrect') .description('Resurrect previously saved processes') .action(async () => { try { const pm = await getOrCreateProcessManager(); await pm.load(); const processes = await pm.list(); const stoppedProcesses = processes.filter(p => p.status === 'stopped'); if (stoppedProcesses.length === 0) { console.log(chalk_1.default.yellow(`${figures_1.default.info} No stopped processes to resurrect`)); return; } console.log(chalk_1.default.blue(`${figures_1.default.info} Resurrecting ${stoppedProcesses.length} processes...`)); for (const proc of stoppedProcesses) { try { await pm.restart(proc.id); console.log(chalk_1.default.green(`${figures_1.default.tick} Resurrected: ${proc.name} (${proc.id})`)); } catch (error) { console.log(chalk_1.default.red(`${figures_1.default.cross} Failed to resurrect: ${proc.name} (${proc.id})`)); } } } catch (error) { if (error instanceof Error) { console.error(chalk_1.default.red(`${figures_1.default.cross} Resurrect Error: ${error.message}`)); } else { console.error(chalk_1.default.red(`${figures_1.default.cross} An unknown resurrect error occurred`)); } process.exit(1); } }); // Info command - اطلاعات دقیق برنامه program .command('info <id>') .alias('show') .description('Show detailed information about a process') .action(async (id) => { try { const pm = await getOrCreateProcessManager(); const processInfo = pm.getProcess(id); if (!processInfo) { console.error(chalk_1.default.red(`${figures_1.default.cross} Process ${id} not found`)); process.exit(1); } console.log('\n' + chalk_1.default.bold.cyan(`Process Information: ${processInfo.name}`)); console.log(chalk_1.default.gray('─'.repeat(50))); console.log(`${chalk_1.default.bold('ID:')} ${processInfo.id}`); console.log(`${chalk_1.default.bold('Name:')} ${processInfo.name}`); console.log(`${chalk_1.default.bold('Status:')} ${processInfo.status === 'online' ? chalk_1.default.green(processInfo.status) : chalk_1.default.red(processInfo.status)}`); console.log(`${chalk_1.default.bold('PID:')} ${processInfo.pid || 'N/A'}`); console.log(`${chalk_1.default.bold('Uptime:')} ${formatUptime(processInfo.uptime)}`); console.log(`${chalk_1.default.bold('Restarts:')} ${processInfo.restarts}`); console.log(`${chalk_1.default.bold('CPU:')} ${formatCpu(processInfo.cpu)}`); console.log(`${chalk_1.default.bold('Memory:')} ${formatMemory(processInfo.memory)}`); console.log(`${chalk_1.default.bold('Script:')} ${processInfo.config.script}`); console.log(`${chalk_1.default.bold('Working Directory:')} ${processInfo.config.cwd || process.cwd()}`); console.log(`${chalk_1.default.bold('Auto Restart:')} ${processInfo.config.autorestart ? 'Yes' : 'No'}`); console.log(`${chalk_1.default.bold('Max Restarts:')} ${processInfo.config.max_restarts}`); console.log(`${chalk_1.default.bold('Created At:')} ${processInfo.created_at.toISOString()}`); if (processInfo.started_at) { console.log(`${chalk_1.default.bold('Started At:')} ${processInfo.started_at.toISOString()}`); } if (processInfo.last_restart) { console.log(`${chalk_1.default.bold('Last Restart:')} ${processInfo.last_restart.toISOString()}`); } if (processInfo.config.env) { console.log(`${chalk_1.default.bold('Environment Variables:')}`); Object.entries(processInfo.config.env).forEach(([key, value]) => { console.log(` ${key}: ${value}`); }); } } catch (error) { if (error instanceof Error) { console.error(chalk_1.default.red(`${figures_1.default.cross} Info Error: ${error.message}`)); } else { console.error(chalk_1.default.red(`${figures_1.default.cross} An unknown info error occurred`)); } process.exit(1); } }); // Monitor command - مانیتور زنده program .command('monitor') .alias('monit') .description('Launch process monitor dashboard') .action(async () => { try { const pm = await getOrCreateProcessManager(); console.log(chalk_1.default.blue(`${figures_1.default.info} Starting Neex Process Monitor...`)); console.log(chalk_1.default.gray('Press Ctrl+C to exit')); const displayMonitor = async () => { // Clear screen process.stdout.write('\x1Bc'); const processes = await pm.list(); console.log(chalk_1.default.bold.cyan('Neex Process Monitor')); console.log(chalk_1.default.gray('─'.repeat(80))); if (processes.length === 0) { console.log(chalk_1.default.yellow(`${figures_1.default.info} No processes running`)); } else { processes.forEach(proc => { const statusIcon = proc.status === 'online' ? chalk_1.default.green('●') : proc.status === 'stopped' ? chalk_1.default.gray('○') : proc.status === 'errored' ? chalk_1.default.red('●') : chalk_1.default.yellow('●'); const uptime = formatUptime(proc.uptime); const pid = proc.pid ? `PID: ${proc.pid}` : 'PID: N/A'; const memory = proc.status === 'online' ? formatMemory(proc.memory) : 'N/A'; const cpu = proc.status === 'online' ? formatCpu(proc.cpu) : 'N/A'; console.log(`${statusIcon} ${chalk_1.default.bold(proc.name)} (${proc.id}) - ${proc.status}`); console.log(` ${pid} | Uptime: ${uptime} | Restarts: ${proc.restarts} | CPU: ${cpu} | Memory: ${memory}`); console.log(''); }); } console.log(chalk_1.default.gray('─'.repeat(80))); console.log(`Last updated: ${new Date().toLocaleTimeString()}`); }; // Initial display await displayMonitor(); // Update every 2 seconds const monitorInterval = setInterval(displayMonitor, 2000); // Handle Ctrl+C process.on('SIGINT', () => { clearInterval(monitorInterval); console.log(chalk_1.default.yellow(`\n${figures_1.default.info} Monitor stopped`)); process.exit(0); }); } catch (error) { if (error instanceof Error) { console.error(chalk_1.default.red(`${figures_1.default.cross} Monitor Error: ${error.message}`)); } else { console.error(chalk_1.default.red(`${figures_1.default.cross} An unknown monitor error occurred`)); } process.exit(1); } }); // StartX command - اجرای بهینه برای پروداکشن program .command('startx <script>') .description('Start process optimized for production (auto-restart, clustering, monitoring)') .option('-n, --name <name>', 'Process name') .option('-i, --instances <number>', 'Number of instances (default: CPU cores)', parseInt) .option('--max-memory <size>', 'Max memory before restart (default: 1G)') .option('--cwd <path>', 'Working directory') .option('--env <env>', 'Environment variables (JSON string)') .action(async (script, options) => { try { const pm = await getOrCreateProcessManager(); const os = require('os'); // Resolve script path const scriptPath = path.resolve(script); if (!fs.existsSync(scriptPath)) { console.error(chalk_1.default.red(`${figures_1.default.cross} Script file not found: ${scriptPath}`)); process.exit(1); } const instances = options.instances || os.cpus().length; const processName = options.name || path.basename(script, path.extname(script)); console.log(chalk_1.default.blue(`${figures_1.default.info} Starting production-optimized process...`)); console.log(chalk_1.default.blue(`${figures_1.default.info} Script: ${scriptPath}`)); console.log(chalk_1.default.blue(`${figures_1.default.info} Instances: ${instances}`)); console.log(chalk_1.default.blue(`${figures_1.default.info} Max Memory: ${options.maxMemory || '1G'}`)); const baseConfig = { id: '', name: processName, script: scriptPath, cwd: options.cwd ? path.resolve(options.cwd) : process.cwd(), env: { NODE_ENV: 'production', ...(options.env ? JSON.parse(options.env) : {}) }, instances: 1, autorestart: true, max_restarts: 50, restart_delay: 1000, watch: false, max_memory_restart: options.maxMemory || '1G', time: true, merge_logs: false }; const startedProcesses = []; // Start multiple instances for (let i = 0; i < instances; i++) { const config = { ...baseConfig, name: instances > 1 ? `${processName}-${i}` : processName }; try { const id = await pm.start(config); startedProcesses.push(id); console.log(chalk_1.default.green(`${figures_1.default.tick} Instance ${i + 1}/${instances} started (ID: ${id})`)); // Small delay between starts if (i < instances - 1) { await new Promise(resolve => setTimeout(resolve, 500)); } } catch (error) { console.error(chalk_1.default.red(`${figures_1.default.cross} Failed to start instance ${i + 1}: ${error.message}`)); } } if (startedProcesses.length > 0) { // Auto-save configuration await pm.save(); console.log(chalk_1.default.green(`\n${figures_1.default.tick} Production deployment completed!`)); console.log(chalk_1.default.blue(`${figures_1.default.info} Started ${startedProcesses.length}/${instances} instances`)); console.log(chalk_1.default.blue(`${figures_1.default.info} Configuration saved automatically`)); console.log(chalk_1.default.blue(`${figures_1.default.info} Use 'neex monitor' to watch processes`)); console.log(chalk_1.default.blue(`${figures_1.default.info} Use 'neex logs <id>' to view logs`)); } else { console.error(chalk_1.default.red(`${figures_1.default.cross} Failed to start any instances`)); process.exit(1); } } catch (error) { if (error instanceof Error) { console.error(chalk_1.default.red(`${figures_1.default.cross} StartX Error: ${error.message}`)); } else { console.error(chalk_1.default.red(`${figures_1.default.cross} An unknown startx error occurred`)); } process.exit(1); } }); //stopx command - توقف بهینه برای پروداکشن program .command('stopx <name>') .description('Stop all instances of a production-optimized process by name') .action(async (name) => { try { const pm = await getOrCreateProcessManager(); const processes = await pm.list(); // دریافت لیست تمام فرایندها // پیدا کردن تمام فرایندهایی که با نام اصلی (نه با ایندکس) شروع می‌شوند const processesToStop = processes.filter(p => p.name === name || p.name.startsWith(`${name}-`)); if (processesToStop.length === 0) { console.log(chalk_1.default.yellow(`${figures_1.default.warning} No production process instances found for name "${name}".`)); return; } console.log(chalk_1.default.blue(`${figures_1.default.info} Stopping ${processesToStop.length} instances of "${name}"...`)); const stopPromises = processesToStop.map(async (p) => { try { await pm.stop(p.id); console.log(chalk_1.default.green(`${figures_1.default.tick} Stopped instance ${p.name} (ID: ${p.id})`)); } catch (error) { if (error instanceof Error) { console.error(chalk_1.default.red(`${figures_1.default.cross} Failed to stop instance ${p.name} (ID: ${p.id}): ${error.message}`)); } else { console.error(chalk_1.default.red(`${figures_1.default.cross} An unknown error occurred while stopping instance ${p.name} (ID: ${p.id})`)); } } }); await Promise.all(stopPromises); // اجرای موازی توقف‌ها console.log(chalk_1.default.green(`\n${figures_1.default.tick} All specified production process instances have been processed.`)); await pm.save(); // ذخیره تغییرات (حذف فرایندهای متوقف شده) } catch (error) { if (error instanceof Error) { console.error(chalk_1.default.red(`${figures_1.default.cross} StopX Error: ${error.message}`)); } else { console.error(chalk_1.default.red(`${figures_1.default.cross} An unknown stopx error occurred`)); } process.exit(1); } }); // Build command - Compile TypeScript project program .command('build <entry>') .description('Build TypeScript project from entry point') .option('-o, --out <dir>', 'Output directory', 'dist') .option('--tsconfig <path>', 'Path to tsconfig.json', 'tsconfig.json') .option('--watch', 'Watch for changes and rebuild') .action(async (entry, options) => { try { const entryPath = path.resolve(entry); const tsConfigPath = path.resolve(options.tsconfig); const outDir = path.resolve(options.out); // Check if entry file exists if (!fs.existsSync(entryPath)) { console.error(chalk_1.default.red(`${figures_1.default.cross} Entry point not found: ${entryPath}`)); process.exit(1); } // Check if tsconfig exists if (!fs.existsSync(tsConfigPath)) { console.error(chalk_1.default.red(`${figures_1.default.cross} tsconfig.json not found at: ${tsConfigPath}`)); process.exit(1); } // Create output directory if it doesn't exist if (!fs.existsSync(outDir)) { fs.mkdirSync(outDir, { recursive: true }); } // Read tsconfig const tsConfig = JSON.parse(await fs_1.promises.readFile(tsConfigPath, 'utf8')); // Update tsconfig with entry point tsConfig.files = [entryPath]; // Write temporary tsconfig const tempTsConfigPath = path.join(process.cwd(), '.neex.tsconfig.json'); await fs_1.promises.writeFile(tempTsConfigPath, JSON.stringify(tsConfig, null, 2)); console.log(chalk_1.default.blue(`${figures_1.default.info} Building TypeScript project...`)); console.log(chalk_1.default.blue(`${figures_1.default.info} Entry Point: ${entryPath}`)); console.log(chalk_1.default.blue(`${figures_1.default.info} Output: ${outDir}`)); console.log(chalk_1.default.blue(`${figures_1.default.info} Using tsconfig: ${tempTsConfigPath}`)); // Run tsc command const { spawn } = require('child_process'); const tsc = spawn('tsc', [ '--build', '--project', tempTsConfigPath, ...(options.watch ? ['--watch'] : []) ], { stdio: 'inherit', cwd: process.cwd() }); tsc.on('close', (code) => { // Clean up temporary tsconfig fs.unlink(tempTsConfigPath, (err) => { if (err) console.error('Error cleaning up temporary tsconfig:', err); }); if (code === 0) { console.log(chalk_1.default.green(`${figures_1.default.tick} Build completed successfully!`)); console.log(chalk_1.default.blue(`${figures_1.default.info} Output files in: ${outDir}`)); } else { console.error(chalk_1.default.red(`${figures_1.default.cross} Build failed with code ${code}`)); process.exit(1); } }); } catch (error) { if (error instanceof Error) { console.error(chalk_1.default.red(`${figures_1.default.cross} Build Error: ${error.message}`)); } else { console.error(chalk_1.default.red(`${figures_1.default.cross} An unknown build error occurred`)); } process.exit(1); } }); // Startup command - راه‌اندازی خودکار هنگام بوت program .command('startup') .description('Generate startup script for system boot') .option('--user <user>', 'User to run processes as') .action(async (options) => { try { const user = options.user || require('os').userInfo().username; const homeDir = require('os').homedir(); const neexPath = process.argv[1]; // Path to neex executable const systemdService = `[Unit] Description=Neex Process Manager After=network.target [Service] Type=forking User=${user} WorkingDirectory=${homeDir} ExecStart=${neexPath} resurrect ExecReload=${neexPath} restart all ExecStop=${neexPath} stop all Restart=on-failure RestartSec=5 [Install] WantedBy=multi-user.target`; const servicePath = '/etc/systemd/system/neex.service'; console.log(chalk_1.default.blue(`${figures_1.default.info} Generating startup configuration...`)); console.log(chalk_1.default.yellow(`${figures_1.default.warning} This requires sudo privileges`)); console.log('\nSystemd service file content:'); console.log(chalk_1.default.gray('─'.repeat(40))); console.log(systemdService); console.log(chalk_1.default.gray('─'.repeat(40))); console.log(`\n${chalk_1.default.bold('To enable startup on boot, run:')}`); console.log(chalk_1.default.cyan(`sudo tee ${servicePath} << 'EOF'`)); console.log(systemdService); console.log(chalk_1.default.cyan('EOF')); console.log(chalk_1.default.cyan('sudo systemctl daemon-reload')); console.log(chalk_1.default.cyan('sudo systemctl enable neex')); console.log(chalk_1.default.cyan('sudo systemctl start neex')); console.log(`\n${chalk_1.default.bold('To check status:')}`); console.log(chalk_1.default.cyan('sudo systemctl status neex')); } catch (error) { if (error instanceof Error) { console.error(chalk_1.default.red(`${figures_1.default.cross} Startup Error: ${error.message}`)); } else { console.error(chalk_1.default.red(`${figures_1.default.cross} An unknown startup error occurred`)); } process.exit(1); } }); // Return cleanup function for process manager return { getProcessManager: () => processManager, cleanupProcess: async () => { if (processManager) { await processManager.dispose(); } } }; } exports.addProcessCommands = addProcessCommands;