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
JavaScript
;
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;