neex 0.6.18 → 0.6.21
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/README.md +1 -1
- package/dist/src/build-manager.js +340 -0
- package/dist/src/cli.js +4 -2
- package/dist/src/commands/build-commands.js +237 -0
- package/dist/src/commands/index.js +2 -1
- package/dist/src/commands/start-commands.js +161 -0
- package/dist/src/start-manager.js +471 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -0,0 +1,340 @@
|
|
|
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
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
26
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
27
|
+
};
|
|
28
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
29
|
+
exports.BuildManager = void 0;
|
|
30
|
+
// src/build-manager.ts - Build manager with file watching and compilation
|
|
31
|
+
const watcher_1 = require("./watcher");
|
|
32
|
+
const runner_1 = require("./runner");
|
|
33
|
+
const chalk_1 = __importDefault(require("chalk"));
|
|
34
|
+
const figures_1 = __importDefault(require("figures"));
|
|
35
|
+
const logger_1 = __importDefault(require("./logger"));
|
|
36
|
+
const path = __importStar(require("path"));
|
|
37
|
+
const fs = __importStar(require("fs/promises"));
|
|
38
|
+
class BuildManager {
|
|
39
|
+
constructor(options) {
|
|
40
|
+
this.isBuilding = false;
|
|
41
|
+
this.buildCount = 0;
|
|
42
|
+
this.startTime = new Date();
|
|
43
|
+
const defaultOptions = {
|
|
44
|
+
parallel: false,
|
|
45
|
+
printOutput: true,
|
|
46
|
+
color: true,
|
|
47
|
+
showTiming: true,
|
|
48
|
+
prefix: true,
|
|
49
|
+
stopOnError: false,
|
|
50
|
+
minimalOutput: false,
|
|
51
|
+
groupOutput: false,
|
|
52
|
+
isServerMode: false,
|
|
53
|
+
watch: false,
|
|
54
|
+
ignore: [
|
|
55
|
+
'node_modules/**',
|
|
56
|
+
'.git/**',
|
|
57
|
+
'*.log',
|
|
58
|
+
'dist/**',
|
|
59
|
+
'build/**',
|
|
60
|
+
'coverage/**',
|
|
61
|
+
'.nyc_output/**',
|
|
62
|
+
'*.tmp',
|
|
63
|
+
'*.temp'
|
|
64
|
+
],
|
|
65
|
+
delay: 1000,
|
|
66
|
+
verbose: false,
|
|
67
|
+
showInfo: false,
|
|
68
|
+
runnerName: 'neex build',
|
|
69
|
+
clean: false,
|
|
70
|
+
sourceMap: false,
|
|
71
|
+
target: 'es2020',
|
|
72
|
+
module: 'commonjs'
|
|
73
|
+
};
|
|
74
|
+
this.options = {
|
|
75
|
+
...defaultOptions,
|
|
76
|
+
...options
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
setupFileWatcher() {
|
|
80
|
+
if (!this.options.watch) {
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
83
|
+
const inputDir = path.dirname(this.options.inputFile);
|
|
84
|
+
const watchOptions = {
|
|
85
|
+
watch: [inputDir],
|
|
86
|
+
ignore: this.options.ignore,
|
|
87
|
+
ext: this.options.buildType === 'typescript' ? ['ts', 'tsx'] : ['js', 'jsx', 'mjs', 'cjs'],
|
|
88
|
+
delay: this.options.delay,
|
|
89
|
+
verbose: this.options.verbose && this.options.showInfo
|
|
90
|
+
};
|
|
91
|
+
this.fileWatcher = new watcher_1.FileWatcher(watchOptions);
|
|
92
|
+
this.fileWatcher.on('change', (event) => {
|
|
93
|
+
if (this.options.watch && !this.isBuilding) {
|
|
94
|
+
this.handleFileChange(event);
|
|
95
|
+
}
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
async handleFileChange(event) {
|
|
99
|
+
const prefix = chalk_1.default.cyan(`[${this.options.runnerName}]`);
|
|
100
|
+
if (this.options.showInfo) {
|
|
101
|
+
logger_1.default.printLine(`${prefix} File changed: ${chalk_1.default.yellow(event.relativePath)}`, 'info');
|
|
102
|
+
}
|
|
103
|
+
await this.rebuild();
|
|
104
|
+
}
|
|
105
|
+
async ensureOutputDirectory() {
|
|
106
|
+
try {
|
|
107
|
+
await fs.mkdir(this.options.outputDir, { recursive: true });
|
|
108
|
+
}
|
|
109
|
+
catch (error) {
|
|
110
|
+
if (this.options.showInfo) {
|
|
111
|
+
logger_1.default.printLine(`Failed to create output directory: ${error.message}`, 'error');
|
|
112
|
+
}
|
|
113
|
+
throw error;
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
async cleanOutputDirectory() {
|
|
117
|
+
if (!this.options.clean) {
|
|
118
|
+
return;
|
|
119
|
+
}
|
|
120
|
+
try {
|
|
121
|
+
await fs.rm(this.options.outputDir, { recursive: true, force: true });
|
|
122
|
+
if (this.options.showInfo) {
|
|
123
|
+
const prefix = chalk_1.default.cyan(`[${this.options.runnerName}]`);
|
|
124
|
+
logger_1.default.printLine(`${prefix} Cleaned output directory: ${chalk_1.default.yellow(this.options.outputDir)}`, 'info');
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
catch (error) {
|
|
128
|
+
if (this.options.showInfo) {
|
|
129
|
+
logger_1.default.printLine(`Failed to clean output directory: ${error.message}`, 'error');
|
|
130
|
+
}
|
|
131
|
+
throw error;
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
generateBuildCommand() {
|
|
135
|
+
const { inputFile, outputDir, buildType, sourceMap, target, module } = this.options;
|
|
136
|
+
switch (buildType) {
|
|
137
|
+
case 'typescript':
|
|
138
|
+
let tsCommand = `npx tsc ${inputFile} --outDir ${outputDir} --target ${target} --module ${module} --moduleResolution node --esModuleInterop --allowSyntheticDefaultImports --strict --skipLibCheck`;
|
|
139
|
+
if (sourceMap) {
|
|
140
|
+
tsCommand += ' --sourceMap';
|
|
141
|
+
}
|
|
142
|
+
return tsCommand;
|
|
143
|
+
case 'javascript':
|
|
144
|
+
case 'copy':
|
|
145
|
+
return `cp ${inputFile} ${path.join(outputDir, path.basename(inputFile))}`;
|
|
146
|
+
default:
|
|
147
|
+
return `cp ${inputFile} ${path.join(outputDir, path.basename(inputFile))}`;
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
async runBuild() {
|
|
151
|
+
const buildCommand = this.generateBuildCommand();
|
|
152
|
+
// Create a modified options object for the runner
|
|
153
|
+
const runnerOptions = {
|
|
154
|
+
...this.options,
|
|
155
|
+
customPrefix: () => `build`
|
|
156
|
+
};
|
|
157
|
+
this.runner = new runner_1.Runner(runnerOptions);
|
|
158
|
+
try {
|
|
159
|
+
this.isBuilding = true;
|
|
160
|
+
this.buildCount++;
|
|
161
|
+
this.lastBuildTime = new Date();
|
|
162
|
+
// Ensure output directory exists
|
|
163
|
+
await this.ensureOutputDirectory();
|
|
164
|
+
// Clean if requested
|
|
165
|
+
if (this.options.clean && this.buildCount === 1) {
|
|
166
|
+
await this.cleanOutputDirectory();
|
|
167
|
+
await this.ensureOutputDirectory();
|
|
168
|
+
}
|
|
169
|
+
const results = await this.runner.run([buildCommand]);
|
|
170
|
+
// Handle build results
|
|
171
|
+
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');
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
return results;
|
|
184
|
+
}
|
|
185
|
+
catch (error) {
|
|
186
|
+
if (this.options.showInfo) {
|
|
187
|
+
logger_1.default.printLine(`Build failed: ${error.message}`, 'error');
|
|
188
|
+
}
|
|
189
|
+
return [];
|
|
190
|
+
}
|
|
191
|
+
finally {
|
|
192
|
+
this.isBuilding = false;
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
printBuildBanner() {
|
|
196
|
+
var _a;
|
|
197
|
+
if (!this.options.showInfo) {
|
|
198
|
+
return;
|
|
199
|
+
}
|
|
200
|
+
const prefix = chalk_1.default.cyan(`[${this.options.runnerName}]`);
|
|
201
|
+
const uptime = Math.floor((Date.now() - this.startTime.getTime()) / 1000);
|
|
202
|
+
const uptimeStr = this.formatUptime(uptime);
|
|
203
|
+
console.log('\n' + chalk_1.default.bgBlue.black(` ${(_a = this.options.runnerName) === null || _a === void 0 ? void 0 : _a.toUpperCase()} MODE `) + '\n');
|
|
204
|
+
if (this.buildCount > 0) {
|
|
205
|
+
console.log(`${prefix} ${chalk_1.default.green(`${figures_1.default.tick} Build #${this.buildCount}`)}`);
|
|
206
|
+
}
|
|
207
|
+
console.log(`${prefix} ${chalk_1.default.blue(`${figures_1.default.info} Uptime: ${uptimeStr}`)}`);
|
|
208
|
+
console.log(`${prefix} ${chalk_1.default.blue(`${figures_1.default.info} Input: ${this.options.inputFile}`)}`);
|
|
209
|
+
console.log(`${prefix} ${chalk_1.default.blue(`${figures_1.default.info} Output: ${this.options.outputDir}`)}`);
|
|
210
|
+
console.log(`${prefix} ${chalk_1.default.blue(`${figures_1.default.info} Build type: ${this.options.buildType}`)}`);
|
|
211
|
+
if (this.options.watch) {
|
|
212
|
+
console.log(`${prefix} ${chalk_1.default.blue(`${figures_1.default.info} Watching for changes...`)}`);
|
|
213
|
+
}
|
|
214
|
+
console.log('');
|
|
215
|
+
}
|
|
216
|
+
formatUptime(seconds) {
|
|
217
|
+
if (seconds < 60) {
|
|
218
|
+
return `${seconds}s`;
|
|
219
|
+
}
|
|
220
|
+
else if (seconds < 3600) {
|
|
221
|
+
const minutes = Math.floor(seconds / 60);
|
|
222
|
+
const remainingSeconds = seconds % 60;
|
|
223
|
+
return `${minutes}m ${remainingSeconds}s`;
|
|
224
|
+
}
|
|
225
|
+
else {
|
|
226
|
+
const hours = Math.floor(seconds / 3600);
|
|
227
|
+
const minutes = Math.floor((seconds % 3600) / 60);
|
|
228
|
+
return `${hours}h ${minutes}m`;
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
async start() {
|
|
232
|
+
this.startTime = new Date();
|
|
233
|
+
// Setup file watcher if watch mode is enabled
|
|
234
|
+
if (this.options.watch) {
|
|
235
|
+
this.setupFileWatcher();
|
|
236
|
+
}
|
|
237
|
+
// Print build banner only if showInfo is true
|
|
238
|
+
this.printBuildBanner();
|
|
239
|
+
// Start file watcher if enabled
|
|
240
|
+
if (this.fileWatcher) {
|
|
241
|
+
await this.fileWatcher.start();
|
|
242
|
+
}
|
|
243
|
+
// 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
|
+
await this.runBuild();
|
|
249
|
+
// Set up graceful shutdown
|
|
250
|
+
this.setupGracefulShutdown();
|
|
251
|
+
if (this.options.watch) {
|
|
252
|
+
if (this.options.showInfo) {
|
|
253
|
+
logger_1.default.printLine(`${prefix} Build completed. Watching for changes...`, 'info');
|
|
254
|
+
logger_1.default.printLine(`${prefix} Press ${chalk_1.default.cyan('Ctrl+C')} to stop`, 'info');
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
else {
|
|
258
|
+
if (this.options.showInfo) {
|
|
259
|
+
logger_1.default.printLine(`${prefix} Build process completed`, 'info');
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
async rebuild() {
|
|
264
|
+
const prefix = chalk_1.default.cyan(`[${this.options.runnerName}]`);
|
|
265
|
+
if (this.isBuilding) {
|
|
266
|
+
return;
|
|
267
|
+
}
|
|
268
|
+
if (this.options.showInfo) {
|
|
269
|
+
logger_1.default.printLine(`${prefix} Rebuilding due to file changes...`, 'info');
|
|
270
|
+
}
|
|
271
|
+
// Stop current processes
|
|
272
|
+
if (this.runner) {
|
|
273
|
+
this.runner.cleanup('SIGTERM');
|
|
274
|
+
}
|
|
275
|
+
// Wait a moment before rebuilding
|
|
276
|
+
await new Promise(resolve => setTimeout(resolve, 500));
|
|
277
|
+
// Print rebuild banner only if showInfo is true
|
|
278
|
+
this.printBuildBanner();
|
|
279
|
+
// Run build again
|
|
280
|
+
await this.runBuild();
|
|
281
|
+
if (this.options.showInfo) {
|
|
282
|
+
logger_1.default.printLine(`${prefix} Rebuild completed. Watching for changes...`, 'info');
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
async stop() {
|
|
286
|
+
const prefix = chalk_1.default.cyan(`[${this.options.runnerName}]`);
|
|
287
|
+
if (!this.isBuilding && !this.options.watch) {
|
|
288
|
+
return;
|
|
289
|
+
}
|
|
290
|
+
if (this.options.showInfo) {
|
|
291
|
+
logger_1.default.printLine(`${prefix} Stopping build process...`, 'info');
|
|
292
|
+
}
|
|
293
|
+
// Stop file watcher
|
|
294
|
+
if (this.fileWatcher) {
|
|
295
|
+
this.fileWatcher.stop();
|
|
296
|
+
}
|
|
297
|
+
// Stop current processes
|
|
298
|
+
if (this.runner) {
|
|
299
|
+
this.runner.cleanup('SIGTERM');
|
|
300
|
+
}
|
|
301
|
+
const uptime = Math.floor((Date.now() - this.startTime.getTime()) / 1000);
|
|
302
|
+
const uptimeStr = this.formatUptime(uptime);
|
|
303
|
+
if (this.options.showInfo) {
|
|
304
|
+
logger_1.default.printLine(`${prefix} Build process stopped after ${uptimeStr}`, 'info');
|
|
305
|
+
if (this.buildCount > 0) {
|
|
306
|
+
logger_1.default.printLine(`${prefix} Total builds: ${this.buildCount}`, 'info');
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
setupGracefulShutdown() {
|
|
311
|
+
const handleSignal = (signal) => {
|
|
312
|
+
if (this.options.showInfo) {
|
|
313
|
+
console.log(`\n${chalk_1.default.yellow(`${figures_1.default.warning} Received ${signal}. Shutting down build process...`)}`);
|
|
314
|
+
}
|
|
315
|
+
this.stop().then(() => {
|
|
316
|
+
process.exit(0);
|
|
317
|
+
});
|
|
318
|
+
};
|
|
319
|
+
process.on('SIGINT', () => handleSignal('SIGINT'));
|
|
320
|
+
process.on('SIGTERM', () => handleSignal('SIGTERM'));
|
|
321
|
+
process.on('SIGQUIT', () => handleSignal('SIGQUIT'));
|
|
322
|
+
}
|
|
323
|
+
isActive() {
|
|
324
|
+
return this.isBuilding || (this.options.watch || false);
|
|
325
|
+
}
|
|
326
|
+
getUptime() {
|
|
327
|
+
return Math.floor((Date.now() - this.startTime.getTime()) / 1000);
|
|
328
|
+
}
|
|
329
|
+
getBuildCount() {
|
|
330
|
+
return this.buildCount;
|
|
331
|
+
}
|
|
332
|
+
getLastBuildTime() {
|
|
333
|
+
return this.lastBuildTime;
|
|
334
|
+
}
|
|
335
|
+
getWatchedFiles() {
|
|
336
|
+
var _a;
|
|
337
|
+
return ((_a = this.fileWatcher) === null || _a === void 0 ? void 0 : _a.getWatchedFiles()) || [];
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
exports.BuildManager = BuildManager;
|
package/dist/src/cli.js
CHANGED
|
@@ -22,8 +22,10 @@ function cli() {
|
|
|
22
22
|
(0, index_js_1.addServerCommands)(program);
|
|
23
23
|
const devCommands = (0, index_js_1.addDevCommands)(program);
|
|
24
24
|
cleanupHandlers.push(devCommands.cleanupDev);
|
|
25
|
-
const
|
|
26
|
-
cleanupHandlers.push(
|
|
25
|
+
const buildCommands = (0, index_js_1.addBuildCommands)(program);
|
|
26
|
+
cleanupHandlers.push(buildCommands.cleanupBuild);
|
|
27
|
+
const startCommands = (0, index_js_1.addStartCommands)(program);
|
|
28
|
+
cleanupHandlers.push(startCommands.cleanupStart);
|
|
27
29
|
program.parse(process.argv);
|
|
28
30
|
// Show help if no commands specified
|
|
29
31
|
if (program.args.length === 0) {
|
|
@@ -0,0 +1,237 @@
|
|
|
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
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
26
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
27
|
+
};
|
|
28
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
29
|
+
exports.addBuildCommands = void 0;
|
|
30
|
+
const build_manager_js_1 = require("../build-manager.js");
|
|
31
|
+
const chalk_1 = __importDefault(require("chalk"));
|
|
32
|
+
const figures_1 = __importDefault(require("figures"));
|
|
33
|
+
const path = __importStar(require("path"));
|
|
34
|
+
const fs = __importStar(require("fs/promises"));
|
|
35
|
+
// Helper function to check if file exists
|
|
36
|
+
async function fileExists(filePath) {
|
|
37
|
+
try {
|
|
38
|
+
await fs.access(filePath);
|
|
39
|
+
return true;
|
|
40
|
+
}
|
|
41
|
+
catch (_a) {
|
|
42
|
+
return false;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
// Helper function to determine build configuration
|
|
46
|
+
async function getBuildConfig(filePath, outputDir, showInfo) {
|
|
47
|
+
const ext = path.extname(filePath).toLowerCase();
|
|
48
|
+
const absolutePath = path.resolve(process.cwd(), filePath);
|
|
49
|
+
const fileName = path.basename(filePath, ext);
|
|
50
|
+
const outputPath = path.resolve(process.cwd(), outputDir);
|
|
51
|
+
// Check if file exists
|
|
52
|
+
if (!(await fileExists(absolutePath))) {
|
|
53
|
+
throw new Error(`File not found: ${filePath}`);
|
|
54
|
+
}
|
|
55
|
+
if (showInfo) {
|
|
56
|
+
console.log(chalk_1.default.blue(`${figures_1.default.info} neex build: Analyzing ${chalk_1.default.cyan(path.basename(filePath))}`));
|
|
57
|
+
}
|
|
58
|
+
switch (ext) {
|
|
59
|
+
case '.ts':
|
|
60
|
+
case '.mts':
|
|
61
|
+
case '.cts':
|
|
62
|
+
if (showInfo) {
|
|
63
|
+
console.log(chalk_1.default.green(`${figures_1.default.tick} neex build: TypeScript detected, compiling to JavaScript`));
|
|
64
|
+
}
|
|
65
|
+
return {
|
|
66
|
+
inputFile: absolutePath,
|
|
67
|
+
outputFile: path.join(outputPath, `${fileName}.js`),
|
|
68
|
+
buildCommand: `npx tsc ${filePath} --outDir ${outputDir} --target es2020 --module commonjs --moduleResolution node --esModuleInterop --allowSyntheticDefaultImports --strict --skipLibCheck`,
|
|
69
|
+
buildType: 'typescript'
|
|
70
|
+
};
|
|
71
|
+
case '.js':
|
|
72
|
+
case '.mjs':
|
|
73
|
+
case '.cjs':
|
|
74
|
+
if (showInfo) {
|
|
75
|
+
console.log(chalk_1.default.green(`${figures_1.default.tick} neex build: JavaScript detected, copying to output directory`));
|
|
76
|
+
}
|
|
77
|
+
return {
|
|
78
|
+
inputFile: absolutePath,
|
|
79
|
+
outputFile: path.join(outputPath, path.basename(filePath)),
|
|
80
|
+
buildCommand: `cp ${filePath} ${path.join(outputDir, path.basename(filePath))}`,
|
|
81
|
+
buildType: 'copy'
|
|
82
|
+
};
|
|
83
|
+
default:
|
|
84
|
+
if (showInfo) {
|
|
85
|
+
console.log(chalk_1.default.yellow(`${figures_1.default.warning} neex build: Unknown file type, copying as-is`));
|
|
86
|
+
}
|
|
87
|
+
return {
|
|
88
|
+
inputFile: absolutePath,
|
|
89
|
+
outputFile: path.join(outputPath, path.basename(filePath)),
|
|
90
|
+
buildCommand: `cp ${filePath} ${path.join(outputDir, path.basename(filePath))}`,
|
|
91
|
+
buildType: 'copy'
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
function addBuildCommands(program) {
|
|
96
|
+
let buildManager = null;
|
|
97
|
+
// Build command - compile TypeScript/JavaScript projects
|
|
98
|
+
program
|
|
99
|
+
.command('build <file>') // Made file mandatory
|
|
100
|
+
.alias('b')
|
|
101
|
+
.description('Build TypeScript/JavaScript files for production')
|
|
102
|
+
.option('-o, --output <dir>', 'Output directory', 'dist')
|
|
103
|
+
.option('-c, --no-color', 'Disable colored output')
|
|
104
|
+
.option('-t, --no-timing', 'Hide timing information')
|
|
105
|
+
.option('-p, --no-prefix', 'Hide command prefix')
|
|
106
|
+
.option('-s, --stop-on-error', 'Stop on first error')
|
|
107
|
+
.option('-m, --minimal', 'Use minimal output format')
|
|
108
|
+
.option('-w, --watch', 'Watch for changes and rebuild')
|
|
109
|
+
.option('-i, --ignore <patterns...>', 'Patterns to ignore when watching')
|
|
110
|
+
.option('-d, --delay <ms>', 'Delay before rebuild in milliseconds', parseInt)
|
|
111
|
+
.option('--clean', 'Clean output directory before build')
|
|
112
|
+
.option('--verbose', 'Verbose output')
|
|
113
|
+
.option('--info', 'Show detailed information during build')
|
|
114
|
+
.option('--source-map', 'Generate source maps')
|
|
115
|
+
.option('--target <target>', 'Target ECMAScript version', 'es2020')
|
|
116
|
+
.option('--module <module>', 'Module system', 'commonjs')
|
|
117
|
+
.action(async (file, options) => {
|
|
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
|
+
}
|
|
124
|
+
// Validate file parameter
|
|
125
|
+
if (!file || file.trim() === '') {
|
|
126
|
+
console.error(chalk_1.default.red(`${figures_1.default.cross} neex build: Error - No file specified!`));
|
|
127
|
+
console.error(chalk_1.default.yellow(`${figures_1.default.pointer} Usage: neex build <file>`));
|
|
128
|
+
console.error(chalk_1.default.yellow(`${figures_1.default.pointer} Example: neex build src/server.ts`));
|
|
129
|
+
process.exit(1);
|
|
130
|
+
}
|
|
131
|
+
// Get build configuration
|
|
132
|
+
let buildConfig;
|
|
133
|
+
try {
|
|
134
|
+
buildConfig = await getBuildConfig(file, options.output, showInfo);
|
|
135
|
+
}
|
|
136
|
+
catch (error) {
|
|
137
|
+
console.error(chalk_1.default.red(`${figures_1.default.cross} neex build: ${error instanceof Error ? error.message : 'Unknown error occurred'}`));
|
|
138
|
+
process.exit(1);
|
|
139
|
+
}
|
|
140
|
+
// Setup ignore patterns for watch mode
|
|
141
|
+
const ignorePatterns = options.ignore || [
|
|
142
|
+
'node_modules/**',
|
|
143
|
+
'.git/**',
|
|
144
|
+
'*.log',
|
|
145
|
+
'dist/**',
|
|
146
|
+
'build/**',
|
|
147
|
+
'coverage/**',
|
|
148
|
+
'.nyc_output/**',
|
|
149
|
+
'*.tmp',
|
|
150
|
+
'*.temp',
|
|
151
|
+
'.DS_Store',
|
|
152
|
+
'Thumbs.db'
|
|
153
|
+
];
|
|
154
|
+
// Log configuration only if --info flag is set
|
|
155
|
+
if (showInfo) {
|
|
156
|
+
console.log(chalk_1.default.blue(`${figures_1.default.info} neex build: Configuration:`));
|
|
157
|
+
console.log(chalk_1.default.blue(` ${figures_1.default.arrowRight} Input: ${chalk_1.default.cyan(file)}`));
|
|
158
|
+
console.log(chalk_1.default.blue(` ${figures_1.default.arrowRight} Output: ${chalk_1.default.cyan(options.output)}`));
|
|
159
|
+
console.log(chalk_1.default.blue(` ${figures_1.default.arrowRight} Build type: ${chalk_1.default.cyan(buildConfig.buildType)}`));
|
|
160
|
+
console.log(chalk_1.default.blue(` ${figures_1.default.arrowRight} Target: ${chalk_1.default.cyan(options.target)}`));
|
|
161
|
+
console.log(chalk_1.default.blue(` ${figures_1.default.arrowRight} Module: ${chalk_1.default.cyan(options.module)}`));
|
|
162
|
+
console.log(chalk_1.default.blue(` ${figures_1.default.arrowRight} Watch mode: ${chalk_1.default.cyan(options.watch ? 'Yes' : 'No')}`));
|
|
163
|
+
console.log(chalk_1.default.blue(` ${figures_1.default.arrowRight} Clean before build: ${chalk_1.default.cyan(options.clean ? 'Yes' : 'No')}`));
|
|
164
|
+
console.log(chalk_1.default.blue(` ${figures_1.default.arrowRight} Source maps: ${chalk_1.default.cyan(options.sourceMap ? 'Yes' : 'No')}`));
|
|
165
|
+
if (options.verbose) {
|
|
166
|
+
console.log(chalk_1.default.blue(`${figures_1.default.info} neex build: Verbose mode enabled - showing detailed logs`));
|
|
167
|
+
}
|
|
168
|
+
console.log(chalk_1.default.green(`${figures_1.default.tick} neex build: Starting build process...`));
|
|
169
|
+
console.log(chalk_1.default.gray(`${'='.repeat(60)}`));
|
|
170
|
+
}
|
|
171
|
+
// Create BuildManager instance
|
|
172
|
+
buildManager = new build_manager_js_1.BuildManager({
|
|
173
|
+
runnerName: 'neex build',
|
|
174
|
+
inputFile: file,
|
|
175
|
+
outputDir: options.output,
|
|
176
|
+
buildType: buildConfig.buildType,
|
|
177
|
+
buildCommand: buildConfig.buildCommand,
|
|
178
|
+
color: options.color,
|
|
179
|
+
showTiming: options.timing,
|
|
180
|
+
prefix: options.prefix,
|
|
181
|
+
stopOnError: options.stopOnError,
|
|
182
|
+
printOutput: true,
|
|
183
|
+
minimalOutput: options.minimal,
|
|
184
|
+
watch: options.watch,
|
|
185
|
+
ignore: ignorePatterns,
|
|
186
|
+
delay: options.delay || 1000,
|
|
187
|
+
verbose: options.verbose,
|
|
188
|
+
showInfo: showInfo,
|
|
189
|
+
clean: options.clean,
|
|
190
|
+
sourceMap: options.sourceMap,
|
|
191
|
+
target: options.target,
|
|
192
|
+
module: options.module,
|
|
193
|
+
parallel: false,
|
|
194
|
+
groupOutput: false,
|
|
195
|
+
isServerMode: false
|
|
196
|
+
});
|
|
197
|
+
// Start the build process
|
|
198
|
+
try {
|
|
199
|
+
await buildManager.start();
|
|
200
|
+
console.log(chalk_1.default.green(`${figures_1.default.tick} Build completed successfully`));
|
|
201
|
+
}
|
|
202
|
+
catch (error) {
|
|
203
|
+
console.error(chalk_1.default.red(`${figures_1.default.cross} Build failed`));
|
|
204
|
+
if (error instanceof Error) {
|
|
205
|
+
console.error(chalk_1.default.red(`Error: ${error.message}`));
|
|
206
|
+
}
|
|
207
|
+
process.exit(1);
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
catch (error) {
|
|
211
|
+
console.error(chalk_1.default.red(`${figures_1.default.cross} neex build: Fatal error occurred`));
|
|
212
|
+
if (error instanceof Error) {
|
|
213
|
+
console.error(chalk_1.default.red(`${figures_1.default.cross} Details: ${error.message}`));
|
|
214
|
+
if (options.verbose && error.stack) {
|
|
215
|
+
console.error(chalk_1.default.gray(`Stack trace:\n${error.stack}`));
|
|
216
|
+
}
|
|
217
|
+
}
|
|
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
|
+
process.exit(1);
|
|
223
|
+
}
|
|
224
|
+
});
|
|
225
|
+
// Return cleanup function for build manager
|
|
226
|
+
return {
|
|
227
|
+
getBuildManager: () => buildManager,
|
|
228
|
+
cleanupBuild: () => {
|
|
229
|
+
if (buildManager && buildManager.isActive()) {
|
|
230
|
+
console.log(chalk_1.default.blue(`${figures_1.default.info} neex build: Stopping build process...`));
|
|
231
|
+
buildManager.stop();
|
|
232
|
+
console.log(chalk_1.default.green(`${figures_1.default.tick} neex build: Build process stopped successfully`));
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
};
|
|
236
|
+
}
|
|
237
|
+
exports.addBuildCommands = addBuildCommands;
|
|
@@ -17,5 +17,6 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
17
17
|
// src/commands/index.ts - Export all commands
|
|
18
18
|
__exportStar(require("./run-commands.js"), exports);
|
|
19
19
|
__exportStar(require("./dev-commands.js"), exports);
|
|
20
|
-
__exportStar(require("./process-commands.js"), exports);
|
|
21
20
|
__exportStar(require("./server-commands.js"), exports);
|
|
21
|
+
__exportStar(require("./start-commands.js"), exports);
|
|
22
|
+
__exportStar(require("./build-commands"), exports);
|
|
@@ -0,0 +1,161 @@
|
|
|
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
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
26
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
27
|
+
};
|
|
28
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
29
|
+
exports.addStartCommands = void 0;
|
|
30
|
+
const start_manager_js_1 = require("../start-manager.js");
|
|
31
|
+
const chalk_1 = __importDefault(require("chalk"));
|
|
32
|
+
const figures_1 = __importDefault(require("figures"));
|
|
33
|
+
const path = __importStar(require("path"));
|
|
34
|
+
const fs = __importStar(require("fs/promises"));
|
|
35
|
+
// Helper function to check if file exists
|
|
36
|
+
async function fileExists(filePath) {
|
|
37
|
+
try {
|
|
38
|
+
await fs.access(filePath);
|
|
39
|
+
return true;
|
|
40
|
+
}
|
|
41
|
+
catch (_a) {
|
|
42
|
+
return false;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
// Helper function to determine the best command to start the application
|
|
46
|
+
async function getStartCommand(filePath, showInfo) {
|
|
47
|
+
const ext = path.extname(filePath).toLowerCase();
|
|
48
|
+
const absolutePath = path.resolve(process.cwd(), filePath);
|
|
49
|
+
const fileName = path.basename(filePath, ext);
|
|
50
|
+
// Check if file exists
|
|
51
|
+
if (!(await fileExists(absolutePath))) {
|
|
52
|
+
throw new Error(`File not found: ${filePath}`);
|
|
53
|
+
}
|
|
54
|
+
if (showInfo) {
|
|
55
|
+
console.log(chalk_1.default.blue(`${figures_1.default.info} neex start: Analyzing ${chalk_1.default.cyan(path.basename(filePath))}`));
|
|
56
|
+
}
|
|
57
|
+
switch (ext) {
|
|
58
|
+
case '.js':
|
|
59
|
+
case '.mjs':
|
|
60
|
+
case '.cjs':
|
|
61
|
+
if (showInfo) {
|
|
62
|
+
console.log(chalk_1.default.green(`${figures_1.default.tick} neex start: JavaScript detected, using Node.js runtime`));
|
|
63
|
+
}
|
|
64
|
+
return {
|
|
65
|
+
command: `node ${filePath}`,
|
|
66
|
+
runtime: 'Node.js',
|
|
67
|
+
processName: fileName
|
|
68
|
+
};
|
|
69
|
+
case '.ts':
|
|
70
|
+
case '.mts':
|
|
71
|
+
case '.cts':
|
|
72
|
+
if (showInfo) {
|
|
73
|
+
console.log(chalk_1.default.yellow(`${figures_1.default.warning} neex start: TypeScript detected, consider building first`));
|
|
74
|
+
console.log(chalk_1.default.yellow(`${figures_1.default.pointer} Tip: Run 'neex build ${filePath}' first, then start the built .js file`));
|
|
75
|
+
}
|
|
76
|
+
return {
|
|
77
|
+
command: `npx ts-node ${filePath}`,
|
|
78
|
+
runtime: 'TypeScript (ts-node)',
|
|
79
|
+
processName: fileName
|
|
80
|
+
};
|
|
81
|
+
default:
|
|
82
|
+
if (showInfo) {
|
|
83
|
+
console.log(chalk_1.default.yellow(`${figures_1.default.warning} neex start: Unknown file type, using Node.js`));
|
|
84
|
+
}
|
|
85
|
+
return {
|
|
86
|
+
command: `node ${filePath}`,
|
|
87
|
+
runtime: 'Node.js',
|
|
88
|
+
processName: fileName
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
function addStartCommands(program) {
|
|
93
|
+
let startManager = null;
|
|
94
|
+
const cleanupStart = () => {
|
|
95
|
+
if (startManager) {
|
|
96
|
+
startManager.stop();
|
|
97
|
+
startManager = null;
|
|
98
|
+
}
|
|
99
|
+
};
|
|
100
|
+
program
|
|
101
|
+
.command('start <file>')
|
|
102
|
+
.alias('s')
|
|
103
|
+
.description('Start a production application')
|
|
104
|
+
.option('-c, --no-color', 'Disable colored output')
|
|
105
|
+
.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
|
+
.action(async (file, options) => {
|
|
115
|
+
try {
|
|
116
|
+
// Get start command configuration
|
|
117
|
+
const startConfig = await getStartCommand(file, true);
|
|
118
|
+
// Create StartManager instance
|
|
119
|
+
const startManager = new start_manager_js_1.StartManager({
|
|
120
|
+
runnerName: 'neex start',
|
|
121
|
+
targetFile: file,
|
|
122
|
+
command: startConfig.command,
|
|
123
|
+
processName: startConfig.processName,
|
|
124
|
+
runtime: startConfig.runtime,
|
|
125
|
+
environment: options.environment,
|
|
126
|
+
showInfo: true,
|
|
127
|
+
color: !options.color,
|
|
128
|
+
showTiming: !options.timing,
|
|
129
|
+
watch: options.watch,
|
|
130
|
+
delay: parseInt(options.delay),
|
|
131
|
+
verbose: options.verbose,
|
|
132
|
+
cluster: options.cluster,
|
|
133
|
+
clusterInstances: parseInt(options.instances),
|
|
134
|
+
memoryLimit: parseInt(options.memory),
|
|
135
|
+
cpuLimit: parseInt(options.cpu),
|
|
136
|
+
parallel: false,
|
|
137
|
+
printOutput: true,
|
|
138
|
+
prefix: true,
|
|
139
|
+
stopOnError: false,
|
|
140
|
+
minimalOutput: false,
|
|
141
|
+
groupOutput: false,
|
|
142
|
+
isServerMode: true
|
|
143
|
+
});
|
|
144
|
+
// Start the application
|
|
145
|
+
await startManager.start();
|
|
146
|
+
console.log(chalk_1.default.green(`${figures_1.default.tick} Application started successfully`));
|
|
147
|
+
}
|
|
148
|
+
catch (error) {
|
|
149
|
+
console.error(chalk_1.default.red(`${figures_1.default.cross} Failed to start application`));
|
|
150
|
+
if (error instanceof Error) {
|
|
151
|
+
console.error(chalk_1.default.red(`Error: ${error.message}`));
|
|
152
|
+
}
|
|
153
|
+
process.exit(1);
|
|
154
|
+
}
|
|
155
|
+
});
|
|
156
|
+
return {
|
|
157
|
+
getStartManager: () => startManager,
|
|
158
|
+
cleanupStart
|
|
159
|
+
};
|
|
160
|
+
}
|
|
161
|
+
exports.addStartCommands = addStartCommands;
|
|
@@ -0,0 +1,471 @@
|
|
|
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
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
26
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
27
|
+
};
|
|
28
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
29
|
+
exports.StartManager = void 0;
|
|
30
|
+
// src/start-manager.ts - Production application start manager with monitoring
|
|
31
|
+
const watcher_1 = require("./watcher");
|
|
32
|
+
const runner_1 = require("./runner");
|
|
33
|
+
const chalk_1 = __importDefault(require("chalk"));
|
|
34
|
+
const figures_1 = __importDefault(require("figures"));
|
|
35
|
+
const logger_1 = __importDefault(require("./logger"));
|
|
36
|
+
const os = __importStar(require("os"));
|
|
37
|
+
class StartManager {
|
|
38
|
+
constructor(options) {
|
|
39
|
+
this.isRunning = false;
|
|
40
|
+
this.restartCount = 0;
|
|
41
|
+
this.crashCount = 0;
|
|
42
|
+
this.startTime = new Date();
|
|
43
|
+
this.processStats = {
|
|
44
|
+
memoryUsage: 0,
|
|
45
|
+
cpuUsage: 0,
|
|
46
|
+
uptime: 0
|
|
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
|
+
const defaultOptions = {
|
|
52
|
+
parallel: false,
|
|
53
|
+
printOutput: true,
|
|
54
|
+
color: true,
|
|
55
|
+
showTiming: true,
|
|
56
|
+
prefix: true,
|
|
57
|
+
stopOnError: false,
|
|
58
|
+
minimalOutput: false,
|
|
59
|
+
groupOutput: false,
|
|
60
|
+
isServerMode: true,
|
|
61
|
+
watch: false,
|
|
62
|
+
watchPaths: [],
|
|
63
|
+
ignore: [
|
|
64
|
+
'node_modules/**',
|
|
65
|
+
'.git/**',
|
|
66
|
+
'*.log',
|
|
67
|
+
'src/**',
|
|
68
|
+
'test/**',
|
|
69
|
+
'tests/**',
|
|
70
|
+
'coverage/**',
|
|
71
|
+
'.nyc_output/**',
|
|
72
|
+
'*.tmp',
|
|
73
|
+
'*.temp'
|
|
74
|
+
],
|
|
75
|
+
ext: ['js', 'mjs', 'json'],
|
|
76
|
+
delay: 1000,
|
|
77
|
+
verbose: false,
|
|
78
|
+
showInfo: false,
|
|
79
|
+
runnerName: 'neex start',
|
|
80
|
+
environment: 'production',
|
|
81
|
+
maxRestarts: 10,
|
|
82
|
+
restartDelay: 3000,
|
|
83
|
+
signal: 'SIGTERM',
|
|
84
|
+
cluster: false,
|
|
85
|
+
clusterInstances: os.cpus().length
|
|
86
|
+
};
|
|
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
|
+
this.options = {
|
|
96
|
+
...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')
|
|
104
|
+
};
|
|
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
|
+
}
|
|
113
|
+
setupFileWatcher() {
|
|
114
|
+
var _a;
|
|
115
|
+
if (!this.options.watch || !((_a = this.options.watchPaths) === null || _a === void 0 ? void 0 : _a.length)) {
|
|
116
|
+
return;
|
|
117
|
+
}
|
|
118
|
+
const watchOptions = {
|
|
119
|
+
watch: this.options.watchPaths,
|
|
120
|
+
ignore: this.options.ignore,
|
|
121
|
+
ext: this.options.ext,
|
|
122
|
+
delay: this.options.delay,
|
|
123
|
+
verbose: this.options.verbose && this.options.showInfo
|
|
124
|
+
};
|
|
125
|
+
this.fileWatcher = new watcher_1.FileWatcher(watchOptions);
|
|
126
|
+
this.fileWatcher.on('change', (event) => {
|
|
127
|
+
if (this.options.watch && this.isRunning) {
|
|
128
|
+
this.handleFileChange(event);
|
|
129
|
+
}
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
async handleFileChange(event) {
|
|
133
|
+
const prefix = chalk_1.default.cyan(`[${this.options.runnerName}]`);
|
|
134
|
+
if (this.options.showInfo) {
|
|
135
|
+
logger_1.default.printLine(`${prefix} File changed: ${chalk_1.default.yellow(event.relativePath)}`, 'info');
|
|
136
|
+
}
|
|
137
|
+
await this.gracefulRestart();
|
|
138
|
+
}
|
|
139
|
+
generateClusterCommand() {
|
|
140
|
+
if (!this.options.cluster) {
|
|
141
|
+
return this.options.command;
|
|
142
|
+
}
|
|
143
|
+
const instances = this.options.clusterInstances || os.cpus().length;
|
|
144
|
+
const baseCommand = this.options.command;
|
|
145
|
+
// For cluster mode, we'll use a simple approach with PM2-like clustering
|
|
146
|
+
// This is a simplified implementation - in real production, you'd use PM2 or similar
|
|
147
|
+
return `${baseCommand} --cluster=${instances}`;
|
|
148
|
+
}
|
|
149
|
+
async startApplication() {
|
|
150
|
+
const command = this.generateClusterCommand();
|
|
151
|
+
// Set environment variables
|
|
152
|
+
const env = {
|
|
153
|
+
...process.env,
|
|
154
|
+
NODE_ENV: this.options.environment,
|
|
155
|
+
NEEX_START_MODE: 'production',
|
|
156
|
+
NEEX_PROCESS_NAME: this.options.processName
|
|
157
|
+
};
|
|
158
|
+
// Create a modified options object for the runner
|
|
159
|
+
const runnerOptions = {
|
|
160
|
+
...this.options,
|
|
161
|
+
env,
|
|
162
|
+
customPrefix: () => this.options.processName,
|
|
163
|
+
// Override some options for production
|
|
164
|
+
stopOnError: false,
|
|
165
|
+
restartOnFailure: true,
|
|
166
|
+
maxRestarts: this.options.maxRestarts,
|
|
167
|
+
restartDelay: this.options.restartDelay
|
|
168
|
+
};
|
|
169
|
+
this.runner = new runner_1.Runner(runnerOptions);
|
|
170
|
+
try {
|
|
171
|
+
const results = await this.runner.run([command]);
|
|
172
|
+
return results;
|
|
173
|
+
}
|
|
174
|
+
catch (error) {
|
|
175
|
+
this.crashCount++;
|
|
176
|
+
if (this.options.showInfo) {
|
|
177
|
+
logger_1.default.printLine(`Application crashed: ${error.message}`, 'error');
|
|
178
|
+
}
|
|
179
|
+
// Check if we should restart
|
|
180
|
+
if (this.shouldRestart()) {
|
|
181
|
+
await this.handleCrash();
|
|
182
|
+
}
|
|
183
|
+
return [];
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
shouldRestart() {
|
|
187
|
+
if (!this.options.maxRestarts) {
|
|
188
|
+
return true;
|
|
189
|
+
}
|
|
190
|
+
return this.restartCount < this.options.maxRestarts;
|
|
191
|
+
}
|
|
192
|
+
async handleCrash() {
|
|
193
|
+
const prefix = chalk_1.default.cyan(`[${this.options.runnerName}]`);
|
|
194
|
+
if (this.options.showInfo) {
|
|
195
|
+
logger_1.default.printLine(`${prefix} ${chalk_1.default.red(`${figures_1.default.cross} Application crashed`)}`, 'error');
|
|
196
|
+
logger_1.default.printLine(`${prefix} ${chalk_1.default.yellow(`${figures_1.default.warning} Attempting restart in ${this.options.restartDelay}ms...`)}`, 'info');
|
|
197
|
+
}
|
|
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
|
+
// Wait before restarting
|
|
207
|
+
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
|
+
}
|
|
217
|
+
}
|
|
218
|
+
collectProcessStats() {
|
|
219
|
+
var _a;
|
|
220
|
+
if (!this.options.showInfo) {
|
|
221
|
+
return;
|
|
222
|
+
}
|
|
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
|
+
}
|
|
251
|
+
}
|
|
252
|
+
printStartBanner() {
|
|
253
|
+
var _a, _b;
|
|
254
|
+
if (!this.options.showInfo) {
|
|
255
|
+
return;
|
|
256
|
+
}
|
|
257
|
+
const prefix = chalk_1.default.cyan(`[${this.options.runnerName}]`);
|
|
258
|
+
const uptime = Math.floor((Date.now() - this.startTime.getTime()) / 1000);
|
|
259
|
+
const uptimeStr = this.formatUptime(uptime);
|
|
260
|
+
console.log('\n' + chalk_1.default.bgGreen.black(` ${(_a = this.options.runnerName) === null || _a === void 0 ? void 0 : _a.toUpperCase()} - ${(_b = this.options.environment) === null || _b === void 0 ? void 0 : _b.toUpperCase()} MODE `) + '\n');
|
|
261
|
+
console.log(`${prefix} ${chalk_1.default.green(`${figures_1.default.tick} ${this.options.processName} started successfully`)}`);
|
|
262
|
+
console.log(`${prefix} ${chalk_1.default.blue(`${figures_1.default.info} Runtime: ${this.options.runtime}`)}`);
|
|
263
|
+
console.log(`${prefix} ${chalk_1.default.blue(`${figures_1.default.info} Environment: ${this.options.environment}`)}`);
|
|
264
|
+
console.log(`${prefix} ${chalk_1.default.blue(`${figures_1.default.info} Uptime: ${uptimeStr}`)}`);
|
|
265
|
+
if (this.options.cluster) {
|
|
266
|
+
console.log(`${prefix} ${chalk_1.default.blue(`${figures_1.default.info} Cluster mode: ${this.options.clusterInstances} instances`)}`);
|
|
267
|
+
}
|
|
268
|
+
if (this.options.watch) {
|
|
269
|
+
console.log(`${prefix} ${chalk_1.default.blue(`${figures_1.default.info} Hot reload: enabled`)}`);
|
|
270
|
+
}
|
|
271
|
+
if (this.restartCount > 0) {
|
|
272
|
+
console.log(`${prefix} ${chalk_1.default.yellow(`${figures_1.default.warning} Restarts: ${this.restartCount}`)}`);
|
|
273
|
+
}
|
|
274
|
+
if (this.crashCount > 0) {
|
|
275
|
+
console.log(`${prefix} ${chalk_1.default.red(`${figures_1.default.cross} Crashes: ${this.crashCount}`)}`);
|
|
276
|
+
}
|
|
277
|
+
// Show process stats
|
|
278
|
+
this.collectProcessStats();
|
|
279
|
+
console.log(`${prefix} ${chalk_1.default.blue(`${figures_1.default.info} Memory: ${this.processStats.memoryUsage}MB`)}`);
|
|
280
|
+
if (this.options.memoryLimit) {
|
|
281
|
+
const memoryPercent = Math.round((this.processStats.memoryUsage / this.options.memoryLimit) * 100);
|
|
282
|
+
console.log(`${prefix} ${chalk_1.default.blue(`${figures_1.default.info} Memory usage: ${memoryPercent}%`)}`);
|
|
283
|
+
}
|
|
284
|
+
console.log('');
|
|
285
|
+
}
|
|
286
|
+
formatUptime(seconds) {
|
|
287
|
+
if (seconds < 60) {
|
|
288
|
+
return `${seconds}s`;
|
|
289
|
+
}
|
|
290
|
+
else if (seconds < 3600) {
|
|
291
|
+
const minutes = Math.floor(seconds / 60);
|
|
292
|
+
const remainingSeconds = seconds % 60;
|
|
293
|
+
return `${minutes}m ${remainingSeconds}s`;
|
|
294
|
+
}
|
|
295
|
+
else {
|
|
296
|
+
const hours = Math.floor(seconds / 3600);
|
|
297
|
+
const minutes = Math.floor((seconds % 3600) / 60);
|
|
298
|
+
return `${hours}h ${minutes}m`;
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
monitorResources() {
|
|
302
|
+
if (!this.options.showInfo) {
|
|
303
|
+
return;
|
|
304
|
+
}
|
|
305
|
+
const checkInterval = setInterval(() => {
|
|
306
|
+
if (!this.isRunning) {
|
|
307
|
+
clearInterval(checkInterval);
|
|
308
|
+
return;
|
|
309
|
+
}
|
|
310
|
+
this.collectProcessStats();
|
|
311
|
+
// Check memory limit
|
|
312
|
+
if (this.options.memoryLimit && this.processStats.memoryUsage > this.options.memoryLimit) {
|
|
313
|
+
const prefix = chalk_1.default.cyan(`[${this.options.runnerName}]`);
|
|
314
|
+
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');
|
|
315
|
+
}
|
|
316
|
+
// Log stats every 30 seconds in verbose mode
|
|
317
|
+
if (this.options.verbose && this.processStats.uptime % 30 === 0) {
|
|
318
|
+
const prefix = chalk_1.default.cyan(`[${this.options.runnerName}]`);
|
|
319
|
+
logger_1.default.printLine(`${prefix} ${chalk_1.default.gray(`Stats: ${this.processStats.memoryUsage}MB memory, ${this.formatUptime(this.processStats.uptime)} uptime`)}`, 'info');
|
|
320
|
+
}
|
|
321
|
+
}, 1000);
|
|
322
|
+
}
|
|
323
|
+
async start() {
|
|
324
|
+
this.isRunning = true;
|
|
325
|
+
this.startTime = new Date();
|
|
326
|
+
// Setup file watcher if enabled
|
|
327
|
+
if (this.options.watch) {
|
|
328
|
+
this.setupFileWatcher();
|
|
329
|
+
}
|
|
330
|
+
// Print start banner
|
|
331
|
+
this.printStartBanner();
|
|
332
|
+
// Start file watcher if enabled
|
|
333
|
+
if (this.fileWatcher) {
|
|
334
|
+
await this.fileWatcher.start();
|
|
335
|
+
}
|
|
336
|
+
// Start resource monitoring
|
|
337
|
+
this.monitorResources();
|
|
338
|
+
// Start application
|
|
339
|
+
const prefix = chalk_1.default.cyan(`[${this.options.runnerName}]`);
|
|
340
|
+
if (this.options.showInfo) {
|
|
341
|
+
logger_1.default.printLine(`${prefix} Starting ${this.options.processName}...`, 'info');
|
|
342
|
+
}
|
|
343
|
+
await this.startApplication();
|
|
344
|
+
// Set up graceful shutdown
|
|
345
|
+
this.setupGracefulShutdown();
|
|
346
|
+
if (this.options.showInfo) {
|
|
347
|
+
logger_1.default.printLine(`${prefix} ${this.options.processName} is running in ${this.options.environment} mode`, 'info');
|
|
348
|
+
if (this.options.watch) {
|
|
349
|
+
logger_1.default.printLine(`${prefix} Watching for changes...`, 'info');
|
|
350
|
+
}
|
|
351
|
+
logger_1.default.printLine(`${prefix} Press ${chalk_1.default.cyan('Ctrl+C')} to stop`, 'info');
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
async gracefulRestart() {
|
|
355
|
+
const prefix = chalk_1.default.cyan(`[${this.options.runnerName}]`);
|
|
356
|
+
if (!this.isRunning) {
|
|
357
|
+
return;
|
|
358
|
+
}
|
|
359
|
+
if (!this.shouldRestart()) {
|
|
360
|
+
if (this.options.showInfo) {
|
|
361
|
+
logger_1.default.printLine(`${prefix} ${chalk_1.default.red(`${figures_1.default.cross} Max restarts reached (${this.options.maxRestarts}). Stopping application.`)}`, 'error');
|
|
362
|
+
}
|
|
363
|
+
await this.stop();
|
|
364
|
+
return;
|
|
365
|
+
}
|
|
366
|
+
if (this.options.showInfo) {
|
|
367
|
+
logger_1.default.printLine(`${prefix} ${chalk_1.default.yellow(`${figures_1.default.warning} Gracefully restarting ${this.options.processName}...`)}`, 'info');
|
|
368
|
+
}
|
|
369
|
+
this.restartCount++;
|
|
370
|
+
this.lastRestartTime = new Date();
|
|
371
|
+
// Stop current processes gracefully
|
|
372
|
+
if (this.runner) {
|
|
373
|
+
this.runner.cleanup(this.options.signal);
|
|
374
|
+
}
|
|
375
|
+
// Wait for graceful shutdown
|
|
376
|
+
await new Promise(resolve => setTimeout(resolve, 1000));
|
|
377
|
+
// Print restart banner
|
|
378
|
+
this.printStartBanner();
|
|
379
|
+
// Start application again
|
|
380
|
+
await this.startApplication();
|
|
381
|
+
if (this.options.showInfo) {
|
|
382
|
+
logger_1.default.printLine(`${prefix} ${chalk_1.default.green(`${figures_1.default.tick} ${this.options.processName} restarted successfully`)}`, 'info');
|
|
383
|
+
}
|
|
384
|
+
}
|
|
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
|
+
async stop() {
|
|
415
|
+
const prefix = chalk_1.default.cyan(`[${this.options.runnerName}]`);
|
|
416
|
+
if (!this.isRunning) {
|
|
417
|
+
return;
|
|
418
|
+
}
|
|
419
|
+
if (this.options.showInfo) {
|
|
420
|
+
logger_1.default.printLine(`${prefix} ${chalk_1.default.yellow(`${figures_1.default.warning} Stopping ${this.options.processName}...`)}`, 'info');
|
|
421
|
+
}
|
|
422
|
+
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
|
+
}
|
|
439
|
+
}
|
|
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
|
+
}
|
|
445
|
+
}
|
|
446
|
+
}
|
|
447
|
+
isActive() {
|
|
448
|
+
return this.isRunning;
|
|
449
|
+
}
|
|
450
|
+
getUptime() {
|
|
451
|
+
return Math.floor((Date.now() - this.startTime.getTime()) / 1000);
|
|
452
|
+
}
|
|
453
|
+
getRestartCount() {
|
|
454
|
+
return this.restartCount;
|
|
455
|
+
}
|
|
456
|
+
getCrashCount() {
|
|
457
|
+
return this.crashCount;
|
|
458
|
+
}
|
|
459
|
+
getProcessStats() {
|
|
460
|
+
this.collectProcessStats();
|
|
461
|
+
return { ...this.processStats };
|
|
462
|
+
}
|
|
463
|
+
getLastRestartTime() {
|
|
464
|
+
return this.lastRestartTime;
|
|
465
|
+
}
|
|
466
|
+
getWatchedFiles() {
|
|
467
|
+
var _a;
|
|
468
|
+
return ((_a = this.fileWatcher) === null || _a === void 0 ? void 0 : _a.getWatchedFiles()) || [];
|
|
469
|
+
}
|
|
470
|
+
}
|
|
471
|
+
exports.StartManager = StartManager;
|