neex 0.6.23 → 0.6.25

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.
@@ -27,6 +27,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
27
27
  };
28
28
  Object.defineProperty(exports, "__esModule", { value: true });
29
29
  exports.addStartCommands = void 0;
30
+ const start_manager_js_1 = require("../start-manager.js");
30
31
  const chalk_1 = __importDefault(require("chalk"));
31
32
  const figures_1 = __importDefault(require("figures"));
32
33
  const path = __importStar(require("path"));
@@ -90,14 +91,9 @@ async function getStartCommand(filePath, showInfo) {
90
91
  }
91
92
  function addStartCommands(program) {
92
93
  let startManager = null;
93
- const cleanupStart = () => {
94
- if (startManager) {
95
- startManager.stop();
96
- startManager = null;
97
- }
98
- };
94
+ // Start command - run applications in production mode
99
95
  program
100
- .command('start <file>')
96
+ .command('start <file>') // Made file mandatory
101
97
  .alias('s')
102
98
  .description('Start JavaScript/TypeScript applications in production mode')
103
99
  .option('-c, --no-color', 'Disable colored output')
@@ -162,17 +158,97 @@ function addStartCommands(program) {
162
158
  // Log configuration only if --info flag is set
163
159
  if (showInfo) {
164
160
  console.log(chalk_1.default.blue(`${figures_1.default.info} neex start: Configuration:`));
165
- console;
161
+ console.log(chalk_1.default.blue(` ${figures_1.default.arrowRight} Target: ${chalk_1.default.cyan(file)}`));
162
+ console.log(chalk_1.default.blue(` ${figures_1.default.arrowRight} Runtime: ${chalk_1.default.cyan(startConfig.runtime)}`));
163
+ console.log(chalk_1.default.blue(` ${figures_1.default.arrowRight} Process name: ${chalk_1.default.cyan(startConfig.processName)}`));
164
+ console.log(chalk_1.default.blue(` ${figures_1.default.arrowRight} Environment: ${chalk_1.default.cyan(options.env)}`));
165
+ console.log(chalk_1.default.blue(` ${figures_1.default.arrowRight} Watch mode: ${chalk_1.default.cyan(options.watch ? 'Yes' : 'No')}`));
166
+ console.log(chalk_1.default.blue(` ${figures_1.default.arrowRight} Cluster mode: ${chalk_1.default.cyan(options.cluster ? 'Yes' : 'No')}`));
167
+ if (options.cluster) {
168
+ console.log(chalk_1.default.blue(` ${figures_1.default.arrowRight} Cluster instances: ${chalk_1.default.cyan(options.clusterInstances || 'auto')}`));
169
+ }
170
+ if (options.watch) {
171
+ console.log(chalk_1.default.blue(` ${figures_1.default.arrowRight} Watch paths: ${chalk_1.default.cyan(watchPaths.join(', '))}`));
172
+ console.log(chalk_1.default.blue(` ${figures_1.default.arrowRight} Extensions: ${chalk_1.default.cyan(extensions.join(', '))}`));
173
+ console.log(chalk_1.default.blue(` ${figures_1.default.arrowRight} Restart delay: ${chalk_1.default.cyan(options.delay || 1000)}ms`));
174
+ }
175
+ if (options.maxRestarts) {
176
+ console.log(chalk_1.default.blue(` ${figures_1.default.arrowRight} Max restarts: ${chalk_1.default.cyan(options.maxRestarts)}`));
177
+ }
178
+ if (options.memoryLimit) {
179
+ console.log(chalk_1.default.blue(` ${figures_1.default.arrowRight} Memory limit: ${chalk_1.default.cyan(options.memoryLimit)}MB`));
180
+ }
181
+ if (options.cpuLimit) {
182
+ console.log(chalk_1.default.blue(` ${figures_1.default.arrowRight} CPU limit: ${chalk_1.default.cyan(options.cpuLimit)}%`));
183
+ }
184
+ if (options.verbose) {
185
+ console.log(chalk_1.default.blue(`${figures_1.default.info} neex start: Verbose mode enabled - showing detailed logs`));
186
+ }
187
+ console.log(chalk_1.default.green(`${figures_1.default.tick} neex start: Starting production application server...`));
188
+ console.log(chalk_1.default.green(`${figures_1.default.tick} neex start: Launching ${chalk_1.default.cyan(startConfig.processName)} in ${chalk_1.default.cyan(options.env)} mode...`));
189
+ console.log(chalk_1.default.blue(`${figures_1.default.info} neex start: Press Ctrl+C to stop the application server`));
190
+ console.log(chalk_1.default.gray(`${'='.repeat(60)}`));
166
191
  }
192
+ // Create StartManager instance
193
+ startManager = new start_manager_js_1.StartManager({
194
+ runnerName: 'neex start',
195
+ targetFile: file,
196
+ command: startConfig.command,
197
+ processName: startConfig.processName,
198
+ runtime: startConfig.runtime,
199
+ environment: options.env,
200
+ parallel: false,
201
+ color: options.color,
202
+ showTiming: options.timing,
203
+ prefix: options.prefix,
204
+ printOutput: options.output,
205
+ minimalOutput: options.minimal,
206
+ watch: options.watch,
207
+ watchPaths: watchPaths,
208
+ ignore: ignorePatterns,
209
+ ext: extensions,
210
+ delay: options.delay || 1000,
211
+ maxRestarts: options.maxRestarts,
212
+ restartDelay: options.restartDelay || 3000,
213
+ verbose: options.verbose,
214
+ showInfo: showInfo,
215
+ signal: options.signal,
216
+ cluster: options.cluster,
217
+ clusterInstances: options.clusterInstances,
218
+ memoryLimit: options.memoryLimit,
219
+ cpuLimit: options.cpuLimit,
220
+ groupOutput: false,
221
+ isServerMode: true,
222
+ stopOnError: false
223
+ });
224
+ // Start the application server
225
+ await startManager.start();
167
226
  }
168
227
  catch (error) {
169
- console.error(chalk_1.default.red(`${figures_1.default.cross} neex start: ${error instanceof Error ? error.message : 'Unknown error occurred'}`));
228
+ console.error(chalk_1.default.red(`${figures_1.default.cross} neex start: Fatal error occurred`));
229
+ if (error instanceof Error) {
230
+ console.error(chalk_1.default.red(`${figures_1.default.cross} Details: ${error.message}`));
231
+ if (options.verbose && error.stack) {
232
+ console.error(chalk_1.default.gray(`Stack trace:\n${error.stack}`));
233
+ }
234
+ }
235
+ else {
236
+ console.error(chalk_1.default.red(`${figures_1.default.cross} Unknown error occurred`));
237
+ }
238
+ console.error(chalk_1.default.yellow(`${figures_1.default.pointer} Try running with --verbose flag for more details`));
170
239
  process.exit(1);
171
240
  }
172
241
  });
