neex 0.6.40 → 0.6.41
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/src/dev-runner.js +22 -5
- package/dist/src/logger.js +209 -78
- package/dist/src/runner.js +53 -5
- package/dist/src/watcher.js +16 -6
- package/package.json +1 -1
package/dist/src/dev-runner.js
CHANGED
|
@@ -68,6 +68,10 @@ class DevRunner {
|
|
|
68
68
|
});
|
|
69
69
|
}
|
|
70
70
|
async handleFileChange(event) {
|
|
71
|
+
const prefix = chalk_1.default.cyan(`[${this.options.runnerName}]`);
|
|
72
|
+
if (this.options.showInfo) {
|
|
73
|
+
logger_1.default.printLine(`${prefix} File changed: ${chalk_1.default.yellow(event.relativePath)}`, 'info');
|
|
74
|
+
}
|
|
71
75
|
if (this.options.clearConsole) {
|
|
72
76
|
console.clear();
|
|
73
77
|
}
|
|
@@ -98,6 +102,9 @@ class DevRunner {
|
|
|
98
102
|
return results;
|
|
99
103
|
}
|
|
100
104
|
catch (error) {
|
|
105
|
+
if (this.options.showInfo) {
|
|
106
|
+
logger_1.default.printLine(`Execution failed: ${error.message}`, 'error');
|
|
107
|
+
}
|
|
101
108
|
return [];
|
|
102
109
|
}
|
|
103
110
|
}
|
|
@@ -148,12 +155,16 @@ class DevRunner {
|
|
|
148
155
|
await this.fileWatcher.start();
|
|
149
156
|
}
|
|
150
157
|
// Run initial commands
|
|
158
|
+
const prefix = chalk_1.default.cyan(`[${this.options.runnerName}]`);
|
|
159
|
+
if (this.options.showInfo) {
|
|
160
|
+
logger_1.default.printLine(`${prefix} Starting development server...`, 'info');
|
|
161
|
+
}
|
|
151
162
|
await this.runCommands();
|
|
152
163
|
// Set up graceful shutdown
|
|
153
164
|
this.setupGracefulShutdown();
|
|
154
165
|
if (this.options.showInfo) {
|
|
155
|
-
logger_1.default.printLine(
|
|
156
|
-
logger_1.default.printLine(
|
|
166
|
+
logger_1.default.printLine(`${prefix} Development server started. Watching for changes...`, 'info');
|
|
167
|
+
logger_1.default.printLine(`${prefix} Press ${chalk_1.default.cyan('Ctrl+C')} to stop`, 'info');
|
|
157
168
|
}
|
|
158
169
|
}
|
|
159
170
|
async restart() {
|
|
@@ -161,6 +172,9 @@ class DevRunner {
|
|
|
161
172
|
if (!this.isRunning) {
|
|
162
173
|
return;
|
|
163
174
|
}
|
|
175
|
+
if (this.options.showInfo) {
|
|
176
|
+
logger_1.default.printLine(`${prefix} Restarting due to file changes...`, 'info');
|
|
177
|
+
}
|
|
164
178
|
this.restartCount++;
|
|
165
179
|
// Stop current processes
|
|
166
180
|
if (this.runner) {
|
|
@@ -172,6 +186,9 @@ class DevRunner {
|
|
|
172
186
|
this.printDevBanner();
|
|
173
187
|
// Run commands again
|
|
174
188
|
await this.runCommands();
|
|
189
|
+
if (this.options.showInfo) {
|
|
190
|
+
logger_1.default.printLine(`${prefix} Restart completed. Watching for changes...`, 'info');
|
|
191
|
+
}
|
|
175
192
|
}
|
|
176
193
|
async stop() {
|
|
177
194
|
const prefix = chalk_1.default.cyan(`[${this.options.runnerName}]`);
|
|
@@ -179,7 +196,7 @@ class DevRunner {
|
|
|
179
196
|
return;
|
|
180
197
|
}
|
|
181
198
|
if (this.options.showInfo) {
|
|
182
|
-
logger_1.default.printLine(
|
|
199
|
+
logger_1.default.printLine(`${prefix} Stopping development server...`, 'info');
|
|
183
200
|
}
|
|
184
201
|
this.isRunning = false;
|
|
185
202
|
// Stop file watcher
|
|
@@ -193,9 +210,9 @@ class DevRunner {
|
|
|
193
210
|
const uptime = Math.floor((Date.now() - this.startTime.getTime()) / 1000);
|
|
194
211
|
const uptimeStr = this.formatUptime(uptime);
|
|
195
212
|
if (this.options.showInfo) {
|
|
196
|
-
logger_1.default.printLine(`${this.options.runnerName} development server stopped after ${uptimeStr}`, 'info');
|
|
213
|
+
logger_1.default.printLine(`${prefix} ${this.options.runnerName} development server stopped after ${uptimeStr}`, 'info');
|
|
197
214
|
if (this.restartCount > 0) {
|
|
198
|
-
logger_1.default.printLine(
|
|
215
|
+
logger_1.default.printLine(`${prefix} Total restarts: ${this.restartCount}`, 'info');
|
|
199
216
|
}
|
|
200
217
|
}
|
|
201
218
|
}
|
package/dist/src/logger.js
CHANGED
|
@@ -3,16 +3,21 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
// src/logger.ts
|
|
6
7
|
const chalk_1 = __importDefault(require("chalk"));
|
|
7
8
|
const figures_1 = __importDefault(require("figures"));
|
|
9
|
+
const string_width_1 = __importDefault(require("string-width"));
|
|
10
|
+
const utils_1 = require("./utils");
|
|
8
11
|
class Logger {
|
|
9
|
-
printSummary(results) {
|
|
10
|
-
throw new Error('Method not implemented.');
|
|
11
|
-
}
|
|
12
12
|
constructor() {
|
|
13
|
+
this.prefixLength = 0;
|
|
13
14
|
this.outputBuffer = new Map();
|
|
14
15
|
this.commandColors = new Map();
|
|
15
16
|
this.startTimes = new Map();
|
|
17
|
+
this.spinnerFrames = ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏'];
|
|
18
|
+
this.spinnerIndex = 0;
|
|
19
|
+
this.spinnerIntervals = new Map();
|
|
20
|
+
this.isSpinnerActive = false;
|
|
16
21
|
}
|
|
17
22
|
static getInstance() {
|
|
18
23
|
if (!Logger.instance) {
|
|
@@ -20,28 +25,60 @@ class Logger {
|
|
|
20
25
|
}
|
|
21
26
|
return Logger.instance;
|
|
22
27
|
}
|
|
28
|
+
getSpinnerFrame() {
|
|
29
|
+
const frame = this.spinnerFrames[this.spinnerIndex];
|
|
30
|
+
this.spinnerIndex = (this.spinnerIndex + 1) % this.spinnerFrames.length;
|
|
31
|
+
return frame;
|
|
32
|
+
}
|
|
23
33
|
showBanner() {
|
|
24
34
|
console.log('\n' + chalk_1.default.bgHex('#0066FF').black(' Neex ') + '\n');
|
|
25
35
|
}
|
|
26
36
|
setCommands(commands) {
|
|
27
|
-
//
|
|
37
|
+
// Clear any existing spinner intervals
|
|
38
|
+
this.stopAllSpinners();
|
|
39
|
+
// Show Neex banner
|
|
40
|
+
this.showBanner();
|
|
41
|
+
// Calculate prefix length for aligning output
|
|
42
|
+
this.prefixLength = Math.max(...commands.map(cmd => (0, string_width_1.default)(cmd))) + 3;
|
|
43
|
+
// Initialize buffers and colors for each command
|
|
28
44
|
commands.forEach(cmd => {
|
|
29
45
|
this.outputBuffer.set(cmd, []);
|
|
30
|
-
|
|
31
|
-
this.commandColors.set(cmd, this.getRandomColor());
|
|
32
|
-
}
|
|
46
|
+
this.commandColors.set(cmd, this.generateColor(cmd));
|
|
33
47
|
});
|
|
48
|
+
// Log commands that will be executed
|
|
49
|
+
console.log(chalk_1.default.dim('» Commands to execute:'));
|
|
50
|
+
commands.forEach(cmd => {
|
|
51
|
+
const color = this.commandColors.get(cmd) || chalk_1.default.white;
|
|
52
|
+
console.log(chalk_1.default.dim(' ┌') + color(` ${cmd}`));
|
|
53
|
+
});
|
|
54
|
+
console.log(''); // Add a blank line after commands list
|
|
34
55
|
}
|
|
35
|
-
|
|
56
|
+
generateColor(command) {
|
|
57
|
+
// Generate distinct colors for commands based on the command string
|
|
36
58
|
const vibrantColors = [
|
|
37
|
-
'#
|
|
38
|
-
'#
|
|
59
|
+
'#00BFFF',
|
|
60
|
+
'#32CD32',
|
|
61
|
+
'#FF6347',
|
|
62
|
+
'#9370DB',
|
|
63
|
+
'#FF8C00',
|
|
64
|
+
'#20B2AA',
|
|
65
|
+
'#0066FF',
|
|
66
|
+
'#4169E1',
|
|
67
|
+
'#FFD700',
|
|
68
|
+
'#8A2BE2' // Blue Violet
|
|
39
69
|
];
|
|
40
|
-
|
|
70
|
+
let hash = 0;
|
|
71
|
+
for (let i = 0; i < command.length; i++) {
|
|
72
|
+
hash = (hash << 5) - hash + command.charCodeAt(i);
|
|
73
|
+
hash |= 0; // Convert to 32bit integer
|
|
74
|
+
}
|
|
75
|
+
const colorIndex = Math.abs(hash) % vibrantColors.length;
|
|
41
76
|
return chalk_1.default.hex(vibrantColors[colorIndex]);
|
|
42
77
|
}
|
|
43
78
|
formatPrefix(command) {
|
|
44
|
-
|
|
79
|
+
const color = this.commandColors.get(command) || chalk_1.default.white;
|
|
80
|
+
const prefix = `${command}:`.padEnd(this.prefixLength);
|
|
81
|
+
return color(prefix);
|
|
45
82
|
}
|
|
46
83
|
bufferOutput(output) {
|
|
47
84
|
const currentBuffer = this.outputBuffer.get(output.command) || [];
|
|
@@ -49,92 +86,186 @@ class Logger {
|
|
|
49
86
|
this.outputBuffer.set(output.command, currentBuffer);
|
|
50
87
|
}
|
|
51
88
|
printBuffer(command) {
|
|
52
|
-
this.
|
|
89
|
+
const buffer = this.outputBuffer.get(command) || [];
|
|
90
|
+
const color = this.commandColors.get(command) || chalk_1.default.white;
|
|
91
|
+
// Stop spinner for this command if running
|
|
92
|
+
this.stopSpinner(command);
|
|
93
|
+
buffer.forEach(output => {
|
|
94
|
+
const prefix = this.formatPrefix(output.command);
|
|
95
|
+
const content = output.data.trim();
|
|
96
|
+
if (content) {
|
|
97
|
+
const lines = content.split('\n');
|
|
98
|
+
lines.forEach(line => {
|
|
99
|
+
if (line.trim()) {
|
|
100
|
+
const outputLine = `${prefix} ${line}`;
|
|
101
|
+
// Show stderr in appropriate colors
|
|
102
|
+
if (output.type === 'stderr') {
|
|
103
|
+
// Not all stderr is an error, check for warning or info patterns
|
|
104
|
+
if (line.toLowerCase().includes('warn') || line.toLowerCase().includes('warning')) {
|
|
105
|
+
console.log(`${prefix} ${chalk_1.default.yellow(line)}`);
|
|
106
|
+
}
|
|
107
|
+
else if (line.toLowerCase().includes('error')) {
|
|
108
|
+
console.log(`${prefix} ${chalk_1.default.red(line)}`);
|
|
109
|
+
}
|
|
110
|
+
else {
|
|
111
|
+
console.log(`${prefix} ${line}`);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
else {
|
|
115
|
+
console.log(outputLine);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
});
|
|
121
|
+
// Clear buffer after printing
|
|
122
|
+
this.outputBuffer.set(command, []);
|
|
53
123
|
}
|
|
54
124
|
clearBuffer(command) {
|
|
55
125
|
this.outputBuffer.set(command, []);
|
|
56
126
|
}
|
|
57
|
-
flushBuffer(command) {
|
|
58
|
-
const buffer = this.outputBuffer.get(command);
|
|
59
|
-
if (buffer) {
|
|
60
|
-
buffer.forEach(output => {
|
|
61
|
-
const prefix = this.formatPrefix(output.command);
|
|
62
|
-
const color = this.commandColors.get(output.command) || chalk_1.default.white;
|
|
63
|
-
const formattedOutput = output.data
|
|
64
|
-
.split('\n')
|
|
65
|
-
.filter(line => line.trim() !== '')
|
|
66
|
-
.map(line => `${prefix}${color(line)}`)
|
|
67
|
-
.join('\n');
|
|
68
|
-
if (formattedOutput) {
|
|
69
|
-
if (output.type === 'stderr') {
|
|
70
|
-
console.error(formattedOutput);
|
|
71
|
-
}
|
|
72
|
-
else {
|
|
73
|
-
console.log(formattedOutput);
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
});
|
|
77
|
-
this.outputBuffer.set(command, []);
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
127
|
printLine(message, level = 'info') {
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
128
|
+
if (level === 'error') {
|
|
129
|
+
console.error(chalk_1.default.red(`${figures_1.default.cross} ${message}`));
|
|
130
|
+
}
|
|
131
|
+
else if (level === 'warn') {
|
|
132
|
+
console.warn(chalk_1.default.yellow(`${figures_1.default.warning} ${message}`));
|
|
133
|
+
}
|
|
134
|
+
else {
|
|
135
|
+
console.log(chalk_1.default.blue(`${figures_1.default.info} ${message}`));
|
|
136
|
+
}
|
|
85
137
|
}
|
|
86
138
|
printStart(command) {
|
|
139
|
+
// Record start time
|
|
87
140
|
this.startTimes.set(command, new Date());
|
|
141
|
+
const prefix = this.formatPrefix(command);
|
|
88
142
|
const color = this.commandColors.get(command) || chalk_1.default.white;
|
|
89
|
-
|
|
143
|
+
// Stop any previous spinner for this command (e.g. if retrying)
|
|
144
|
+
this.stopSpinner(command);
|
|
145
|
+
// Clear the line before printing "Starting..."
|
|
146
|
+
if (this.isSpinnerActive) { // Check if any spinner was active to avoid clearing unnecessarily
|
|
147
|
+
process.stdout.write('\r' + ' '.repeat(process.stdout.columns || 80) + '\r');
|
|
148
|
+
}
|
|
149
|
+
console.log(`${prefix} ${color('Starting...')}`);
|
|
150
|
+
// Start spinner for this command
|
|
151
|
+
this.startSpinner(command);
|
|
152
|
+
}
|
|
153
|
+
startSpinner(command) {
|
|
154
|
+
// Only create a spinner if one doesn't already exist for this command
|
|
155
|
+
if (this.spinnerIntervals.has(command)) {
|
|
156
|
+
return;
|
|
157
|
+
}
|
|
158
|
+
this.isSpinnerActive = true;
|
|
159
|
+
const color = this.commandColors.get(command) || chalk_1.default.white;
|
|
160
|
+
const prefix = this.formatPrefix(command);
|
|
161
|
+
const interval = setInterval(() => {
|
|
162
|
+
const frame = this.getSpinnerFrame();
|
|
163
|
+
process.stdout.write(`\r${prefix} ${color(frame)} ${chalk_1.default.dim('Running...')}`);
|
|
164
|
+
}, 80);
|
|
165
|
+
this.spinnerIntervals.set(command, interval);
|
|
166
|
+
}
|
|
167
|
+
stopSpinner(command) {
|
|
168
|
+
const interval = this.spinnerIntervals.get(command);
|
|
169
|
+
if (interval) {
|
|
170
|
+
clearInterval(interval);
|
|
171
|
+
this.spinnerIntervals.delete(command);
|
|
172
|
+
// Clear the spinner line
|
|
173
|
+
if (this.isSpinnerActive) {
|
|
174
|
+
process.stdout.write('\r' + ' '.repeat(process.stdout.columns || 80) + '\r');
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
stopAllSpinners() {
|
|
179
|
+
this.spinnerIntervals.forEach((interval, command) => {
|
|
180
|
+
clearInterval(interval);
|
|
181
|
+
});
|
|
182
|
+
this.spinnerIntervals.clear();
|
|
183
|
+
this.isSpinnerActive = false;
|
|
184
|
+
// Clear the spinner line if any spinner was active
|
|
185
|
+
if (this.isSpinnerActive) {
|
|
186
|
+
process.stdout.write('\r' + ' '.repeat(process.stdout.columns || 80) + '\r');
|
|
187
|
+
}
|
|
90
188
|
}
|
|
91
189
|
printSuccess(result) {
|
|
92
190
|
const { command, duration } = result;
|
|
93
|
-
|
|
191
|
+
this.stopSpinner(command);
|
|
94
192
|
const prefix = this.formatPrefix(command);
|
|
95
|
-
|
|
193
|
+
const color = this.commandColors.get(command) || chalk_1.default.white;
|
|
194
|
+
const durationStr = duration
|
|
195
|
+
? ` ${chalk_1.default.dim(`(${(duration / 1000).toFixed(2)}s)`)}`
|
|
196
|
+
: '';
|
|
197
|
+
console.log(`${prefix} ${chalk_1.default.green(figures_1.default.tick)} ${chalk_1.default.green('Completed')}${durationStr}`);
|
|
96
198
|
}
|
|
97
199
|
printError(result) {
|
|
98
|
-
const { command,
|
|
99
|
-
|
|
200
|
+
const { command, error, code, duration } = result;
|
|
201
|
+
this.stopSpinner(command);
|
|
100
202
|
const prefix = this.formatPrefix(command);
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
203
|
+
const durationStr = duration ? ` ${chalk_1.default.dim(`(${(duration / 1000).toFixed(2)}s)`)}` : '';
|
|
204
|
+
const errorCode = code !== null ? ` ${chalk_1.default.red(`[code: ${code}]`)}` : '';
|
|
205
|
+
console.error(`${prefix} ${chalk_1.default.red(figures_1.default.cross)} ${chalk_1.default.red('Failed')}${errorCode}${durationStr}`);
|
|
206
|
+
if (error) {
|
|
207
|
+
console.error(`${prefix} ${chalk_1.default.red(error.message)}`);
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
printEnd(result, minimalOutput) {
|
|
211
|
+
this.stopSpinner(result.command);
|
|
212
|
+
const prefix = this.formatPrefix(result.command); // Corrected to formatPrefix
|
|
213
|
+
let durationDisplay = '';
|
|
214
|
+
if (result.duration !== null) {
|
|
215
|
+
// Ensure result.duration is treated as a number here
|
|
216
|
+
durationDisplay = `(${(0, utils_1.formatDuration)(result.duration)})`;
|
|
217
|
+
}
|
|
218
|
+
const duration = durationDisplay;
|
|
219
|
+
if (minimalOutput) {
|
|
220
|
+
if (!result.success) {
|
|
221
|
+
const status = result.code !== null ? `failed (code ${result.code})` : 'failed';
|
|
222
|
+
this.printLine(`${prefix} ${chalk_1.default.red(figures_1.default.cross)} ${result.command} ${status} ${duration}`, 'error');
|
|
223
|
+
}
|
|
110
224
|
}
|
|
111
225
|
else {
|
|
112
|
-
|
|
226
|
+
if (result.success) {
|
|
227
|
+
this.printLine(`${prefix} ${chalk_1.default.green(figures_1.default.tick)} Command "${result.command}" finished successfully ${duration}`, 'info');
|
|
228
|
+
}
|
|
229
|
+
else {
|
|
230
|
+
const errorCode = result.code !== null ? ` (code ${result.code})` : '';
|
|
231
|
+
const errorMessage = result.error ? `: ${result.error.message}` : '';
|
|
232
|
+
this.printLine(`${prefix} ${chalk_1.default.red(figures_1.default.cross)} Command "${result.command}" failed${errorCode}${errorMessage} ${duration}`, 'error');
|
|
233
|
+
}
|
|
113
234
|
}
|
|
114
235
|
}
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
236
|
+
printSummary(results) {
|
|
237
|
+
// Stop any remaining spinners
|
|
238
|
+
this.stopAllSpinners();
|
|
239
|
+
const successful = results.filter(r => r.success).length;
|
|
240
|
+
const failed = results.length - successful;
|
|
241
|
+
const totalDuration = results.reduce((sum, result) => sum + (result.duration || 0), 0);
|
|
242
|
+
const totalSeconds = (totalDuration / 1000).toFixed(2);
|
|
243
|
+
console.log('\n' + chalk_1.default.bgHex('#0066FF').black(' Execution Summary ') + '\n');
|
|
244
|
+
console.log(`${chalk_1.default.green(`${figures_1.default.tick} ${successful} succeeded`)}, ${chalk_1.default.red(`${figures_1.default.cross} ${failed} failed`)}`);
|
|
245
|
+
console.log(`${chalk_1.default.blue(figures_1.default.info)} ${chalk_1.default.dim(`Total execution time: ${totalSeconds}s`)}`);
|
|
246
|
+
if (successful > 0) {
|
|
247
|
+
console.log('\n' + chalk_1.default.green.bold('Successful commands:'));
|
|
248
|
+
results
|
|
249
|
+
.filter(r => r.success)
|
|
250
|
+
.forEach(result => {
|
|
251
|
+
const color = this.commandColors.get(result.command) || chalk_1.default.white;
|
|
252
|
+
const duration = result.duration
|
|
253
|
+
? chalk_1.default.dim(` (${(result.duration / 1000).toFixed(2)}s)`)
|
|
254
|
+
: '';
|
|
255
|
+
console.log(` ${chalk_1.default.green(figures_1.default.tick)} ${color(result.command)}${duration}`);
|
|
256
|
+
});
|
|
257
|
+
}
|
|
258
|
+
if (failed > 0) {
|
|
259
|
+
console.log('\n' + chalk_1.default.red.bold('Failed commands:'));
|
|
260
|
+
results
|
|
261
|
+
.filter(r => !r.success)
|
|
262
|
+
.forEach(result => {
|
|
263
|
+
const color = this.commandColors.get(result.command) || chalk_1.default.white;
|
|
264
|
+
const duration = result.duration
|
|
265
|
+
? chalk_1.default.dim(` (${(result.duration / 1000).toFixed(2)}s)`)
|
|
266
|
+
: '';
|
|
267
|
+
const code = result.code !== null ? chalk_1.default.red(` [code: ${result.code}]`) : '';
|
|
268
|
+
console.log(` ${chalk_1.default.red(figures_1.default.cross)} ${color(result.command)}${code}${duration}`);
|
|
138
269
|
});
|
|
139
270
|
}
|
|
140
271
|
}
|
package/dist/src/runner.js
CHANGED
|
@@ -27,9 +27,11 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
27
27
|
};
|
|
28
28
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
29
29
|
exports.Runner = void 0;
|
|
30
|
+
// src/runner.ts - Updated version
|
|
30
31
|
const child_process_1 = require("child_process");
|
|
31
32
|
const fsPromises = __importStar(require("fs/promises"));
|
|
32
33
|
const path = __importStar(require("path"));
|
|
34
|
+
const chalk_1 = __importDefault(require("chalk"));
|
|
33
35
|
const logger_1 = __importDefault(require("./logger"));
|
|
34
36
|
const p_map_1 = __importDefault(require("p-map"));
|
|
35
37
|
const npm_run_path_1 = __importDefault(require("npm-run-path"));
|
|
@@ -54,6 +56,7 @@ class Runner {
|
|
|
54
56
|
}
|
|
55
57
|
}
|
|
56
58
|
catch (error) {
|
|
59
|
+
logger_1.default.printLine(`Could not read or parse package.json: ${error.message}`, 'warn');
|
|
57
60
|
packageJson = { scripts: {} };
|
|
58
61
|
}
|
|
59
62
|
for (const command of commands) {
|
|
@@ -62,12 +65,13 @@ class Runner {
|
|
|
62
65
|
let foundMatch = false;
|
|
63
66
|
for (const scriptName in packageJson.scripts) {
|
|
64
67
|
if (pattern.test(scriptName)) {
|
|
65
|
-
expandedCommands.push(scriptName);
|
|
68
|
+
expandedCommands.push(scriptName); // Or packageJson.scripts[scriptName] if you want the script value
|
|
66
69
|
foundMatch = true;
|
|
67
70
|
}
|
|
68
71
|
}
|
|
69
72
|
if (!foundMatch) {
|
|
70
|
-
|
|
73
|
+
logger_1.default.printLine(`No scripts found in package.json matching wildcard: ${command}`, 'warn');
|
|
74
|
+
expandedCommands.push(command); // Add original command if no match
|
|
71
75
|
}
|
|
72
76
|
}
|
|
73
77
|
else {
|
|
@@ -91,18 +95,21 @@ class Runner {
|
|
|
91
95
|
return { executableCommand: commandToExecute, executionCwd: targetCwd };
|
|
92
96
|
}
|
|
93
97
|
else {
|
|
98
|
+
// It's a script from package.json, but no 'cd ... && ...' pattern
|
|
94
99
|
return { executableCommand: scriptValue, executionCwd: baseDir };
|
|
95
100
|
}
|
|
96
101
|
}
|
|
97
102
|
}
|
|
98
103
|
catch (error) {
|
|
99
|
-
// Errors
|
|
104
|
+
// Errors like package.json not found, or script not in package.json
|
|
105
|
+
// Will treat as direct command
|
|
100
106
|
}
|
|
101
107
|
return { executableCommand: scriptNameOrCommand, executionCwd: undefined };
|
|
102
108
|
}
|
|
103
109
|
detectServerInfo(command, data) {
|
|
104
110
|
if (!this.options.isServerMode)
|
|
105
111
|
return;
|
|
112
|
+
// Get or create server info
|
|
106
113
|
let serverInfo = this.serverInfo.get(command);
|
|
107
114
|
if (!serverInfo) {
|
|
108
115
|
serverInfo = {
|
|
@@ -111,16 +118,25 @@ class Runner {
|
|
|
111
118
|
};
|
|
112
119
|
this.serverInfo.set(command, serverInfo);
|
|
113
120
|
}
|
|
121
|
+
// Try to detect port from output
|
|
114
122
|
const portMatch = data.match(this.portRegex);
|
|
115
123
|
if (portMatch && portMatch[1]) {
|
|
116
124
|
serverInfo.port = parseInt(portMatch[1], 10);
|
|
117
125
|
serverInfo.status = 'running';
|
|
126
|
+
// Only log if we just discovered the port
|
|
127
|
+
if (!serverInfo.url) {
|
|
128
|
+
logger_1.default.printLine(`Server ${command} running on port ${serverInfo.port}`, 'info');
|
|
129
|
+
}
|
|
118
130
|
}
|
|
131
|
+
// Try to detect full URL from output
|
|
119
132
|
const urlMatch = data.match(this.urlRegex);
|
|
120
133
|
if (urlMatch && urlMatch[1]) {
|
|
121
134
|
serverInfo.url = urlMatch[1];
|
|
122
135
|
serverInfo.status = 'running';
|
|
136
|
+
// Log the full URL once we detect it
|
|
137
|
+
logger_1.default.printLine(`Server ${command} available at ${chalk_1.default.cyan(serverInfo.url)}`, 'info');
|
|
123
138
|
}
|
|
139
|
+
// Update server info
|
|
124
140
|
this.serverInfo.set(command, serverInfo);
|
|
125
141
|
}
|
|
126
142
|
async runCommand(originalCommand, currentRetry = 0) {
|
|
@@ -132,7 +148,6 @@ class Runner {
|
|
|
132
148
|
code: null,
|
|
133
149
|
startTime,
|
|
134
150
|
endTime: null,
|
|
135
|
-
duration: 0,
|
|
136
151
|
output: [],
|
|
137
152
|
stderr: []
|
|
138
153
|
};
|
|
@@ -203,11 +218,13 @@ class Runner {
|
|
|
203
218
|
serverInfo.status = 'error';
|
|
204
219
|
this.serverInfo.set(originalCommand, serverInfo);
|
|
205
220
|
}
|
|
221
|
+
logger_1.default.printLine(`Command "${originalCommand}" failed to start: ${err.message}`, 'error');
|
|
206
222
|
}
|
|
207
223
|
logger_1.default.printBuffer(originalCommand);
|
|
208
224
|
if (this.options.printOutput)
|
|
209
225
|
logger_1.default.printEnd(result, this.options.minimalOutput);
|
|
210
226
|
if (this.options.retry && this.options.retry > 0 && currentRetry < this.options.retry) {
|
|
227
|
+
logger_1.default.printLine(`Command "${originalCommand}" failed with error. Retrying (${currentRetry + 1}/${this.options.retry})...`, 'warn');
|
|
211
228
|
if (this.options.retryDelay && this.options.retryDelay > 0) {
|
|
212
229
|
await new Promise(res => setTimeout(res, this.options.retryDelay));
|
|
213
230
|
}
|
|
@@ -223,17 +240,22 @@ class Runner {
|
|
|
223
240
|
result.success = code === 0;
|
|
224
241
|
result.endTime = new Date();
|
|
225
242
|
result.duration = result.endTime.getTime() - startTime.getTime();
|
|
243
|
+
this.activeProcesses.delete(originalCommand);
|
|
226
244
|
if (this.options.isServerMode) {
|
|
227
245
|
const serverInfo = this.serverInfo.get(originalCommand);
|
|
228
246
|
if (serverInfo) {
|
|
229
247
|
serverInfo.status = code === 0 ? 'stopped' : 'error';
|
|
230
248
|
this.serverInfo.set(originalCommand, serverInfo);
|
|
231
249
|
}
|
|
250
|
+
if (code !== 0) {
|
|
251
|
+
logger_1.default.printLine(`Server "${originalCommand}" exited with code ${code}`, 'error');
|
|
252
|
+
}
|
|
232
253
|
}
|
|
233
254
|
logger_1.default.printBuffer(originalCommand);
|
|
234
255
|
if (this.options.printOutput)
|
|
235
256
|
logger_1.default.printEnd(result, this.options.minimalOutput);
|
|
236
257
|
if (!result.success && this.options.retry && this.options.retry > 0 && currentRetry < this.options.retry) {
|
|
258
|
+
logger_1.default.printLine(`Command "${originalCommand}" failed with code ${code}. Retrying (${currentRetry + 1}/${this.options.retry})...`, 'warn');
|
|
237
259
|
if (this.options.retryDelay && this.options.retryDelay > 0) {
|
|
238
260
|
await new Promise(res => setTimeout(res, this.options.retryDelay));
|
|
239
261
|
}
|
|
@@ -269,39 +291,65 @@ class Runner {
|
|
|
269
291
|
});
|
|
270
292
|
}
|
|
271
293
|
catch (error) {
|
|
294
|
+
if (this.options.isServerMode) {
|
|
295
|
+
logger_1.default.printLine('One or more servers failed to start. Stopping all servers.', 'error');
|
|
296
|
+
}
|
|
272
297
|
return [];
|
|
273
298
|
}
|
|
274
299
|
}
|
|
275
300
|
async run(initialCommands) {
|
|
276
301
|
const commands = await this.expandWildcardCommands(initialCommands);
|
|
277
302
|
if (commands.length === 0) {
|
|
303
|
+
logger_1.default.printLine('No commands to run after wildcard expansion.', 'warn');
|
|
278
304
|
return [];
|
|
279
305
|
}
|
|
306
|
+
// Initialize logger with the final list of commands
|
|
280
307
|
logger_1.default.setCommands(commands);
|
|
308
|
+
// Run in parallel or sequential mode
|
|
281
309
|
if (this.options.parallel) {
|
|
310
|
+
if (this.options.isServerMode) {
|
|
311
|
+
logger_1.default.printLine('Starting servers in parallel mode', 'info');
|
|
312
|
+
}
|
|
282
313
|
return this.runParallel(commands);
|
|
283
314
|
}
|
|
284
315
|
else {
|
|
316
|
+
if (this.options.isServerMode) {
|
|
317
|
+
logger_1.default.printLine('Starting servers in sequential mode', 'info');
|
|
318
|
+
}
|
|
285
319
|
return this.runSequential(commands);
|
|
286
320
|
}
|
|
287
321
|
}
|
|
288
322
|
cleanup(signal = 'SIGTERM') {
|
|
323
|
+
logger_1.default.printLine('Cleaning up child processes...', 'warn');
|
|
289
324
|
this.activeProcesses.forEach((proc, command) => {
|
|
290
325
|
if (proc.pid && !proc.killed) {
|
|
291
326
|
try {
|
|
327
|
+
// Kill process group
|
|
292
328
|
process.kill(-proc.pid, signal);
|
|
329
|
+
logger_1.default.printLine(`Sent ${signal} to process group ${proc.pid} (${command})`, 'info');
|
|
293
330
|
}
|
|
294
331
|
catch (e) {
|
|
332
|
+
// Fallback if killing group failed
|
|
295
333
|
try {
|
|
296
334
|
proc.kill(signal);
|
|
335
|
+
logger_1.default.printLine(`Sent ${signal} to process ${proc.pid} (${command})`, 'info');
|
|
297
336
|
}
|
|
298
337
|
catch (errInner) {
|
|
299
|
-
|
|
338
|
+
logger_1.default.printLine(`Failed to kill process ${proc.pid} (${command}): ${errInner.message}`, 'error');
|
|
300
339
|
}
|
|
301
340
|
}
|
|
302
341
|
}
|
|
303
342
|
});
|
|
304
343
|
this.activeProcesses.clear();
|
|
344
|
+
// Print server status summary if in server mode
|
|
345
|
+
if (this.options.isServerMode && this.serverInfo.size > 0) {
|
|
346
|
+
logger_1.default.printLine('Server shutdown summary:', 'info');
|
|
347
|
+
this.serverInfo.forEach((info, command) => {
|
|
348
|
+
const statusColor = info.status === 'running' ? chalk_1.default.green :
|
|
349
|
+
info.status === 'error' ? chalk_1.default.red : chalk_1.default.yellow;
|
|
350
|
+
logger_1.default.printLine(` ${command}: ${statusColor(info.status)}`, 'info');
|
|
351
|
+
});
|
|
352
|
+
}
|
|
305
353
|
}
|
|
306
354
|
}
|
|
307
355
|
exports.Runner = Runner;
|
package/dist/src/watcher.js
CHANGED
|
@@ -22,12 +22,17 @@ var __importStar = (this && this.__importStar) || function (mod) {
|
|
|
22
22
|
__setModuleDefault(result, mod);
|
|
23
23
|
return result;
|
|
24
24
|
};
|
|
25
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
26
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
27
|
+
};
|
|
25
28
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
26
29
|
exports.FileWatcher = void 0;
|
|
27
30
|
// src/watcher.ts - File watcher for development (nodemon functionality)
|
|
28
31
|
const fs = __importStar(require("fs"));
|
|
29
32
|
const path = __importStar(require("path"));
|
|
30
33
|
const events_1 = require("events");
|
|
34
|
+
const chalk_1 = __importDefault(require("chalk"));
|
|
35
|
+
const logger_1 = __importDefault(require("./logger"));
|
|
31
36
|
class FileWatcher extends events_1.EventEmitter {
|
|
32
37
|
constructor(options) {
|
|
33
38
|
super();
|
|
@@ -116,7 +121,7 @@ class FileWatcher extends events_1.EventEmitter {
|
|
|
116
121
|
try {
|
|
117
122
|
const absolutePath = path.resolve(dirPath);
|
|
118
123
|
if (this.options.verbose) {
|
|
119
|
-
|
|
124
|
+
logger_1.default.printLine(`Watching directory: ${chalk_1.default.cyan(absolutePath)}`, 'info');
|
|
120
125
|
}
|
|
121
126
|
const watcher = fs.watch(absolutePath, { recursive: true }, async (eventType, filename) => {
|
|
122
127
|
if (!filename)
|
|
@@ -134,7 +139,7 @@ class FileWatcher extends events_1.EventEmitter {
|
|
|
134
139
|
}
|
|
135
140
|
catch (error) {
|
|
136
141
|
if (this.options.verbose) {
|
|
137
|
-
|
|
142
|
+
logger_1.default.printLine(`Failed to watch directory ${dirPath}: ${error.message}`, 'warn');
|
|
138
143
|
}
|
|
139
144
|
}
|
|
140
145
|
}
|
|
@@ -148,7 +153,7 @@ class FileWatcher extends events_1.EventEmitter {
|
|
|
148
153
|
return;
|
|
149
154
|
}
|
|
150
155
|
if (this.options.verbose) {
|
|
151
|
-
|
|
156
|
+
logger_1.default.printLine(`Watching file: ${chalk_1.default.cyan(absolutePath)}`, 'info');
|
|
152
157
|
}
|
|
153
158
|
const watcher = fs.watch(absolutePath, (eventType) => {
|
|
154
159
|
this.handleFileChange(absolutePath, eventType);
|
|
@@ -158,13 +163,13 @@ class FileWatcher extends events_1.EventEmitter {
|
|
|
158
163
|
}
|
|
159
164
|
catch (error) {
|
|
160
165
|
if (this.options.verbose) {
|
|
161
|
-
|
|
166
|
+
logger_1.default.printLine(`Failed to watch file ${filePath}: ${error.message}`, 'warn');
|
|
162
167
|
}
|
|
163
168
|
}
|
|
164
169
|
}
|
|
165
170
|
handleFileChange(filePath, eventType) {
|
|
166
171
|
if (this.options.verbose) {
|
|
167
|
-
|
|
172
|
+
logger_1.default.printLine(`File ${eventType}: ${chalk_1.default.yellow(path.relative(process.cwd(), filePath))}`, 'info');
|
|
168
173
|
}
|
|
169
174
|
// Debounce file changes
|
|
170
175
|
if (this.debounceTimer) {
|
|
@@ -183,6 +188,7 @@ class FileWatcher extends events_1.EventEmitter {
|
|
|
183
188
|
return;
|
|
184
189
|
}
|
|
185
190
|
this.isWatching = true;
|
|
191
|
+
logger_1.default.printLine('Starting file watcher...', 'info');
|
|
186
192
|
for (const watchPath of this.options.watch) {
|
|
187
193
|
const absolutePath = path.resolve(watchPath);
|
|
188
194
|
try {
|
|
@@ -195,17 +201,20 @@ class FileWatcher extends events_1.EventEmitter {
|
|
|
195
201
|
}
|
|
196
202
|
}
|
|
197
203
|
catch (error) {
|
|
198
|
-
|
|
204
|
+
logger_1.default.printLine(`Cannot watch ${watchPath}: ${error.message}`, 'warn');
|
|
199
205
|
}
|
|
200
206
|
}
|
|
201
207
|
const watchedCount = this.watchers.length;
|
|
208
|
+
logger_1.default.printLine(`File watcher started. Monitoring ${chalk_1.default.green(watchedCount)} locations`, 'info');
|
|
202
209
|
if (this.options.ext && this.options.ext.length > 0) {
|
|
210
|
+
logger_1.default.printLine(`Watching extensions: ${chalk_1.default.cyan(this.options.ext.join(', '))}`, 'info');
|
|
203
211
|
}
|
|
204
212
|
}
|
|
205
213
|
stop() {
|
|
206
214
|
if (!this.isWatching) {
|
|
207
215
|
return;
|
|
208
216
|
}
|
|
217
|
+
logger_1.default.printLine('Stopping file watcher...', 'info');
|
|
209
218
|
this.watchers.forEach(watcher => {
|
|
210
219
|
try {
|
|
211
220
|
watcher.close();
|
|
@@ -221,6 +230,7 @@ class FileWatcher extends events_1.EventEmitter {
|
|
|
221
230
|
clearTimeout(this.debounceTimer);
|
|
222
231
|
this.debounceTimer = null;
|
|
223
232
|
}
|
|
233
|
+
logger_1.default.printLine('File watcher stopped', 'info');
|
|
224
234
|
}
|
|
225
235
|
isActive() {
|
|
226
236
|
return this.isWatching;
|