neex 0.1.6 → 0.1.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/src/cli.js CHANGED
@@ -1,716 +1,50 @@
1
1
  "use strict";
2
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
- if (k2 === undefined) k2 = k;
4
- var desc = Object.getOwnPropertyDescriptor(m, k);
5
- if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
- desc = { enumerable: true, get: function() { return m[k]; } };
7
- }
8
- Object.defineProperty(o, k2, desc);
9
- }) : (function(o, m, k, k2) {
10
- if (k2 === undefined) k2 = k;
11
- o[k2] = m[k];
12
- }));
13
- var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
- Object.defineProperty(o, "default", { enumerable: true, value: v });
15
- }) : function(o, v) {
16
- o["default"] = v;
17
- });
18
- var __importStar = (this && this.__importStar) || function (mod) {
19
- if (mod && mod.__esModule) return mod;
20
- var result = {};
21
- if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
- __setModuleDefault(result, mod);
23
- return result;
24
- };
25
2
  var __importDefault = (this && this.__importDefault) || function (mod) {
26
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
27
4
  };
28
5
  Object.defineProperty(exports, "__esModule", { value: true });
29
- // src/cli.ts - Enhanced version with Nodemon and PM2 functionality
6
+ // src/cli.ts - Main CLI file (refactored)
30
7
  const commander_1 = require("commander");
31
- const index_js_1 = require("./index.js");
32
- const dev_runner_js_1 = require("./dev-runner.js");
33
- const process_manager_js_1 = require("./process-manager.js");
8
+ const index_js_1 = require("./commands/index.js");
34
9
  const chalk_1 = __importDefault(require("chalk"));
35
10
  const figures_1 = __importDefault(require("figures"));
36
- const path = __importStar(require("path"));
37
- const fs = __importStar(require("fs/promises")); // Added for reading package.json
38
11
  const { version } = require('../../package.json');