242
+ // Return cleanup function for start manager
173
243
  return {
174
244
  getStartManager: () => startManager,
175
- cleanupStart
245
+ cleanupStart: () => {
246
+ if (startManager && startManager.isActive()) {
247
+ console.log(chalk_1.default.blue(`${figures_1.default.info} neex start: Stopping application server...`));
248
+ startManager.stop();
249
+ console.log(chalk_1.default.green(`${figures_1.default.tick} neex start: Application server stopped successfully`));
250
+ }
251
+ }
176
252
  };
177
253
  }
178
254
  exports.addStartCommands = addStartCommands;
@@ -45,9 +45,6 @@ class StartManager {
45
45
  cpuUsage: 0,
46
46
  uptime: 0
47
47
  };
48
- if (!options.targetFile || !options.command || !options.processName || !options.runtime) {
49
- throw new Error('Missing required options: targetFile, command, processName, and runtime are required');
50
- }
51
48
  const defaultOptions = {
52
49
  parallel: false,
53
50
  printOutput: true,
@@ -84,31 +81,10 @@ class StartManager {
84
81
  cluster: false,
85
82
  clusterInstances: os.cpus().length
86
83
  };
87
- // Validate numeric values
88
- const validateNumber = (value, name) => {
89
- const num = parseInt(value);
90
- if (isNaN(num) || num < 0) {
91
- throw new Error(`Invalid ${name}: must be a non-negative number`);
92
- }
93
- return num;
94
- };
95
84
  this.options = {
96
85
  ...defaultOptions,
97
- ...options,
98
- delay: validateNumber(options.delay || defaultOptions.delay, 'delay'),
99
- clusterInstances: validateNumber(options.clusterInstances || defaultOptions.clusterInstances, 'clusterInstances'),
100
- memoryLimit: options.memoryLimit ? validateNumber(options.memoryLimit, 'memoryLimit') : undefined,
101
- cpuLimit: options.cpuLimit ? validateNumber(options.cpuLimit, 'cpuLimit') : undefined,
102
- maxRestarts: options.maxRestarts ? validateNumber(options.maxRestarts, 'maxRestarts') : undefined,
103
- restartDelay: validateNumber(options.restartDelay || defaultOptions.restartDelay, 'restartDelay')
86
+ ...options
104
87
  };
105
- // Validate environment
106
- if (this.options.environment) {
107
- this.options.environment = this.options.environment.toLowerCase();
108
- if (!['production', 'development', 'staging', 'test'].includes(this.options.environment)) {
109
- throw new Error(`Invalid environment: ${this.options.environment}. Must be one of: production, development, staging, test`);
110
- }
111
- }
112
88
  }
