neex 0.6.22 → 0.6.24

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.
@@ -42,12 +42,12 @@ class BuildManager {
42
42
  this.startTime = new Date();
43
43
  const defaultOptions = {
44
44
  parallel: false,
45
- printOutput: true,
45
+ printOutput: false,
46
46
  color: true,
47
- showTiming: true,
48
- prefix: true,
49
- stopOnError: false,
50
- minimalOutput: false,
47
+ showTiming: false,
48
+ prefix: false,
49
+ stopOnError: true,
50
+ minimalOutput: true,
51
51
  groupOutput: false,
52
52
  isServerMode: false,
53
53
  watch: false,
@@ -96,8 +96,8 @@ class BuildManager {
96
96
  });
97
97
  }
98
98
  async handleFileChange(event) {
99
- const prefix = chalk_1.default.cyan(`[${this.options.runnerName}]`);
100
99
  if (this.options.showInfo) {
100
+ const prefix = chalk_1.default.cyan(`[${this.options.runnerName}]`);
101
101
  logger_1.default.printLine(`${prefix} File changed: ${chalk_1.default.yellow(event.relativePath)}`, 'info');
102
102
  }
103
103
  await this.rebuild();
@@ -149,10 +149,13 @@ class BuildManager {
149
149
  }
150
150
  async runBuild() {
151
151
  const buildCommand = this.generateBuildCommand();
152
- // Create a modified options object for the runner
152
+ // Create a runner with clean output settings
153
153
  const runnerOptions = {
154
154
  ...this.options,
155
- customPrefix: () => `build`
155
+ printOutput: Boolean(this.options.showInfo),
156
+ showTiming: Boolean(this.options.showInfo),
157
+ prefix: Boolean(this.options.showInfo),
158
+ customPrefix: this.options.showInfo ? () => `build` : undefined
156
159
  };
157
160
  this.runner = new runner_1.Runner(runnerOptions);
158
161
  try {
@@ -169,24 +172,23 @@ class BuildManager {
169
172
  const results = await this.runner.run([buildCommand]);
170
173
  // Handle build results
171
174
  const success = results.every(result => result.success);
172
- const prefix = chalk_1.default.cyan(`[${this.options.runnerName}]`);
173
- if (success) {
174
- if (this.options.showInfo) {
175
- logger_1.default.printLine(`${prefix} ${chalk_1.default.green(`${figures_1.default.tick} Build completed successfully`)}`, 'info');
176
- }
177
- }
178
- else {
179
- if (this.options.showInfo) {
180
- logger_1.default.printLine(`${prefix} ${chalk_1.default.red(`${figures_1.default.cross} Build failed`)}`, 'error');
175
+ if (!success) {
176
+ // Only show errors, let the caller handle success message
177
+ const failedResults = results.filter(result => !result.success);
178
+ for (const result of failedResults) {
179
+ if (result.stderr) {
180
+ console.error(chalk_1.default.red(result.stderr));
181
+ }
182
+ if (result.error) {
183
+ console.error(chalk_1.default.red(result.error));
184
+ }
181
185
  }
186
+ throw new Error('Build failed');
182
187
  }
183
188
  return results;
184
189
  }
185
190
  catch (error) {
186
- if (this.options.showInfo) {
187
- logger_1.default.printLine(`Build failed: ${error.message}`, 'error');
188
- }
189
- return [];
191
+ throw error;
190
192
  }
191
193
  finally {
192
194
  this.isBuilding = false;
@@ -235,37 +237,31 @@ class BuildManager {
235
237
  this.setupFileWatcher();
236
238
  }
237
239
  // Print build banner only if showInfo is true
238
- this.printBuildBanner();
240
+ if (this.options.showInfo) {
241
+ this.printBuildBanner();
242
+ }
239
243
  // Start file watcher if enabled
240
244
  if (this.fileWatcher) {
241
245
  await this.fileWatcher.start();
242
246
  }
243
247
  // Run initial build
244
- const prefix = chalk_1.default.cyan(`[${this.options.runnerName}]`);
245
- if (this.options.showInfo) {
246
- logger_1.default.printLine(`${prefix} Starting build process...`, 'info');
247
- }
248
248
  await this.runBuild();
249
249
  // Set up graceful shutdown
250
250
  this.setupGracefulShutdown();
251
251
  if (this.options.watch) {
252
252
  if (this.options.showInfo) {
253
+ const prefix = chalk_1.default.cyan(`[${this.options.runnerName}]`);
253
254
  logger_1.default.printLine(`${prefix} Build completed. Watching for changes...`, 'info');
254
255
  logger_1.default.printLine(`${prefix} Press ${chalk_1.default.cyan('Ctrl+C')} to stop`, 'info');
255
256
  }
256
257
  }
257
- else {
258
- if (this.options.showInfo) {
259
- logger_1.default.printLine(`${prefix} Build process completed`, 'info');
260
- }
261
- }
262
258
  }
263
259
  async rebuild() {
264
- const prefix = chalk_1.default.cyan(`[${this.options.runnerName}]`);
265
260
  if (this.isBuilding) {
266
261
  return;
267
262
  }
268
263
  if (this.options.showInfo) {
264
+ const prefix = chalk_1.default.cyan(`[${this.options.runnerName}]`);
269
265
  logger_1.default.printLine(`${prefix} Rebuilding due to file changes...`, 'info');
270
266
  }
271
267
  // Stop current processes
@@ -275,19 +271,26 @@ class BuildManager {
275
271
  // Wait a moment before rebuilding
276
272
  await new Promise(resolve => setTimeout(resolve, 500));
277
273
  // Print rebuild banner only if showInfo is true
278
- this.printBuildBanner();
274
+ if (this.options.showInfo) {
275
+ this.printBuildBanner();
276
+ }
279
277
  // Run build again
280
278
  await this.runBuild();
281
279
  if (this.options.showInfo) {
280
+ const prefix = chalk_1.default.cyan(`[${this.options.runnerName}]`);
282
281
  logger_1.default.printLine(`${prefix} Rebuild completed. Watching for changes...`, 'info');
283
282
  }
283
+ else {
284
+ // Show rebuild completion even without showInfo for watch mode
285
+ console.log(chalk_1.default.green(`${figures_1.default.tick} Rebuild completed`));
286
+ }
284
287
  }
285
288
  async stop() {
286
- const prefix = chalk_1.default.cyan(`[${this.options.runnerName}]`);
287
289
  if (!this.isBuilding && !this.options.watch) {
288
290
  return;
289
291
  }
290
292
  if (this.options.showInfo) {
293
+ const prefix = chalk_1.default.cyan(`[${this.options.runnerName}]`);
291
294
  logger_1.default.printLine(`${prefix} Stopping build process...`, 'info');
292
295
  }
293
296
  // Stop file watcher
@@ -298,9 +301,10 @@ class BuildManager {
298
301
  if (this.runner) {
299
302
  this.runner.cleanup('SIGTERM');
300
303
  }
301
- const uptime = Math.floor((Date.now() - this.startTime.getTime()) / 1000);
302
- const uptimeStr = this.formatUptime(uptime);
303
304
  if (this.options.showInfo) {
305
+ const prefix = chalk_1.default.cyan(`[${this.options.runnerName}]`);
306
+ const uptime = Math.floor((Date.now() - this.startTime.getTime()) / 1000);
307
+ const uptimeStr = this.formatUptime(uptime);
304
308
  logger_1.default.printLine(`${prefix} Build process stopped after ${uptimeStr}`, 'info');
305
309
  if (this.buildCount > 0) {
306
310
  logger_1.default.printLine(`${prefix} Total builds: ${this.buildCount}`, 'info');
@@ -116,11 +116,7 @@ function addBuildCommands(program) {
116
116
  .option('--module <module>', 'Module system', 'commonjs')
117
117
  .action(async (file, options) => {
118
118
  try {
119
- const showInfo = options.info || false;
120
- if (showInfo) {
121
- console.log(chalk_1.default.blue(`${figures_1.default.info} neex build: Starting build process...`));
122
- console.log(chalk_1.default.blue(`${figures_1.default.info} neex build: Target file: ${chalk_1.default.cyan(file)}`));
123
- }
119
+ const showInfo = options.info || options.verbose || false;
124
120
  // Validate file parameter
125
121
  if (!file || file.trim() === '') {
126
122
  console.error(chalk_1.default.red(`${figures_1.default.cross} neex build: Error - No file specified!`));
@@ -130,18 +126,18 @@ function addBuildCommands(program) {
130
126
  }
131
127
  // Get build configuration
132
128
  const buildConfig = await getBuildConfig(file, options.output, showInfo);
133
- // Create BuildManager instance with all required options
134
- const buildManager = new build_manager_js_1.BuildManager({
129
+ // Create BuildManager instance with clean output settings
130
+ buildManager = new build_manager_js_1.BuildManager({
135
131
  runnerName: 'neex build',
136
132
  inputFile: file,
137
133
  outputDir: options.output,
138
134
  buildType: buildConfig.buildType,
139
135
  buildCommand: buildConfig.buildCommand,
140
136
  showInfo: showInfo,
141
- color: !options.color,
142
- showTiming: !options.timing,
137
+ color: !options.noColor,
138
+ showTiming: false,
143
139
  watch: options.watch,
144
- delay: parseInt(options.delay),
140
+ delay: parseInt(options.delay) || 1000,
145
141
  verbose: options.verbose,
146
142
  clean: options.clean,
147
143
  sourceMap: options.sourceMap,
@@ -150,56 +146,19 @@ function addBuildCommands(program) {
150
146
  parallel: false,
151
147
  groupOutput: false,
152
148
  isServerMode: false,
153
- printOutput: true,
154
- prefix: true,
155
- stopOnError: false,
156
- minimalOutput: false
149
+ printOutput: false,
150
+ prefix: false,
151
+ stopOnError: true,
152
+ minimalOutput: true // Use minimal output
157
153
  });
158
- // Setup ignore patterns for watch mode
159
- const ignorePatterns = options.ignore || [
160
- 'node_modules/**',
161
- '.git/**',
162
- '*.log',
163
- 'dist/**',
164
- 'build/**',
165
- 'coverage/**',
166
- '.nyc_output/**',
167
- '*.tmp',
168
- '*.temp',
169
- '.DS_Store',
170
- 'Thumbs.db'
171
- ];
172
- // Log configuration only if --info flag is set
173
- if (showInfo) {
174
- console.log(chalk_1.default.blue(`${figures_1.default.info} neex build: Configuration:`));
175
- console.log(chalk_1.default.blue(` ${figures_1.default.arrowRight} Input: ${chalk_1.default.cyan(file)}`));
176
- console.log(chalk_1.default.blue(` ${figures_1.default.arrowRight} Output: ${chalk_1.default.cyan(options.output)}`));
177
- console.log(chalk_1.default.blue(` ${figures_1.default.arrowRight} Build type: ${chalk_1.default.cyan(buildConfig.buildType)}`));
178
- console.log(chalk_1.default.blue(` ${figures_1.default.arrowRight} Target: ${chalk_1.default.cyan(options.target)}`));
179
- console.log(chalk_1.default.blue(` ${figures_1.default.arrowRight} Module: ${chalk_1.default.cyan(options.module)}`));
180
- console.log(chalk_1.default.blue(` ${figures_1.default.arrowRight} Watch mode: ${chalk_1.default.cyan(options.watch ? 'Yes' : 'No')}`));
181
- console.log(chalk_1.default.blue(` ${figures_1.default.arrowRight} Clean before build: ${chalk_1.default.cyan(options.clean ? 'Yes' : 'No')}`));
182
- console.log(chalk_1.default.blue(` ${figures_1.default.arrowRight} Source maps: ${chalk_1.default.cyan(options.sourceMap ? 'Yes' : 'No')}`));
183
- if (options.verbose) {
184
- console.log(chalk_1.default.blue(`${figures_1.default.info} neex build: Verbose mode enabled - showing detailed logs`));
185
- }
186
- console.log(chalk_1.default.green(`${figures_1.default.tick} neex build: Starting build process...`));
187
- console.log(chalk_1.default.gray(`${'='.repeat(60)}`));
188
- }
189
154
  // Start the build process
190
155
  try {
191
- if (showInfo) {
192
- console.log(chalk_1.default.blue(`${figures_1.default.info} neex build: Analyzing ${chalk_1.default.cyan(path.basename(file))}`));
193
- }
194
156
  await buildManager.start();
195
- if (showInfo) {
196
- console.log(chalk_1.default.green(`${figures_1.default.tick} Build completed successfully`));
197
- }
198
- else {
199
- console.log(chalk_1.default.green(`${figures_1.default.tick} Build completed`));
200
- }
157
+ // Only show success message, no extra logs
158
+ console.log(chalk_1.default.green(`${figures_1.default.tick} Build completed`));
201
159
  }
202
160
  catch (error) {
161
+ // Only show error message, no extra logs
203
162
  console.error(chalk_1.default.red(`${figures_1.default.cross} Build failed`));
204
163
  if (error instanceof Error) {
205
164
  console.error(chalk_1.default.red(`Error: ${error.message}`));
@@ -208,17 +167,14 @@ function addBuildCommands(program) {
208
167
  }
209
168
  }
210
169
  catch (error) {
211
- console.error(chalk_1.default.red(`${figures_1.default.cross} neex build: Fatal error occurred`));
170
+ // Only show fatal error, no extra logs
171
+ console.error(chalk_1.default.red(`${figures_1.default.cross} Build failed`));
212
172
  if (error instanceof Error) {
213
- console.error(chalk_1.default.red(`${figures_1.default.cross} Details: ${error.message}`));
173
+ console.error(chalk_1.default.red(`Error: ${error.message}`));
214
174
  if (options.verbose && error.stack) {
215
175
  console.error(chalk_1.default.gray(`Stack trace:\n${error.stack}`));
216
176
  }
217
177
  }
218
- else {
219
- console.error(chalk_1.default.red(`${figures_1.default.cross} Unknown error occurred`));
220
- }
221
- console.error(chalk_1.default.yellow(`${figures_1.default.pointer} Try running with --verbose flag for more details`));
222
178
  process.exit(1);
223
179
  }
224
180
  });
@@ -227,9 +183,7 @@ function addBuildCommands(program) {
227
183
  getBuildManager: () => buildManager,
228
184
  cleanupBuild: () => {
229
185
  if (buildManager && buildManager.isActive()) {
230
- console.log(chalk_1.default.blue(`${figures_1.default.info} neex build: Stopping build process...`));
231
186
  buildManager.stop();
232
- console.log(chalk_1.default.green(`${figures_1.default.tick} neex build: Build process stopped successfully`));
233
187
  }
234
188
  }
235
189
  };
@@ -91,90 +91,169 @@ async function getStartCommand(filePath, showInfo) {
91
91
  }
92
92
  function addStartCommands(program) {
93
93
  let startManager = null;
94
- const cleanupStart = () => {
95
- if (startManager) {
96
- startManager.stop();
97
- startManager = null;
98
- }
99
- };
94
+ // Start command - run applications in production mode
100
95
  program
101
96
  .command('start <file>')
102
97
  .alias('s')
103
- .description('Start a production application')
98
+ .description('Start JavaScript/TypeScript applications in production mode')
104
99
  .option('-c, --no-color', 'Disable colored output')
105
100
  .option('-t, --no-timing', 'Hide timing information')
106
- .option('-v, --verbose', 'Show detailed logs')
107
- .option('-w, --watch', 'Watch for file changes')
108
- .option('--delay <ms>', 'Delay between file changes (ms)', '1000')
109
- .option('--environment <env>', 'Application environment', 'production')
110
- .option('--cluster', 'Enable cluster mode')
111
- .option('--instances <num>', 'Number of cluster instances', '1')
112
- .option('--memory <mb>', 'Memory limit (MB)', '0')
113
- .option('--cpu <percent>', 'CPU limit (%)', '0')
114
- .option('--info', 'Show detailed start information')
101
+ .option('-p, --no-prefix', 'Hide command prefix')
102
+ .option('-o, --no-output', 'Hide command output')
103
+ .option('-m, --minimal', 'Use minimal output format')
104
+ .option('-w, --watch', 'Watch for changes and restart (production hot-reload)')
105
+ .option('-i, --ignore <patterns...>', 'Patterns to ignore when watching')
106
+ .option('-e, --ext <extensions...>', 'File extensions to watch (default: js,mjs,json)')
107
+ .option('-d, --delay <ms>', 'Delay before restart in milliseconds', parseInt)
108
+ .option('--max-restarts <number>', 'Maximum number of restarts', parseInt)
109
+ .option('--restart-delay <ms>', 'Delay between restarts in milliseconds', parseInt)
110
+ .option('--verbose', 'Verbose output')
111
+ .option('--info', 'Show detailed information during startup')
112
+ .option('--signal <signal>', 'Signal to send to processes on restart', 'SIGTERM')
113
+ .option('--env <env>', 'Environment mode', 'production')
114
+ .option('--cluster', 'Enable cluster mode (spawn multiple processes)')
115
+ .option('--cluster-instances <number>', 'Number of cluster instances', parseInt)
116
+ .option('--memory-limit <mb>', 'Memory limit in MB', parseInt)
117
+ .option('--cpu-limit <percent>', 'CPU limit percentage', parseInt)
115
118
  .action(async (file, options) => {
116
119
  try {
117
- // Get start command configuration
118
- const startConfig = await getStartCommand(file, options.info);
120
+ const showInfo = options.info || false;
121
+ // Validate file parameter
122
+ if (!file || file.trim() === '') {
123
+ console.error(chalk_1.default.red(`${figures_1.default.cross} neex start: Error - No file specified!`));
124
+ console.error(chalk_1.default.yellow(`${figures_1.default.pointer} Usage: neex start <file>`));
125
+ console.error(chalk_1.default.yellow(`${figures_1.default.pointer} Example: neex start dist/server.js`));
126
+ process.exit(1);
127
+ }
128
+ // Show initial info (only if --info flag is set)
129
+ if (showInfo) {
130
+ console.log(chalk_1.default.blue(`${figures_1.default.info} neex start: Starting production application server...`));
131
+ console.log(chalk_1.default.blue(`${figures_1.default.info} neex start: Target file: ${chalk_1.default.cyan(file)}`));
132
+ }
133
+ // Get the start command configuration
134
+ let startConfig;
135
+ try {
136
+ startConfig = await getStartCommand(file, showInfo);
137
+ }
138
+ catch (error) {
139
+ console.error(chalk_1.default.red(`${figures_1.default.cross} neex start: ${error instanceof Error ? error.message : 'Unknown error occurred'}`));
140
+ process.exit(1);
141
+ }
142
+ // Setup watch configuration if enabled
143
+ const watchPaths = options.watch ? [path.dirname(file)] : [];
144
+ const ignorePatterns = options.ignore || [
145
+ 'node_modules/**',
146
+ '.git/**',
147
+ '*.log',
148
+ 'src/**',
149
+ 'test/**',
150
+ 'tests/**',
151
+ 'coverage/**',
152
+ '.nyc_output/**',
153
+ '*.tmp',
154
+ '*.temp',
155
+ '.DS_Store',
156
+ 'Thumbs.db'
157
+ ];
158
+ const extensions = options.ext || ['js', 'mjs', 'json'];
159
+ // Log configuration only if --info flag is set
160
+ if (showInfo) {
161
+ console.log(chalk_1.default.blue(`${figures_1.default.info} neex start: Configuration:`));
162
+ console.log(chalk_1.default.blue(` ${figures_1.default.arrowRight} Target: ${chalk_1.default.cyan(file)}`));
163
+ console.log(chalk_1.default.blue(` ${figures_1.default.arrowRight} Runtime: ${chalk_1.default.cyan(startConfig.runtime)}`));
164
+ console.log(chalk_1.default.blue(` ${figures_1.default.arrowRight} Process name: ${chalk_1.default.cyan(startConfig.processName)}`));
165
+ console.log(chalk_1.default.blue(` ${figures_1.default.arrowRight} Environment: ${chalk_1.default.cyan(options.env)}`));
166
+ console.log(chalk_1.default.blue(` ${figures_1.default.arrowRight} Watch mode: ${chalk_1.default.cyan(options.watch ? 'Yes' : 'No')}`));
167
+ console.log(chalk_1.default.blue(` ${figures_1.default.arrowRight} Cluster mode: ${chalk_1.default.cyan(options.cluster ? 'Yes' : 'No')}`));
168
+ if (options.cluster) {
169
+ console.log(chalk_1.default.blue(` ${figures_1.default.arrowRight} Cluster instances: ${chalk_1.default.cyan(options.clusterInstances || 'auto')}`));
170
+ }
171
+ if (options.watch) {
172
+ console.log(chalk_1.default.blue(` ${figures_1.default.arrowRight} Watch paths: ${chalk_1.default.cyan(watchPaths.join(', '))}`));
173
+ console.log(chalk_1.default.blue(` ${figures_1.default.arrowRight} Extensions: ${chalk_1.default.cyan(extensions.join(', '))}`));
174
+ console.log(chalk_1.default.blue(` ${figures_1.default.arrowRight} Restart delay: ${chalk_1.default.cyan(options.delay || 1000)}ms`));
175
+ }
176
+ if (options.maxRestarts) {
177
+ console.log(chalk_1.default.blue(` ${figures_1.default.arrowRight} Max restarts: ${chalk_1.default.cyan(options.maxRestarts)}`));
178
+ }
179
+ if (options.memoryLimit) {
180
+ console.log(chalk_1.default.blue(` ${figures_1.default.arrowRight} Memory limit: ${chalk_1.default.cyan(options.memoryLimit)}MB`));
181
+ }
182
+ if (options.cpuLimit) {
183
+ console.log(chalk_1.default.blue(` ${figures_1.default.arrowRight} CPU limit: ${chalk_1.default.cyan(options.cpuLimit)}%`));
184
+ }
185
+ if (options.verbose) {
186
+ console.log(chalk_1.default.blue(`${figures_1.default.info} neex start: Verbose mode enabled - showing detailed logs`));
187
+ }
188
+ console.log(chalk_1.default.green(`${figures_1.default.tick} neex start: Starting production application server...`));
189
+ 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...`));
190
+ console.log(chalk_1.default.blue(`${figures_1.default.info} neex start: Press Ctrl+C to stop the application server`));
191
+ console.log(chalk_1.default.gray(`${'='.repeat(60)}`));
192
+ }
193
+ else {
194
+ // Minimal output without --info flag (similar to neex dev)
195
+ console.log(chalk_1.default.green(`${figures_1.default.tick} neex start: Starting ${chalk_1.default.cyan(path.basename(file))} in ${chalk_1.default.cyan(options.env)} mode...`));
196
+ }
119
197
  // Create StartManager instance
120
- const startManager = new start_manager_js_1.StartManager({
198
+ startManager = new start_manager_js_1.StartManager({
121
199
  runnerName: 'neex start',
122
200
  targetFile: file,
123
201
  command: startConfig.command,
124
202
  processName: startConfig.processName,
125
203
  runtime: startConfig.runtime,
126
- environment: options.environment,
127
- showInfo: options.info,
128
- color: !options.color,
129
- showTiming: !options.timing,
204
+ environment: options.env,
205
+ parallel: false,
206
+ color: options.color,
207
+ showTiming: options.timing,
208
+ prefix: options.prefix,
209
+ printOutput: options.output,
210
+ minimalOutput: options.minimal,
130
211
  watch: options.watch,
131
- delay: parseInt(options.delay),
212
+ watchPaths: watchPaths,
213
+ ignore: ignorePatterns,
214
+ ext: extensions,
215
+ delay: options.delay || 1000,
216
+ maxRestarts: options.maxRestarts,
217
+ restartDelay: options.restartDelay || 3000,
132
218
  verbose: options.verbose,
219
+ showInfo: showInfo,
220
+ signal: options.signal,
133
221
  cluster: options.cluster,
134
- clusterInstances: parseInt(options.instances),
135
- memoryLimit: parseInt(options.memory),
136
- cpuLimit: parseInt(options.cpu),
137
- parallel: false,
138
- printOutput: true,
139
- prefix: true,
140
- stopOnError: false,
141
- minimalOutput: false,
222
+ clusterInstances: options.clusterInstances,
223
+ memoryLimit: options.memoryLimit,
224
+ cpuLimit: options.cpuLimit,
142
225
  groupOutput: false,
143
- isServerMode: true
226
+ isServerMode: true,
227
+ stopOnError: false
144
228
  });
145
- // Start the application
146
- try {
147
- if (options.info) {
148
- console.log(chalk_1.default.blue(`${figures_1.default.info} neex start: Analyzing ${chalk_1.default.cyan(path.basename(file))}`));
149
- console.log(chalk_1.default.green(`${figures_1.default.tick} neex start: ${startConfig.runtime} detected, using ${startConfig.runtime} runtime`));
150
- }
151
- await startManager.start();
152
- if (options.info) {
153
- console.log(chalk_1.default.green(`${figures_1.default.tick} Application started successfully`));
154
- }
155
- else {
156
- console.log(chalk_1.default.green(`${figures_1.default.tick} Application started`));
157
- }
158
- }
159
- catch (error) {
160
- console.error(chalk_1.default.red(`${figures_1.default.cross} Failed to start application`));
161
- if (error instanceof Error) {
162
- console.error(chalk_1.default.red(`Error: ${error.message}`));
163
- }
164
- process.exit(1);
165
- }
229
+ // Start the application server
230
+ await startManager.start();
166
231
  }
167
232
  catch (error) {
168
- console.error(chalk_1.default.red(`${figures_1.default.cross} Failed to start application`));
233
+ console.error(chalk_1.default.red(`${figures_1.default.cross} neex start: Fatal error occurred`));
169
234
  if (error instanceof Error) {
170
- console.error(chalk_1.default.red(`Error: ${error.message}`));
235
+ console.error(chalk_1.default.red(`${figures_1.default.cross} Details: ${error.message}`));
236
+ if (options.verbose && error.stack) {
237
+ console.error(chalk_1.default.gray(`Stack trace:\n${error.stack}`));
238
+ }
239
+ }
240
+ else {
241
+ console.error(chalk_1.default.red(`${figures_1.default.cross} Unknown error occurred`));
171
242
  }
243
+ console.error(chalk_1.default.yellow(`${figures_1.default.pointer} Try running with --verbose flag for more details`));
172
244
  process.exit(1);
173
245
  }
174
246
  });
247
+ // Return cleanup function for start manager
175
248
  return {
176
249
  getStartManager: () => startManager,
177
- cleanupStart
250
+ cleanupStart: () => {
251
+ if (startManager && startManager.isActive()) {
252
+ console.log(chalk_1.default.blue(`${figures_1.default.info} neex start: Stopping application server...`));
253
+ startManager.stop();
254
+ console.log(chalk_1.default.green(`${figures_1.default.tick} neex start: Application server stopped successfully`));
255
+ }
256
+ }
178
257
  };
179
258
  }
180
259
  exports.addStartCommands = addStartCommands;
@@ -148,7 +148,8 @@ class Runner {
148
148
  code: null,
149
149
  startTime,
150
150
  endTime: null,
151
- output: []
151
+ output: [],
152
+ stderr: []
152
153
  };
153
154
  if (this.options.printOutput) {
154
155
  logger_1.default.printStart(originalCommand);
@@ -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.22",
3
+ "version": "0.6.24",
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",