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.
- package/dist/src/build-manager.js +40 -36
- package/dist/src/commands/build-commands.js +16 -62
- package/dist/src/commands/start-commands.js +136 -57
- package/dist/src/runner.js +2 -1
- package/dist/src/start-manager.js +34 -121
- package/package.json +1 -1
|
@@ -42,12 +42,12 @@ class BuildManager {
|
|
|
42
42
|
this.startTime = new Date();
|
|
43
43
|
const defaultOptions = {
|
|
44
44
|
parallel: false,
|
|
45
|
-
printOutput:
|
|
45
|
+
printOutput: false,
|
|
46
46
|
color: true,
|
|
47
|
-
showTiming:
|
|
48
|
-
prefix:
|
|
49
|
-
stopOnError:
|
|
50
|
-
minimalOutput:
|
|
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
|
|
152
|
+
// Create a runner with clean output settings
|
|
153
153
|
const runnerOptions = {
|
|
154
154
|
...this.options,
|
|
155
|
-
|
|
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
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
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
|
-
|
|
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.
|
|
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.
|
|
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
|
|
134
|
-
|
|
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.
|
|
142
|
-
showTiming:
|
|
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:
|
|
154
|
-
prefix:
|
|
155
|
-
stopOnError:
|
|
156
|
-
minimalOutput:
|
|
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
|
-
|
|
196
|
-
|
|
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
|
-
|
|
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(
|
|
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
|
-
|
|
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
|
|
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('-
|
|
107
|
-
.option('-
|
|
108
|
-
.option('--
|
|
109
|
-
.option('--
|
|
110
|
-
.option('--
|
|
111
|
-
.option('--
|
|
112
|
-
.option('--
|
|
113
|
-
.option('--
|
|
114
|
-
.option('--
|
|
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
|
-
|
|
118
|
-
|
|
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
|
-
|
|
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.
|
|
127
|
-
|
|
128
|
-
color:
|
|
129
|
-
showTiming:
|
|
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
|
-
|
|
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:
|
|
135
|
-
memoryLimit:
|
|
136
|
-
cpuLimit:
|
|
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
|
-
|
|
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}
|
|
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(
|
|
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;
|
package/dist/src/runner.js
CHANGED
|
@@ -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
|
-
|
|
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
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
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
|
-
|
|
424
|
-
|
|
425
|
-
|
|
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
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
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
|
}
|