113
89
  setupFileWatcher() {
114
90
  var _a;
@@ -195,59 +171,20 @@ class StartManager {
195
171
  logger_1.default.printLine(`${prefix} ${chalk_1.default.red(`${figures_1.default.cross} Application crashed`)}`, 'error');
196
172
  logger_1.default.printLine(`${prefix} ${chalk_1.default.yellow(`${figures_1.default.warning} Attempting restart in ${this.options.restartDelay}ms...`)}`, 'info');
197
173
  }
198
- // Check if we should restart
199
- if (!this.shouldRestart()) {
200
- if (this.options.showInfo) {
201
- logger_1.default.printLine(`${prefix} ${chalk_1.default.red(`${figures_1.default.cross} Max restarts reached (${this.options.maxRestarts}). Stopping application.`)}`, 'error');
202
- }
203
- await this.stop();
204
- return;
205
- }
206
174
  // Wait before restarting
207
175
  await new Promise(resolve => setTimeout(resolve, this.options.restartDelay));
208
- try {
209
- await this.gracefulRestart();
210
- }
211
- catch (error) {
212
- logger_1.default.printLine(`Failed to restart application: ${error.message}`, 'error');
213
- if (this.options.stopOnError) {
214
- await this.stop();
215
- }
216
- }
176
+ await this.gracefulRestart();
217
177
  }
218
178
  collectProcessStats() {
219
- var _a;
220
179
  if (!this.options.showInfo) {
221
180
  return;
222
181
  }
223
- try {
224
- const memUsage = process.memoryUsage();
225
- this.processStats.memoryUsage = Math.round(memUsage.heapUsed / 1024 / 1024);
226
- this.processStats.uptime = Math.floor((Date.now() - this.startTime.getTime()) / 1000);
227
- // More accurate CPU usage calculation
228
- const cpuUsage = process.cpuUsage();
229
- const totalCpuTime = cpuUsage.user + cpuUsage.system;
230
- const timeDiff = Date.now() - (((_a = this.lastRestartTime) === null || _a === void 0 ? void 0 : _a.getTime()) || this.startTime.getTime());
231
- this.processStats.cpuUsage = Math.round((totalCpuTime / timeDiff) * 100);
232
- // Check resource limits
233
- if (this.options.memoryLimit && this.processStats.memoryUsage > this.options.memoryLimit) {
234
- const prefix = chalk_1.default.cyan(`[${this.options.runnerName}]`);
235
- logger_1.default.printLine(`${prefix} ${chalk_1.default.red(`${figures_1.default.warning} Memory limit exceeded: ${this.processStats.memoryUsage}MB > ${this.options.memoryLimit}MB`)}`, 'warn');
236
- if (this.options.stopOnError) {
237
- this.stop();
238
- }
239
- }
240
- if (this.options.cpuLimit && this.processStats.cpuUsage > this.options.cpuLimit) {
241
- const prefix = chalk_1.default.cyan(`[${this.options.runnerName}]`);
242
- logger_1.default.printLine(`${prefix} ${chalk_1.default.red(`${figures_1.default.warning} CPU limit exceeded: ${this.processStats.cpuUsage}% > ${this.options.cpuLimit}%`)}`, 'warn');
243
- if (this.options.stopOnError) {
244
- this.stop();
245
- }
246
- }
247
- }
248
- catch (error) {
249
- logger_1.default.printLine(`Failed to collect process stats: ${error.message}`, 'error');
250
- }
182
+ const memUsage = process.memoryUsage();
183
+ this.processStats.memoryUsage = Math.round(memUsage.heapUsed / 1024 / 1024);
184
+ this.processStats.uptime = Math.floor((Date.now() - this.startTime.getTime()) / 1000);
185
+ // Simple CPU usage approximation
186
+ const cpuUsage = process.cpuUsage();
187
+ this.processStats.cpuUsage = Math.round(((cpuUsage.user + cpuUsage.system) / 1000000) * 100) / 100;
251
188
  }
252
189
  printStartBanner() {
253
190
  var _a, _b;
@@ -382,35 +319,6 @@ class StartManager {
382
319
  logger_1.default.printLine(`${prefix} ${chalk_1.default.green(`${figures_1.default.tick} ${this.options.processName} restarted successfully`)}`, 'info');
383
320
  }
384
321
  }
