neex 0.6.18 → 0.6.20

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.
@@ -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 processCommands = (0, index_js_1.addProcessCommands)(program);
26
- cleanupHandlers.push(processCommands.cleanupProcess);
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,227 @@
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
+ await buildManager.start();
199
+ }
200
+ catch (error) {
201
+ console.error(chalk_1.default.red(`${figures_1.default.cross} neex build: Fatal error occurred`));
202
+ if (error instanceof Error) {
203
+ console.error(chalk_1.default.red(`${figures_1.default.cross} Details: ${error.message}`));
204
+ if (options.verbose && error.stack) {
205
+ console.error(chalk_1.default.gray(`Stack trace:\n${error.stack}`));
206
+ }
207
+ }
208
+ else {
209
+ console.error(chalk_1.default.red(`${figures_1.default.cross} Unknown error occurred`));
210
+ }
211
+ console.error(chalk_1.default.yellow(`${figures_1.default.pointer} Try running with --verbose flag for more details`));
212
+ process.exit(1);
213
+ }
214
+ });
215
+ // Return cleanup function for build manager
216
+ return {
217
+ getBuildManager: () => buildManager,
218
+ cleanupBuild: () => {
219
+ if (buildManager && buildManager.isActive()) {
220
+ console.log(chalk_1.default.blue(`${figures_1.default.info} neex build: Stopping build process...`));
221
+ buildManager.stop();
222
+ console.log(chalk_1.default.green(`${figures_1.default.tick} neex build: Build process stopped successfully`));
223
+ }
224
+ }
225
+ };
226
+ }
227
+ 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,178 @@
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 chalk_1 = __importDefault(require("chalk"));
31
+ const figures_1 = __importDefault(require("figures"));
32
+ const path = __importStar(require("path"));
33
+ const fs = __importStar(require("fs/promises"));
34
+ // Helper function to check if file exists
35
+ async function fileExists(filePath) {
36
+ try {
37
+ await fs.access(filePath);
38
+ return true;
39
+ }
40
+ catch (_a) {
41
+ return false;
42
+ }
43
+ }
44
+ // Helper function to determine the best command to start the application
45
+ async function getStartCommand(filePath, showInfo) {
46
+ const ext = path.extname(filePath).toLowerCase();
47
+ const absolutePath = path.resolve(process.cwd(), filePath);
48
+ const fileName = path.basename(filePath, ext);
49
+ // Check if file exists
50
+ if (!(await fileExists(absolutePath))) {
51
+ throw new Error(`File not found: ${filePath}`);
52
+ }
53
+ if (showInfo) {
54
+ console.log(chalk_1.default.blue(`${figures_1.default.info} neex start: Analyzing ${chalk_1.default.cyan(path.basename(filePath))}`));
55
+ }
56
+ switch (ext) {
57
+ case '.js':
58
+ case '.mjs':
59
+ case '.cjs':
60
+ if (showInfo) {
61
+ console.log(chalk_1.default.green(`${figures_1.default.tick} neex start: JavaScript detected, using Node.js runtime`));
62
+ }
63
+ return {
64
+ command: `node ${filePath}`,
65
+ runtime: 'Node.js',
66
+ processName: fileName
67
+ };
68
+ case '.ts':
69
+ case '.mts':
70
+ case '.cts':
71
+ if (showInfo) {
72
+ console.log(chalk_1.default.yellow(`${figures_1.default.warning} neex start: TypeScript detected, consider building first`));
73
+ console.log(chalk_1.default.yellow(`${figures_1.default.pointer} Tip: Run 'neex build ${filePath}' first, then start the built .js file`));
74
+ }
75
+ return {
76
+ command: `npx ts-node ${filePath}`,
77
+ runtime: 'TypeScript (ts-node)',
78
+ processName: fileName
79
+ };
80
+ default:
81
+ if (showInfo) {
82
+ console.log(chalk_1.default.yellow(`${figures_1.default.warning} neex start: Unknown file type, using Node.js`));
83
+ }
84
+ return {
85
+ command: `node ${filePath}`,
86
+ runtime: 'Node.js',
87
+ processName: fileName
88
+ };
89
+ }
90
+ }
91
+ function addStartCommands(program) {
92
+ let startManager = null;
93
+ const cleanupStart = () => {
94
+ if (startManager) {
95
+ startManager.stop();
96
+ startManager = null;
97
+ }
98
+ };
99
+ program
100
+ .command('start <file>')
101
+ .alias('s')
102
+ .description('Start JavaScript/TypeScript applications in production mode')
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('-o, --no-output', 'Hide command output')
107
+ .option('-m, --minimal', 'Use minimal output format')
108
+ .option('-w, --watch', 'Watch for changes and restart (production hot-reload)')
109
+ .option('-i, --ignore <patterns...>', 'Patterns to ignore when watching')
110
+ .option('-e, --ext <extensions...>', 'File extensions to watch (default: js,mjs,json)')
111
+ .option('-d, --delay <ms>', 'Delay before restart in milliseconds', parseInt)
112
+ .option('--max-restarts <number>', 'Maximum number of restarts', parseInt)
113
+ .option('--restart-delay <ms>', 'Delay between restarts in milliseconds', parseInt)
114
+ .option('--verbose', 'Verbose output')
115
+ .option('--info', 'Show detailed information during startup')
116
+ .option('--signal <signal>', 'Signal to send to processes on restart', 'SIGTERM')
117
+ .option('--env <env>', 'Environment mode', 'production')
118
+ .option('--cluster', 'Enable cluster mode (spawn multiple processes)')
119
+ .option('--cluster-instances <number>', 'Number of cluster instances', parseInt)
120
+ .option('--memory-limit <mb>', 'Memory limit in MB', parseInt)
121
+ .option('--cpu-limit <percent>', 'CPU limit percentage', parseInt)
122
+ .action(async (file, options) => {
123
+ try {
124
+ const showInfo = options.info || false;
125
+ if (showInfo) {
126
+ console.log(chalk_1.default.blue(`${figures_1.default.info} neex start: Starting production application server...`));
127
+ console.log(chalk_1.default.blue(`${figures_1.default.info} neex start: Target file: ${chalk_1.default.cyan(file)}`));
128
+ }
129
+ // Validate file parameter
130
+ if (!file || file.trim() === '') {
131
+ console.error(chalk_1.default.red(`${figures_1.default.cross} neex start: Error - No file specified!`));
132
+ console.error(chalk_1.default.yellow(`${figures_1.default.pointer} Usage: neex start <file>`));
133
+ console.error(chalk_1.default.yellow(`${figures_1.default.pointer} Example: neex start dist/server.js`));
134
+ process.exit(1);
135
+ }
136
+ // Get the start command configuration
137
+ let startConfig;
138
+ try {
139
+ startConfig = await getStartCommand(file, showInfo);
140
+ }
141
+ catch (error) {
142
+ console.error(chalk_1.default.red(`${figures_1.default.cross} neex start: ${error instanceof Error ? error.message : 'Unknown error occurred'}`));
143
+ process.exit(1);
144
+ }
145
+ // Setup watch configuration if enabled
146
+ const watchPaths = options.watch ? [path.dirname(file)] : [];
147
+ const ignorePatterns = options.ignore || [
148
+ 'node_modules/**',
149
+ '.git/**',
150
+ '*.log',
151
+ 'src/**',
152
+ 'test/**',
153
+ 'tests/**',
154
+ 'coverage/**',
155
+ '.nyc_output/**',
156
+ '*.tmp',
157
+ '*.temp',
158
+ '.DS_Store',
159
+ 'Thumbs.db'
160
+ ];
161
+ const extensions = options.ext || ['js', 'mjs', 'json'];
162
+ // Log configuration only if --info flag is set
163
+ if (showInfo) {
164
+ console.log(chalk_1.default.blue(`${figures_1.default.info} neex start: Configuration:`));
165
+ console;
166
+ }
167
+ }
168
+ catch (error) {
169
+ console.error(chalk_1.default.red(`${figures_1.default.cross} neex start: ${error instanceof Error ? error.message : 'Unknown error occurred'}`));
170
+ process.exit(1);
171
+ }
172
+ });
173
+ return {
174
+ getStartManager: () => startManager,
175
+ cleanupStart
176
+ };
177
+ }
178
+ exports.addStartCommands = addStartCommands;
@@ -0,0 +1,384 @@
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
+ const defaultOptions = {
49
+ parallel: false,
50
+ printOutput: true,
51
+ color: true,
52
+ showTiming: true,
53
+ prefix: true,
54
+ stopOnError: false,
55
+ minimalOutput: false,
56
+ groupOutput: false,
57
+ isServerMode: true,
58
+ watch: false,
59
+ watchPaths: [],
60
+ ignore: [
61
+ 'node_modules/**',
62
+ '.git/**',
63
+ '*.log',
64
+ 'src/**',
65
+ 'test/**',
66
+ 'tests/**',
67
+ 'coverage/**',
68
+ '.nyc_output/**',
69
+ '*.tmp',
70
+ '*.temp'
71
+ ],
72
+ ext: ['js', 'mjs', 'json'],
73
+ delay: 1000,
74
+ verbose: false,
75
+ showInfo: false,
76
+ runnerName: 'neex start',
77
+ environment: 'production',
78
+ maxRestarts: 10,
79
+ restartDelay: 3000,
80
+ signal: 'SIGTERM',
81
+ cluster: false,
82
+ clusterInstances: os.cpus().length
83
+ };
84
+ this.options = {
85
+ ...defaultOptions,
86
+ ...options
87
+ };
88
+ }
89
+ setupFileWatcher() {
90
+ var _a;
91
+ if (!this.options.watch || !((_a = this.options.watchPaths) === null || _a === void 0 ? void 0 : _a.length)) {
92
+ return;
93
+ }
94
+ const watchOptions = {
95
+ watch: this.options.watchPaths,
96
+ ignore: this.options.ignore,
97
+ ext: this.options.ext,
98
+ delay: this.options.delay,
99
+ verbose: this.options.verbose && this.options.showInfo
100
+ };
101
+ this.fileWatcher = new watcher_1.FileWatcher(watchOptions);
102
+ this.fileWatcher.on('change', (event) => {
103
+ if (this.options.watch && this.isRunning) {
104
+ this.handleFileChange(event);
105
+ }
106
+ });
107
+ }
108
+ async handleFileChange(event) {
109
+ const prefix = chalk_1.default.cyan(`[${this.options.runnerName}]`);
110
+ if (this.options.showInfo) {
111
+ logger_1.default.printLine(`${prefix} File changed: ${chalk_1.default.yellow(event.relativePath)}`, 'info');
112
+ }
113
+ await this.gracefulRestart();
114
+ }
115
+ generateClusterCommand() {
116
+ if (!this.options.cluster) {
117
+ return this.options.command;
118
+ }
119
+ const instances = this.options.clusterInstances || os.cpus().length;
120
+ const baseCommand = this.options.command;
121
+ // For cluster mode, we'll use a simple approach with PM2-like clustering
122
+ // This is a simplified implementation - in real production, you'd use PM2 or similar
123
+ return `${baseCommand} --cluster=${instances}`;
124
+ }
125
+ async startApplication() {
126
+ const command = this.generateClusterCommand();
127
+ // Set environment variables
128
+ const env = {
129
+ ...process.env,
130
+ NODE_ENV: this.options.environment,
131
+ NEEX_START_MODE: 'production',
132
+ NEEX_PROCESS_NAME: this.options.processName
133
+ };
134
+ // Create a modified options object for the runner
135
+ const runnerOptions = {
136
+ ...this.options,
137
+ env,
138
+ customPrefix: () => this.options.processName,
139
+ // Override some options for production
140
+ stopOnError: false,
141
+ restartOnFailure: true,
142
+ maxRestarts: this.options.maxRestarts,
143
+ restartDelay: this.options.restartDelay
144
+ };
145
+ this.runner = new runner_1.Runner(runnerOptions);
146
+ try {
147
+ const results = await this.runner.run([command]);
148
+ return results;
149
+ }
150
+ catch (error) {
151
+ this.crashCount++;
152
+ if (this.options.showInfo) {
153
+ logger_1.default.printLine(`Application crashed: ${error.message}`, 'error');
154
+ }
155
+ // Check if we should restart
156
+ if (this.shouldRestart()) {
157
+ await this.handleCrash();
158
+ }
159
+ return [];
160
+ }
161
+ }
162
+ shouldRestart() {
163
+ if (!this.options.maxRestarts) {
164
+ return true;
165
+ }
166
+ return this.restartCount < this.options.maxRestarts;
167
+ }
168
+ async handleCrash() {
169
+ const prefix = chalk_1.default.cyan(`[${this.options.runnerName}]`);
170
+ if (this.options.showInfo) {
171
+ logger_1.default.printLine(`${prefix} ${chalk_1.default.red(`${figures_1.default.cross} Application crashed`)}`, 'error');
172
+ logger_1.default.printLine(`${prefix} ${chalk_1.default.yellow(`${figures_1.default.warning} Attempting restart in ${this.options.restartDelay}ms...`)}`, 'info');
173
+ }
174
+ // Wait before restarting
175
+ await new Promise(resolve => setTimeout(resolve, this.options.restartDelay));
176
+ await this.gracefulRestart();
177
+ }
178
+ collectProcessStats() {
179
+ if (!this.options.showInfo) {
180
+ return;
181
+ }
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;
188
+ }
189
+ printStartBanner() {
190
+ var _a, _b;
191
+ if (!this.options.showInfo) {
192
+ return;
193
+ }
194
+ const prefix = chalk_1.default.cyan(`[${this.options.runnerName}]`);
195
+ const uptime = Math.floor((Date.now() - this.startTime.getTime()) / 1000);
196
+ const uptimeStr = this.formatUptime(uptime);
197
+ 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');
198
+ console.log(`${prefix} ${chalk_1.default.green(`${figures_1.default.tick} ${this.options.processName} started successfully`)}`);
199
+ console.log(`${prefix} ${chalk_1.default.blue(`${figures_1.default.info} Runtime: ${this.options.runtime}`)}`);
200
+ console.log(`${prefix} ${chalk_1.default.blue(`${figures_1.default.info} Environment: ${this.options.environment}`)}`);
201
+ console.log(`${prefix} ${chalk_1.default.blue(`${figures_1.default.info} Uptime: ${uptimeStr}`)}`);
202
+ if (this.options.cluster) {
203
+ console.log(`${prefix} ${chalk_1.default.blue(`${figures_1.default.info} Cluster mode: ${this.options.clusterInstances} instances`)}`);
204
+ }
205
+ if (this.options.watch) {
206
+ console.log(`${prefix} ${chalk_1.default.blue(`${figures_1.default.info} Hot reload: enabled`)}`);
207
+ }
208
+ if (this.restartCount > 0) {
209
+ console.log(`${prefix} ${chalk_1.default.yellow(`${figures_1.default.warning} Restarts: ${this.restartCount}`)}`);
210
+ }
211
+ if (this.crashCount > 0) {
212
+ console.log(`${prefix} ${chalk_1.default.red(`${figures_1.default.cross} Crashes: ${this.crashCount}`)}`);
213
+ }
214
+ // Show process stats
215
+ this.collectProcessStats();
216
+ console.log(`${prefix} ${chalk_1.default.blue(`${figures_1.default.info} Memory: ${this.processStats.memoryUsage}MB`)}`);
217
+ if (this.options.memoryLimit) {
218
+ const memoryPercent = Math.round((this.processStats.memoryUsage / this.options.memoryLimit) * 100);
219
+ console.log(`${prefix} ${chalk_1.default.blue(`${figures_1.default.info} Memory usage: ${memoryPercent}%`)}`);
220
+ }
221
+ console.log('');
222
+ }
223
+ formatUptime(seconds) {
224
+ if (seconds < 60) {
225
+ return `${seconds}s`;
226
+ }
227
+ else if (seconds < 3600) {
228
+ const minutes = Math.floor(seconds / 60);
229
+ const remainingSeconds = seconds % 60;
230
+ return `${minutes}m ${remainingSeconds}s`;
231
+ }
232
+ else {
233
+ const hours = Math.floor(seconds / 3600);
234
+ const minutes = Math.floor((seconds % 3600) / 60);
235
+ return `${hours}h ${minutes}m`;
236
+ }
237
+ }
238
+ monitorResources() {
239
+ if (!this.options.showInfo) {
240
+ return;
241
+ }
242
+ const checkInterval = setInterval(() => {
243
+ if (!this.isRunning) {
244
+ clearInterval(checkInterval);
245
+ return;
246
+ }
247
+ this.collectProcessStats();
248
+ // Check memory limit
249
+ if (this.options.memoryLimit && this.processStats.memoryUsage > this.options.memoryLimit) {
250
+ const prefix = chalk_1.default.cyan(`[${this.options.runnerName}]`);
251
+ 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');
252
+ }
253
+ // Log stats every 30 seconds in verbose mode
254
+ if (this.options.verbose && this.processStats.uptime % 30 === 0) {
255
+ const prefix = chalk_1.default.cyan(`[${this.options.runnerName}]`);
256
+ logger_1.default.printLine(`${prefix} ${chalk_1.default.gray(`Stats: ${this.processStats.memoryUsage}MB memory, ${this.formatUptime(this.processStats.uptime)} uptime`)}`, 'info');
257
+ }
258
+ }, 1000);
259
+ }
260
+ async start() {
261
+ this.isRunning = true;
262
+ this.startTime = new Date();
263
+ // Setup file watcher if enabled
264
+ if (this.options.watch) {
265
+ this.setupFileWatcher();
266
+ }
267
+ // Print start banner
268
+ this.printStartBanner();
269
+ // Start file watcher if enabled
270
+ if (this.fileWatcher) {
271
+ await this.fileWatcher.start();
272
+ }
273
+ // Start resource monitoring
274
+ this.monitorResources();
275
+ // Start application
276
+ const prefix = chalk_1.default.cyan(`[${this.options.runnerName}]`);
277
+ if (this.options.showInfo) {
278
+ logger_1.default.printLine(`${prefix} Starting ${this.options.processName}...`, 'info');
279
+ }
280
+ await this.startApplication();
281
+ // Set up graceful shutdown
282
+ this.setupGracefulShutdown();
283
+ if (this.options.showInfo) {
284
+ logger_1.default.printLine(`${prefix} ${this.options.processName} is running in ${this.options.environment} mode`, 'info');
285
+ if (this.options.watch) {
286
+ logger_1.default.printLine(`${prefix} Watching for changes...`, 'info');
287
+ }
288
+ logger_1.default.printLine(`${prefix} Press ${chalk_1.default.cyan('Ctrl+C')} to stop`, 'info');
289
+ }
290
+ }
291
+ async gracefulRestart() {
292
+ const prefix = chalk_1.default.cyan(`[${this.options.runnerName}]`);
293
+ if (!this.isRunning) {
294
+ return;
295
+ }
296
+ if (!this.shouldRestart()) {
297
+ if (this.options.showInfo) {
298
+ logger_1.default.printLine(`${prefix} ${chalk_1.default.red(`${figures_1.default.cross} Max restarts reached (${this.options.maxRestarts}). Stopping application.`)}`, 'error');
299
+ }
300
+ await this.stop();
301
+ return;
302
+ }
303
+ if (this.options.showInfo) {
304
+ logger_1.default.printLine(`${prefix} ${chalk_1.default.yellow(`${figures_1.default.warning} Gracefully restarting ${this.options.processName}...`)}`, 'info');
305
+ }
306
+ this.restartCount++;
307
+ this.lastRestartTime = new Date();
308
+ // Stop current processes gracefully
309
+ if (this.runner) {
310
+ this.runner.cleanup(this.options.signal);
311
+ }
312
+ // Wait for graceful shutdown
313
+ await new Promise(resolve => setTimeout(resolve, 1000));
314
+ // Print restart banner
315
+ this.printStartBanner();
316
+ // Start application again
317
+ await this.startApplication();
318
+ if (this.options.showInfo) {
319
+ logger_1.default.printLine(`${prefix} ${chalk_1.default.green(`${figures_1.default.tick} ${this.options.processName} restarted successfully`)}`, 'info');
320
+ }
321
+ }
322
+ async stop() {
323
+ const prefix = chalk_1.default.cyan(`[${this.options.runnerName}]`);
324
+ if (!this.isRunning) {
325
+ return;
326
+ }
327
+ if (this.options.showInfo) {
328
+ logger_1.default.printLine(`${prefix} ${chalk_1.default.yellow(`${figures_1.default.warning} Stopping ${this.options.processName}...`)}`, 'info');
329
+ }
330
+ this.isRunning = false;
331
+ // Stop file watcher
332
+ if (this.fileWatcher) {
333
+ this.fileWatcher.stop();
334
+ }
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');
345
+ }
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
+ }
360
+ isActive() {
361
+ return this.isRunning;
362
+ }
363
+ getUptime() {
364
+ return Math.floor((Date.now() - this.startTime.getTime()) / 1000);
365
+ }
366
+ getRestartCount() {
367
+ return this.restartCount;
368
+ }
369
+ getCrashCount() {
370
+ return this.crashCount;
371
+ }
372
+ getProcessStats() {
373
+ this.collectProcessStats();
374
+ return { ...this.processStats };
375
+ }
376
+ getLastRestartTime() {
377
+ return this.lastRestartTime;
378
+ }
379
+ getWatchedFiles() {
380
+ var _a;
381
+ return ((_a = this.fileWatcher) === null || _a === void 0 ? void 0 : _a.getWatchedFiles()) || [];
382
+ }
383
+ }
384
+ exports.StartManager = StartManager;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "neex",
3
- "version": "0.6.18",
3
+ "version": "0.6.20",
4
4
  "description": "The Modern Build System for Polyrepo-in-Monorepo Architecture",
5
5
  "main": "dist/src/index.js",
6
6
  "types": "dist/src/index.d.ts",