39
- // Helper function to find default command from package.json
40
- async function findDefaultCommand() {
41
- var _a, _b;
42
- try {
43
- const packageJsonPath = path.join(process.cwd(), 'package.json');
44
- await fs.access(packageJsonPath);
45
- const packageJsonContent = await fs.readFile(packageJsonPath, 'utf-8');
46
- const packageJson = JSON.parse(packageJsonContent);
47
- if ((_a = packageJson.scripts) === null || _a === void 0 ? void 0 : _a.dev) {
48
- console.log(chalk_1.default.blue(`${figures_1.default.info} No command provided. Using "dev" script from package.json: npm run dev`));
49
- return 'npm run dev';
50
- }
51
- if ((_b = packageJson.scripts) === null || _b === void 0 ? void 0 : _b.start) {
52
- console.log(chalk_1.default.blue(`${figures_1.default.info} No command provided. Using "start" script from package.json: npm run start`));
53
- return 'npm run start';
54
- }
55
- if (packageJson.main) {
56
- const mainFile = packageJson.main;
57
- const mainFilePath = path.resolve(process.cwd(), mainFile);
58
- try {
59
- await fs.access(mainFilePath);
60
- if (mainFile.endsWith('.ts') || mainFile.endsWith('.mts') || mainFile.endsWith('.cts')) {
61
- console.log(chalk_1.default.blue(`${figures_1.default.info} No command or script found. Using "main" field (TypeScript): npx ts-node ${mainFile}`));
62
- return `npx ts-node ${mainFile}`;
63
- }
64
- else {
65
- console.log(chalk_1.default.blue(`${figures_1.default.info} No command or script found. Using "main" field (JavaScript): node ${mainFile}`));
66
- return `node ${mainFile}`;
67
- }
68
- }
69
- catch (e) {
70
- // Main file doesn't exist, do nothing, will fall through to return null
71
- }
72
- }
73
- return null;
74
- }
75
- catch (error) {
76
- // package.json doesn't exist or other error, do nothing
77
- return null;
78
- }
79
- }
80
12
  function cli() {
81
13
  const program = new commander_1.Command();
82
- let cleanupRunner = null;
83
- let devRunner = null;
84
- let processManager = null;
14
+ // Initialize cleanup handlers
15
+ const cleanupHandlers = [];
85
16
  program
86
17
  .name('neex')
87
18
  .description('Professional script runner with nodemon and PM2 functionality')
88
19
  .version(version);
89
- // Main command for sequential execution (similar to run-s)
90
- program
91
- .command('run <commands...>')
92
- .alias('s')
93
- .description('Run commands sequentially')
94
- .option('-c, --no-color', 'Disable colored output')
95
- .option('-t, --no-timing', 'Hide timing information')
96
- .option('-p, --no-prefix', 'Hide command prefix')
97
- .option('-s, --stop-on-error', 'Stop on first error')
98
- .option('-o, --no-output', 'Hide command output')
99
- .option('-m, --minimal', 'Use minimal output format')
100
- .action(async (commands, options) => {
101
- try {
102
- await (0, index_js_1.run)(commands, {
103
- parallel: false,
104
- color: options.color,
105
- showTiming: options.timing,
106
- prefix: options.prefix,
107
- stopOnError: options.stopOnError,
108
- printOutput: options.output,
109
- minimalOutput: options.minimal,
110
- registerCleanup: (cleanup) => { cleanupRunner = cleanup; }
111
- });
112
- }
113
- catch (error) {
114
- if (error instanceof Error) {
115
- console.error(chalk_1.default.red(`${figures_1.default.cross} Error: ${error.message}`));
116
- }
117
- else {
118
- console.error(chalk_1.default.red(`${figures_1.default.cross} An unknown error occurred`));
119
- }
120
- process.exit(1);
121
- }
122
- });
123
- // runx command: parallel execution by default (with alias 'p'), can run sequentially with -q
124
- program
125
- .command('px <commands...>', { isDefault: true })
126
- .description('Run commands in parallel (default) or sequentially with -q. This is the default command.')
127
- .option('-c, --no-color', 'Disable colored output')
128
- .option('-t, --no-timing', 'Hide timing information')
129
- .option('-p, --no-prefix', 'Hide command prefix')
130
- .option('-s, --stop-on-error', 'Stop on first error')
131
- .option('-o, --no-output', 'Hide command output')
132
- .option('-m, --minimal', 'Use minimal output format')
133
- .option('-x, --max-parallel <number>', 'Maximum number of parallel processes', parseInt)
134
- .option('-q, --sequential', 'Run commands sequentially instead of in parallel')
135
- .option('--retry <count>', 'Number of times to retry a failed command', parseInt)
136
- .option('--retry-delay <ms>', 'Delay in milliseconds between retries', parseInt)
137
- .action(async (commands, options) => {
138
- try {
139
- await (0, index_js_1.run)(commands, {
140
- parallel: !options.sequential,
141
- maxParallel: options.maxParallel,
142
- color: options.color,
143
- showTiming: options.timing,
144
- prefix: options.prefix,
145
- stopOnError: options.stopOnError,
146
- printOutput: options.output,
147
- minimalOutput: options.minimal,
148
- retry: options.retry,
149
- retryDelay: options.retryDelay,
150
- registerCleanup: (cleanup) => { cleanupRunner = cleanup; }
151
- });
152
- }
153
- catch (error) {
154
- if (error instanceof Error) {
155
- console.error(chalk_1.default.red(`${figures_1.default.cross} Error: ${error.message}`));
156
- }
157
- else {
158
- console.error(chalk_1.default.red(`${figures_1.default.cross} An unknown error occurred`));
159
- }
160
- process.exit(1);
161
- }
162
- });
163
- // Servers command specifically optimized for running web servers
164
- program
165
- .command('servers <commands...>')
166
- .alias('srv')
167
- .description('Run multiple servers with optimized output for API, frontend, etc.')
168
- .option('-c, --no-color', 'Disable colored output')
169
- .option('-t, --no-timing', 'Hide timing information')
170
- .option('-p, --no-prefix', 'Hide command prefix')
171
- .option('-s, --stop-on-error', 'Stop when any server crashes')
172
- .option('-x, --max-parallel <number>', 'Maximum number of parallel servers', parseInt)
173
- .option('-g, --group-output', 'Group outputs by server')
174
- .action(async (commands, options) => {
175
- try {
176
- console.log(chalk_1.default.blue(`${figures_1.default.info} Starting servers in parallel mode...`));
177
- await (0, index_js_1.run)(commands, {
178
- parallel: true,
179
- maxParallel: options.maxParallel,
180
- color: options.color,
181
- showTiming: options.timing,
182
- prefix: options.prefix,
183
- stopOnError: options.stopOnError,
184
- printOutput: true,
185
- registerCleanup: (cleanup) => { cleanupRunner = cleanup; },
186
- groupOutput: options.groupOutput,
187
- isServerMode: true
188
- });
189
- }
190
- catch (error) {
191
- if (error instanceof Error) {
192
- console.error(chalk_1.default.red(`${figures_1.default.cross} Server Error: ${error.message}`));
193
- }
194
- else {
195
- console.error(chalk_1.default.red(`${figures_1.default.cross} An unknown server error occurred`));
196
- }
197
- process.exit(1);
198
- }
199
- });
200
- // Watch command (Nodemon functionality)
201
- program
202
- .command('watch [commands...]') // Made commands optional
203
- .alias('w')
204
- .description('Run commands with file watching (nodemon functionality)')
205
- .option('-c, --no-color', 'Disable colored output')
206
- .option('-t, --no-timing', 'Hide timing information')
207
- .option('-p, --no-prefix', 'Hide command prefix')
208
- .option('-s, --stop-on-error', 'Stop on first error')
209
- .option('-o, --no-output', 'Hide command output')
210
- .option('-m, --minimal', 'Use minimal output format')
211
- .option('-w, --watch <paths...>', 'Paths to watch (default: current directory)')
212
- .option('-i, --ignore <patterns...>', 'Patterns to ignore')
213
- .option('-e, --ext <extensions...>', 'File extensions to watch (default: js,mjs,json,ts,tsx,jsx)')
214
- .option('-d, --delay <ms>', 'Delay before restart in milliseconds', parseInt)
215
- .option('--clear', 'Clear console on restart')
216
- .option('--verbose', 'Verbose output')
217
- .option('--signal <signal>', 'Signal to send to processes on restart', 'SIGTERM')
218
- .action(async (commands, options) => {
219
- try {
220
- let effectiveCommands = commands;
221
- if (!effectiveCommands || effectiveCommands.length === 0) {
222
- const foundCommand = await findDefaultCommand();
223
- if (foundCommand) {
224
- effectiveCommands = [foundCommand];
225
- console.log(chalk_1.default.blue(`${figures_1.default.info} No command specified for 'neex w', using default: "${foundCommand}"`));
226
- }
227
- else {
228
- console.error(chalk_1.default.red(`${figures_1.default.cross} No command specified for 'neex w' and no default script (dev, start) or main file found in package.json.`));
229
- console.error(chalk_1.default.yellow(`${figures_1.default.pointer} Please specify a command to run (e.g., neex w "npm run dev") or define a "dev" or "start" script in your package.json.`));
230
- process.exit(1);
231
- }
232
- }
233
- else { // At least one command/argument is provided
234
- const firstArg = effectiveCommands[0];
235
- const remainingArgs = effectiveCommands.slice(1);
236
- const isLikelyCommandOrScript = firstArg.includes(' ') || firstArg.startsWith('npm') || firstArg.startsWith('yarn') || firstArg.startsWith('pnpm');
237
- if (!isLikelyCommandOrScript) {
238
- const filePath = path.resolve(process.cwd(), firstArg);
239
- try {
240
- await fs.access(filePath); // Check if file exists
241
- let commandToExecute = '';
242
- if (firstArg.endsWith('.js') || firstArg.endsWith('.mjs') || firstArg.endsWith('.cjs')) {
243
- commandToExecute = `node ${firstArg}`;
244
- console.log(chalk_1.default.blue(`${figures_1.default.info} Detected .js file, prepending with node.`));
245
- }
246
- else if (firstArg.endsWith('.ts') || firstArg.endsWith('.mts') || firstArg.endsWith('.cts')) {
247
- commandToExecute = `npx ts-node ${firstArg}`;
248
- console.log(chalk_1.default.blue(`${figures_1.default.info} Detected .ts file, prepending with npx ts-node.`));
249
- }
250
- if (commandToExecute) {
251
- effectiveCommands = [commandToExecute, ...remainingArgs];
252
- console.log(chalk_1.default.cyan(`${figures_1.default.pointer} Executing: ${effectiveCommands.join(' ')}`));
253
- }
254
- else {
255
- // Not a .js or .ts file, or file doesn't exist but doesn't look like a command either.
256
- // We'll let it try to run as is. If it was meant to be a file, it will likely fail.
257
- // If it was a command like 'echo', it will run.
258
- console.log(chalk_1.default.yellow(`${figures_1.default.warning} First argument "${firstArg}" is not a recognized .js/.ts file and doesn't look like a script. Attempting to run as is.`));
259
- }
260
- }
261
- catch (e) {
262
- // File doesn't exist. Could be a command like 'echo foo' where 'echo' is firstArg.
263
- // Or could be 'my-script --arg' where 'my-script' is not found.
264
- // We'll let it try to run as is. DevRunner will handle if the command is not found.
265
- console.log(chalk_1.default.yellow(`${figures_1.default.warning} File "${firstArg}" not found. Attempting to run as command.`));
266
- }
267
- }
268
- // If isLikelyCommandOrScript is true, or if the file auto-detection didn't apply,
269
- // effectiveCommands remains as the user provided it (joined later by DevRunner).
270
- }
271
- console.log(chalk_1.default.blue(`${figures_1.default.info} Starting development server with file watching (neex w) for command(s): ${effectiveCommands.map(cmd => `"${cmd}"`).join(' && ')}...`));
272
- const watchPaths = options.watch || ['./'];
273
- const ignorePatterns = options.ignore || [
274
- 'node_modules/**', '.git/**', '*.log', 'dist/**', 'build/**',
275
- 'coverage/**', '.nyc_output/**', '*.tmp', '*.temp'
276
- ];
277
- const extensions = options.ext || ['js', 'mjs', 'json', 'ts', 'tsx', 'jsx'];
278
- devRunner = new dev_runner_js_1.DevRunner({
279
- runnerName: 'neex w',
280
- parallel: false,
281
- color: options.color,
282
- showTiming: options.timing,
283
- prefix: options.prefix,
284
- stopOnError: options.stopOnError,
285
- printOutput: options.output,
286
- minimalOutput: options.minimal,
287
- watch: watchPaths,
288
- ignore: ignorePatterns,
289
- ext: extensions,
290
- delay: options.delay || 1000,
291
- clearConsole: options.clear,
292
- verbose: options.verbose,
293
- signal: options.signal,
294
- restartOnChange: true,
295
- groupOutput: false,
296
- isServerMode: false
297
- });
298
- await devRunner.start(effectiveCommands);
299
- }
300
- catch (error) {
301
- if (error instanceof Error) {
302
- console.error(chalk_1.default.red(`${figures_1.default.cross} Watch Error: ${error.message}`));
303
- }
304
- else {
305
- console.error(chalk_1.default.red(`${figures_1.default.cross} An unknown watch error occurred`));
306
- }
307
- process.exit(1);
308
- }
309
- });
310
- // Process management commands
311
- // Start command
312
- program
313
- .command('start <script>')
314
- .description('Start a new process')
315
- .option('-n, --name <name>', 'Process name')
316
- .option('-i, --instances <number>', 'Number of instances', parseInt)
317
- .option('--cwd <path>', 'Working directory')
318
- .option('--env <env>', 'Environment variables (JSON string)')
319
- .option('--no-autorestart', 'Disable auto-restart')
320
- .option('--max-restarts <number>', 'Maximum restarts', parseInt)
321
- .option('--restart-delay <ms>', 'Restart delay in ms', parseInt)
322
- .option('--watch', 'Enable file watching')
323
- .option('--ignore-watch <patterns...>', 'Patterns to ignore when watching')
324
- .option('--max-memory <size>', 'Max memory before restart (e.g., 1G, 500M)')
325
- .action(async (script, options) => {
326
- try {
327
- if (!processManager) {
328
- processManager = new process_manager_js_1.ProcessManager();
329
- }
330
- const config = {
331
- id: '',
332
- name: options.name || path.basename(script, path.extname(script)),
333
- script,
334
- cwd: options.cwd,
335
- env: options.env ? JSON.parse(options.env) : undefined,
336
- instances: options.instances || 1,
337
- autorestart: options.autorestart !== false,
338
- max_restarts: options.maxRestarts || 10,
339
- restart_delay: options.restartDelay || 1000,
340
- watch: options.watch || false,
341
- ignore_watch: options.ignoreWatch,
342
- max_memory_restart: options.maxMemory
343
- };
344
- const id = await processManager.start(config);
345
- console.log(chalk_1.default.green(`${figures_1.default.tick} Process started with ID: ${id}`));
346
- }
347
- catch (error) {
348
- if (error instanceof Error) {
349
- console.error(chalk_1.default.red(`${figures_1.default.cross} Start Error: ${error.message}`));
350
- }
351
- else {
352
- console.error(chalk_1.default.red(`${figures_1.default.cross} An unknown start error occurred`));
353
- }
354
- process.exit(1);
355
- }
356
- });
357
- // Stop command
358
- program
359
- .command('stop <id>')
360
- .description('Stop a process')
361
- .action(async (id) => {
362
- try {
363
- if (!processManager) {
364
- processManager = new process_manager_js_1.ProcessManager();
365
- await processManager.load();
366
- }
367
- if (id === 'all') {
368
- await processManager.stopAll();
369
- console.log(chalk_1.default.green(`${figures_1.default.tick} All processes stopped`));
370
- }
371
- else {
372
- await processManager.stop(id);
373
- console.log(chalk_1.default.green(`${figures_1.default.tick} Process ${id} stopped`));
374
- }
375
- }
376
- catch (error) {
377
- if (error instanceof Error) {
378
- console.error(chalk_1.default.red(`${figures_1.default.cross} Stop Error: ${error.message}`));
379
- }
380
- else {
381
- console.error(chalk_1.default.red(`${figures_1.default.cross} An unknown stop error occurred`));
382
- }
383
- process.exit(1);
384
- }
385
- });
386
- // Restart command
387
- program
388
- .command('restart <id>')
389
- .description('Restart a process')
390
- .action(async (id) => {
391
- try {
392
- if (!processManager) {
393
- processManager = new process_manager_js_1.ProcessManager();
394
- await processManager.load();
395
- }
396
- if (id === 'all') {
397
- await processManager.restartAll();
398
- console.log(chalk_1.default.green(`${figures_1.default.tick} All processes restarted`));
399
- }
400
- else {
401
- await processManager.restart(id);
402
- console.log(chalk_1.default.green(`${figures_1.default.tick} Process ${id} restarted`));
403
- }
404
- }
405
- catch (error) {
406
- if (error instanceof Error) {
407
- console.error(chalk_1.default.red(`${figures_1.default.cross} Restart Error: ${error.message}`));
408
- }
409
- else {
410
- console.error(chalk_1.default.red(`${figures_1.default.cross} An unknown restart error occurred`));
411
- }
412
- process.exit(1);
413
- }
414
- });
415
- // Delete command
416
- program
417
- .command('delete <id>')
418
- .description('Delete a process')
419
- .action(async (id) => {
420
- try {
421
- if (!processManager) {
422
- processManager = new process_manager_js_1.ProcessManager();
423
- await processManager.load();
424
- }
425
- if (id === 'all') {
426
- await processManager.deleteAll();
427
- console.log(chalk_1.default.green(`${figures_1.default.tick} All processes deleted`));
428
- }
429
- else {
430
- await processManager.delete(id);
431
- console.log(chalk_1.default.green(`${figures_1.default.tick} Process ${id} deleted`));
432
- }
433
- }
434
- catch (error) {
435
- if (error instanceof Error) {
436
- console.error(chalk_1.default.red(`${figures_1.default.cross} Delete Error: ${error.message}`));
437
- }
438
- else {
439
- console.error(chalk_1.default.red(`${figures_1.default.cross} An unknown delete error occurred`));
440
- }
441
- process.exit(1);
442
- }
443
- });
444
- // List/Status command
445
- program
446
- .command('list')
447
- .alias('status')
448
- .alias('ls')
449
- .description('List all processes')
450
- .action(async () => {
451
- try {
452
- if (!processManager) {
453
- processManager = new process_manager_js_1.ProcessManager();
454
- await processManager.load();
455
- }
456
- const processes = await processManager.list();
457
- if (processes.length === 0) {
458
- console.log(chalk_1.default.yellow(`${figures_1.default.info} No processes found`));
459
- return;
460
- }
461
- // Print table header
462
- console.log('\n' + chalk_1.default.bold('Process Management Status'));
463
- console.log(chalk_1.default.gray('─'.repeat(80)));
464
- const header = `${chalk_1.default.bold('ID'.padEnd(15))} ${chalk_1.default.bold('Name'.padEnd(20))} ${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')}`;
465
- console.log(header);
466
- console.log(chalk_1.default.gray('─'.repeat(80)));
467
- // Print process information
468
- processes.forEach(proc => {
469
- const statusColor = proc.status === 'online' ? chalk_1.default.green :
470
- proc.status === 'stopped' ? chalk_1.default.gray :
471
- proc.status === 'errored' ? chalk_1.default.red : chalk_1.default.yellow;
472
- const uptime = formatUptime(proc.uptime);
473
- const pid = proc.pid ? proc.pid.toString() : '-';
474
- const row = `${proc.id.padEnd(15)} ${proc.name.padEnd(20)} ${statusColor(proc.status.padEnd(10))} ${pid.padEnd(8)} ${uptime.padEnd(10)} ${proc.restarts}`;
475
- console.log(row);
476
- });
477
- console.log(chalk_1.default.gray('─'.repeat(80)));
478
- console.log(`\n${chalk_1.default.blue(`${figures_1.default.info} Total: ${processes.length} processes`)}`);
479
- }
480
- catch (error) {
481
- if (error instanceof Error) {
482
- console.error(chalk_1.default.red(`${figures_1.default.cross} List Error: ${error.message}`));
483
- }
484
- else {
485
- console.error(chalk_1.default.red(`${figures_1.default.cross} An unknown list error occurred`));
486
- }
487
- process.exit(1);
488
- }
489
- });
490
- // Logs command
491
- program
492
- .command('logs [id]')
493
- .description('Show process logs')
494
- .option('-f, --follow', 'Follow log output')
495
- .option('-n, --lines <number>', 'Number of lines to show', parseInt)
496
- .action(async (id, options) => {
497
- try {
498
- if (!processManager) {
499
- processManager = new process_manager_js_1.ProcessManager();
500
- await processManager.load();
501
- }
502
- if (id) {
503
- const logs = await processManager.logs(id, options.lines || 100);
504
- if (logs.length === 0) {
505
- console.log(chalk_1.default.yellow(`${figures_1.default.info} No logs found for process ${id}`));
506
- }
507
- else {
508
- logs.forEach(log => console.log(log));
509
- }
510
- }
511
- else {
512
- console.log(chalk_1.default.yellow(`${figures_1.default.info} Please specify a process ID`));
513
- }
514
- if (options.follow) {
515
- console.log(chalk_1.default.blue(`${figures_1.default.info} Following logs... Press Ctrl+C to stop`));
516
- // TODO: Implement log following
517
- }
518
- }
519
- catch (error) {
520
- if (error instanceof Error) {
521
- console.error(chalk_1.default.red(`${figures_1.default.cross} Logs Error: ${error.message}`));
522
- }
523
- else {
524
- console.error(chalk_1.default.red(`${figures_1.default.cross} An unknown logs error occurred`));
525
- }
526
- process.exit(1);
527
- }
528
- });
529
- // Save command
530
- program
531
- .command('save')
532
- .description('Save current process list')
533
- .action(async () => {
534
- try {
535
- if (!processManager) {
536
- processManager = new process_manager_js_1.ProcessManager();
537
- await processManager.load();
538
- }
539
- await processManager.save();
540
- console.log(chalk_1.default.green(`${figures_1.default.tick} Process list saved`));
541
- }
542
- catch (error) {
543
- if (error instanceof Error) {
544
- console.error(chalk_1.default.red(`${figures_1.default.cross} Save Error: ${error.message}`));
545
- }
546
- else {
547
- console.error(chalk_1.default.red(`${figures_1.default.cross} An unknown save error occurred`));
548
- }
549
- process.exit(1);
550
- }
551
- });
552
- // Startup command (placeholder for system startup configuration)
553
- program
554
- .command('startup')
555
- .description('Generate startup script')
556
- .action(() => {
557
- console.log(chalk_1.default.blue(`${figures_1.default.info} Startup script generation:`));
558
- console.log('\nTo start neex processes on system boot, you can:');
559
- console.log('1. Create a systemd service (Linux)');
560
- console.log('2. Use launchd (macOS)');
561
- console.log('3. Use Windows Service (Windows)');
562
- console.log('\nExample systemd service file:');
563
- console.log(chalk_1.default.gray(`
564
- [Unit]
565
- Description=Neex Process Manager
566
- After=network.target
567
-
568
- [Service]
569
- Type=simple
570
- User=your-user
571
- WorkingDirectory=/path/to/your/project
572
- ExecStart=/usr/local/bin/neex pm2 resurrect
573
- Restart=always
574
-
575
- [Install]
576
- WantedBy=multi-user.target
577
- `));
578
- });
579
- // Resurrect command (start saved processes)
580
- program
581
- .command('resurrect')
582
- .description('Resurrect previously saved processes')
583
- .action(async () => {
584
- try {
585
- if (!processManager) {
586
- processManager = new process_manager_js_1.ProcessManager();
587
- }
588
- await processManager.load();
589
- const processes = await processManager.list();
590
- let started = 0;
591
- for (const proc of processes) {
592
- if (proc.status === 'stopped') {
593
- try {
594
- await processManager.restart(proc.id);
595
- started++;
596
- }
597
- catch (error) {
598
- console.log(chalk_1.default.yellow(`${figures_1.default.warning} Failed to start ${proc.id}: ${error.message}`));
599
- }
600
- }
601
- }
602
- console.log(chalk_1.default.green(`${figures_1.default.tick} Resurrected ${started} processes`));
603
- }
604
- catch (error) {
605
- if (error instanceof Error) {
606
- console.error(chalk_1.default.red(`${figures_1.default.cross} Resurrect Error: ${error.message}`));
607
- }
608
- else {
609
- console.error(chalk_1.default.red(`${figures_1.default.cross} An unknown resurrect error occurred`));
610
- }
611
- process.exit(1);
612
- }
613
- });
614
- // Monit command (monitoring interface)
615
- program
616
- .command('monit')
617
- .description('Launch monitoring interface')
618
- .action(async () => {
619
- try {
620
- if (!processManager) {
621
- processManager = new process_manager_js_1.ProcessManager();
622
- await processManager.load();
623
- }
624
- console.log(chalk_1.default.blue(`${figures_1.default.info} Starting monitoring interface...`));
625
- console.log(chalk_1.default.yellow(`${figures_1.default.warning} Press 'q' to quit, 'r' to refresh`));
626
- // Simple monitoring loop
627
- const monitorLoop = async () => {
628
- console.clear();
629
- console.log(chalk_1.default.bold.blue('Neex Process Monitor'));
630
- console.log(chalk_1.default.gray('─'.repeat(80)));
631
- const processes = await processManager.list();
632
- if (processes.length === 0) {
633
- console.log(chalk_1.default.yellow(`${figures_1.default.info} No processes running`));
634
- }
635
- else {
636
- processes.forEach(proc => {
637
- const statusColor = proc.status === 'online' ? chalk_1.default.green :
638
- proc.status === 'stopped' ? chalk_1.default.gray :
639
- proc.status === 'errored' ? chalk_1.default.red : chalk_1.default.yellow;
640
- console.log(`${statusColor('●')} ${proc.name} (${proc.id}) - ${statusColor(proc.status)}`);
641
- console.log(` PID: ${proc.pid || 'N/A'} | Uptime: ${formatUptime(proc.uptime)} | Restarts: ${proc.restarts}`);
642
- console.log();
643
- });
644
- }
645
- console.log(chalk_1.default.gray('─'.repeat(80)));
646
- console.log(chalk_1.default.blue(`Last updated: ${new Date().toLocaleTimeString()}`));
647
- };
648
- // Initial display
649
- await monitorLoop();
650
- // Set up keyboard input handling
651
- process.stdin.setRawMode(true);
652
- process.stdin.resume();
653
- process.stdin.setEncoding('utf8');
654
- const interval = setInterval(monitorLoop, 5000);
655
- process.stdin.on('data', (key) => {
656
- if (key.toString() === 'q' || key.toString() === '\u0003') { // 'q' or Ctrl+C
657
- clearInterval(interval);
658
- process.stdin.setRawMode(false);
659
- console.log('\n' + chalk_1.default.green(`${figures_1.default.tick} Monitoring stopped`));
660
- process.exit(0);
661
- }
662
- else if (key.toString() === 'r') {
663
- monitorLoop();
664
- }
665
- });
666
- }
667
- catch (error) {
668
- if (error instanceof Error) {
669
- console.error(chalk_1.default.red(`${figures_1.default.cross} Monit Error: ${error.message}`));
670
- }
671
- else {
672
- console.error(chalk_1.default.red(`${figures_1.default.cross} An unknown monit error occurred`));
673
- }
674
- process.exit(1);
675
- }
676
- });
20
+ // Add all command groups
21
+ (0, index_js_1.addRunCommands)(program);
22
+ (0, index_js_1.addServerCommands)(program);
23
+ const devCommands = (0, index_js_1.addDevCommands)(program);
24
+ cleanupHandlers.push(devCommands.cleanupDev);
25
+ const processCommands = (0, index_js_1.addProcessCommands)(program);
26
+ cleanupHandlers.push(processCommands.cleanupProcess);
677
27
  program.parse(process.argv);
678
28
  // Show help if no commands specified
679
29
  if (program.args.length === 0) {
680
30
  program.help();
681
31
  }
682
32
  // Graceful shutdown handling
683
- const handleSignal = (signal) => {
33
+ const handleSignal = async (signal) => {
684
34
  console.log(`\n${chalk_1.default.yellow(`${figures_1.default.warning} Received ${signal}. Cleaning up...`)}`);
685
- if (devRunner && devRunner.isActive()) {
686
- devRunner.stop();
687
- }
688
- if (cleanupRunner) {
689
- cleanupRunner();
690
- }
691
- if (processManager) {
692
- processManager.dispose();
35
+ // Run all cleanup handlers
36
+ for (const cleanup of cleanupHandlers) {
37
+ try {
38
+ await cleanup();
39
+ }
40
+ catch (error) {
41
+ console.error(`Cleanup error:`, error);
42
+ }
693
43
  }
694
44
  setTimeout(() => process.exit(0), 500);
695
45
  };
696
- process.on('SIGINT', () => handleSignal('SIGINT'));
697
- process.on('SIGTERM', () => handleSignal('SIGTERM'));
698
- process.on('SIGQUIT', () => handleSignal('SIGQUIT'));
46
+ process.on('SIGINT', () => handleSignal('SIGINT').catch(err => console.error('SIGINT handler error:', err)));
47
+ process.on('SIGTERM', () => handleSignal('SIGTERM').catch(err => console.error('SIGTERM handler error:', err)));
48
+ process.on('SIGQUIT', () => handleSignal('SIGQUIT').catch(err => console.error('SIGQUIT handler error:', err)));
699
49
  }
700
50
  exports.default = cli;
701
- // Helper function to format uptime
702
- function formatUptime(seconds) {
703
- if (seconds < 60) {
704
- return `${seconds}s`;
705
- }
706
- else if (seconds < 3600) {
707
- const minutes = Math.floor(seconds / 60);
708
- const remainingSeconds = seconds % 60;
709
- return `${minutes}m ${remainingSeconds}s`;
710
- }
711
- else {
712
- const hours = Math.floor(seconds / 3600);
713
- const minutes = Math.floor((seconds % 3600) / 60);
714
- return `${hours}h ${minutes}m`;
715
- }
716
- }