385
- setupGracefulShutdown() {
386
- const handleSignal = async (signal) => {
387
- if (!this.isRunning) {
388
- return;
389
- }
390
- try {
391
- if (this.options.showInfo) {
392
- console.log(`\n${chalk_1.default.yellow(`${figures_1.default.warning} Received ${signal}. Gracefully shutting down ${this.options.processName}...`)}`);
393
- }
394
- await this.stop();
395
- process.exit(0);
396
- }
397
- catch (error) {
398
- logger_1.default.printLine(`Failed to handle ${signal}: ${error.message}`, 'error');
399
- process.exit(1);
400
- }
401
- };
402
- process.on('SIGINT', () => handleSignal('SIGINT'));
403
- process.on('SIGTERM', () => handleSignal('SIGTERM'));
404
- process.on('SIGQUIT', () => handleSignal('SIGQUIT'));
405
- process.on('uncaughtException', (error) => {
406
- logger_1.default.printLine(`Uncaught Exception: ${error.message}`, 'error');
407
- handleSignal('SIGTERM');
408
- });
409
- process.on('unhandledRejection', (reason) => {
410
- logger_1.default.printLine(`Unhandled Rejection: ${reason}`, 'error');
411
- handleSignal('SIGTERM');
412
- });
413
- }
414
322
  async stop() {
415
323
  const prefix = chalk_1.default.cyan(`[${this.options.runnerName}]`);
416
324
  if (!this.isRunning) {
@@ -420,30 +328,35 @@ class StartManager {
420
328
  logger_1.default.printLine(`${prefix} ${chalk_1.default.yellow(`${figures_1.default.warning} Stopping ${this.options.processName}...`)}`, 'info');
421
329
  }
422
330
  this.isRunning = false;
423
- try {
424
- // Stop file watcher
425
- if (this.fileWatcher) {
426
- await this.fileWatcher.stop();
427
- }
428
- // Stop application gracefully
429
- if (this.runner) {
430
- await this.runner.cleanup(this.options.signal);
431
- }
432
- // Calculate final stats
433
- const uptime = Math.floor((Date.now() - this.startTime.getTime()) / 1000);
434
- const uptimeStr = this.formatUptime(uptime);
435
- if (this.options.showInfo) {
436
- logger_1.default.printLine(`${prefix} ${chalk_1.default.green(`${figures_1.default.tick} ${this.options.processName} stopped successfully`)}`, 'info');
437
- logger_1.default.printLine(`${prefix} Final stats: ${uptimeStr} uptime, ${this.restartCount} restarts, ${this.crashCount} crashes`, 'info');
438
- }
331
+ // Stop file watcher
332
+ if (this.fileWatcher) {
333
+ this.fileWatcher.stop();
439
334
  }
440
- catch (error) {
441
- logger_1.default.printLine(`Failed to stop application: ${error.message}`, 'error');
442
- if (this.options.stopOnError) {
443
- process.exit(1);
444
- }
335
+ // Stop application gracefully
336
+ if (this.runner) {
337
+ this.runner.cleanup(this.options.signal);
338
+ }
339
+ // Calculate final stats
340
+ const uptime = Math.floor((Date.now() - this.startTime.getTime()) / 1000);
341
+ const uptimeStr = this.formatUptime(uptime);
342
+ if (this.options.showInfo) {
343
+ logger_1.default.printLine(`${prefix} ${chalk_1.default.green(`${figures_1.default.tick} ${this.options.processName} stopped successfully`)}`, 'info');
344
+ logger_1.default.printLine(`${prefix} Final stats: ${uptimeStr} uptime, ${this.restartCount} restarts, ${this.crashCount} crashes`, 'info');
445
345
  }
446
346
  }
347
+ setupGracefulShutdown() {
348
+ const handleSignal = (signal) => {
349
+ if (this.options.showInfo) {
350
+ console.log(`\n${chalk_1.default.yellow(`${figures_1.default.warning} Received ${signal}. Gracefully shutting down ${this.options.processName}...`)}`);
351
+ }
352
+ this.stop().then(() => {
353
+ process.exit(0);
354
+ });
355
+ };
356
+ process.on('SIGINT', () => handleSignal('SIGINT'));
357
+ process.on('SIGTERM', () => handleSignal('SIGTERM'));
358
+ process.on('SIGQUIT', () => handleSignal('SIGQUIT'));
359
+ }
447
360
  isActive() {
448
361
  return this.isRunning;
449
362
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "neex",
3
- "version": "0.6.23",
3
+ "version": "0.6.25",
4
4
  "description": "The Modern Build System for Polyrepo-in-Monorepo Architecture",
5
5
  "main": "dist/src/index.js",
6
6
  "types": "dist/src/index.d.ts",