neex 0.1.8 → 0.2.5
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 +39 -226
- package/bun.lock +621 -0
- package/dist/src/cli.js +119 -24
- package/dist/src/index.js +1 -3
- package/dist/src/logger.js +0 -36
- package/dist/src/runner.js +78 -112
- package/package.json +2 -4
- package/dist/src/commands/dev-commands.js +0 -190
- package/dist/src/commands/index.js +0 -21
- package/dist/src/commands/process-commands.js +0 -679
- package/dist/src/commands/run-commands.js +0 -87
- package/dist/src/commands/server-commands.js +0 -50
- package/dist/src/dev-runner.js +0 -209
- package/dist/src/process-manager.js +0 -669
- package/dist/src/utils.js +0 -10
- package/dist/src/watcher.js +0 -245
- package/feet.txt +0 -16
package/dist/src/cli.js
CHANGED
|
@@ -3,48 +3,143 @@ 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/cli.ts -
|
|
6
|
+
// src/cli.ts - Updated version
|
|
7
7
|
const commander_1 = require("commander");
|
|
8
|
-
const index_js_1 = require("./
|
|
8
|
+
const index_js_1 = require("./index.js");
|
|
9
9
|
const chalk_1 = __importDefault(require("chalk"));
|
|
10
10
|
const figures_1 = __importDefault(require("figures"));
|
|
11
11
|
const { version } = require('../../package.json');
|
|
12
12
|
function cli() {
|
|
13
13
|
const program = new commander_1.Command();
|
|
14
|
-
|
|
15
|
-
const cleanupHandlers = [];
|
|
14
|
+
let cleanupRunner = null;
|
|
16
15
|
program
|
|
17
16
|
.name('neex')
|
|
18
|
-
.description('Professional script runner with
|
|
17
|
+
.description('Professional script runner with beautiful colored output')
|
|
19
18
|
.version(version);
|
|
20
|
-
//
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
19
|
+
// Main command for sequential execution (similar to run-s)
|
|
20
|
+
program
|
|
21
|
+
.command('run <commands...>')
|
|
22
|
+
.alias('s')
|
|
23
|
+
.description('Run commands sequentially')
|
|
24
|
+
.option('-c, --no-color', 'Disable colored output')
|
|
25
|
+
.option('-t, --no-timing', 'Hide timing information')
|
|
26
|
+
.option('-p, --no-prefix', 'Hide command prefix')
|
|
27
|
+
.option('-s, --stop-on-error', 'Stop on first error')
|
|
28
|
+
.option('-o, --no-output', 'Hide command output')
|
|
29
|
+
.option('-m, --minimal', 'Use minimal output format')
|
|
30
|
+
.action(async (commands, options) => {
|
|
31
|
+
try {
|
|
32
|
+
await (0, index_js_1.run)(commands, {
|
|
33
|
+
parallel: false,
|
|
34
|
+
color: options.color,
|
|
35
|
+
showTiming: options.timing,
|
|
36
|
+
prefix: options.prefix,
|
|
37
|
+
stopOnError: options.stopOnError,
|
|
38
|
+
printOutput: options.output,
|
|
39
|
+
minimalOutput: options.minimal,
|
|
40
|
+
registerCleanup: (cleanup) => { cleanupRunner = cleanup; }
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
catch (error) {
|
|
44
|
+
if (error instanceof Error) {
|
|
45
|
+
console.error(chalk_1.default.red(`${figures_1.default.cross} Error: ${error.message}`));
|
|
46
|
+
}
|
|
47
|
+
else {
|
|
48
|
+
console.error(chalk_1.default.red(`${figures_1.default.cross} An unknown error occurred`));
|
|
49
|
+
}
|
|
50
|
+
process.exit(1);
|
|
51
|
+
}
|
|
52
|
+
});
|
|
53
|
+
// runx command: parallel execution by default (with alias 'p'), can run sequentially with -q
|
|
54
|
+
program
|
|
55
|
+
.command('runx <commands...>', { isDefault: true })
|
|
56
|
+
.alias('p')
|
|
57
|
+
.description('Run commands in parallel (default) or sequentially with -q. Alias: p')
|
|
58
|
+
.option('-c, --no-color', 'Disable colored output')
|
|
59
|
+
.option('-t, --no-timing', 'Hide timing information')
|
|
60
|
+
.option('-p, --no-prefix', 'Hide command prefix')
|
|
61
|
+
.option('-s, --stop-on-error', 'Stop on first error')
|
|
62
|
+
.option('-o, --no-output', 'Hide command output')
|
|
63
|
+
.option('-m, --minimal', 'Use minimal output format')
|
|
64
|
+
.option('-x, --max-parallel <number>', 'Maximum number of parallel processes', parseInt)
|
|
65
|
+
.option('-q, --sequential', 'Run commands sequentially instead of in parallel')
|
|
66
|
+
.action(async (commands, options) => {
|
|
67
|
+
try {
|
|
68
|
+
await (0, index_js_1.run)(commands, {
|
|
69
|
+
parallel: !options.sequential,
|
|
70
|
+
maxParallel: options.maxParallel,
|
|
71
|
+
color: options.color,
|
|
72
|
+
showTiming: options.timing,
|
|
73
|
+
prefix: options.prefix,
|
|
74
|
+
stopOnError: options.stopOnError,
|
|
75
|
+
printOutput: options.output,
|
|
76
|
+
minimalOutput: options.minimal,
|
|
77
|
+
registerCleanup: (cleanup) => { cleanupRunner = cleanup; }
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
catch (error) {
|
|
81
|
+
if (error instanceof Error) {
|
|
82
|
+
console.error(chalk_1.default.red(`${figures_1.default.cross} Error: ${error.message}`));
|
|
83
|
+
}
|
|
84
|
+
else {
|
|
85
|
+
console.error(chalk_1.default.red(`${figures_1.default.cross} An unknown error occurred`));
|
|
86
|
+
}
|
|
87
|
+
process.exit(1);
|
|
88
|
+
}
|
|
89
|
+
});
|
|
90
|
+
// Add a new servers command specifically optimized for running web servers
|
|
91
|
+
program
|
|
92
|
+
.command('servers <commands...>')
|
|
93
|
+
.alias('srv')
|
|
94
|
+
.description('Run multiple servers with optimized output for API, frontend, etc.')
|
|
95
|
+
.option('-c, --no-color', 'Disable colored output')
|
|
96
|
+
.option('-t, --no-timing', 'Hide timing information')
|
|
97
|
+
.option('-p, --no-prefix', 'Hide command prefix')
|
|
98
|
+
.option('-s, --stop-on-error', 'Stop when any server crashes')
|
|
99
|
+
.option('-x, --max-parallel <number>', 'Maximum number of parallel servers', parseInt)
|
|
100
|
+
.option('-g, --group-output', 'Group outputs by server')
|
|
101
|
+
.action(async (commands, options) => {
|
|
102
|
+
try {
|
|
103
|
+
console.log(chalk_1.default.blue(`${figures_1.default.info} Starting servers in parallel mode...`));
|
|
104
|
+
await (0, index_js_1.run)(commands, {
|
|
105
|
+
parallel: true,
|
|
106
|
+
maxParallel: options.maxParallel,
|
|
107
|
+
color: options.color,
|
|
108
|
+
showTiming: options.timing,
|
|
109
|
+
prefix: options.prefix,
|
|
110
|
+
stopOnError: options.stopOnError,
|
|
111
|
+
printOutput: true,
|
|
112
|
+
registerCleanup: (cleanup) => { cleanupRunner = cleanup; },
|
|
113
|
+
groupOutput: options.groupOutput,
|
|
114
|
+
isServerMode: true // Special flag for server mode formatting
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
catch (error) {
|
|
118
|
+
if (error instanceof Error) {
|
|
119
|
+
console.error(chalk_1.default.red(`${figures_1.default.cross} Server Error: ${error.message}`));
|
|
120
|
+
}
|
|
121
|
+
else {
|
|
122
|
+
console.error(chalk_1.default.red(`${figures_1.default.cross} An unknown server error occurred`));
|
|
123
|
+
}
|
|
124
|
+
process.exit(1);
|
|
125
|
+
}
|
|
126
|
+
});
|
|
27
127
|
program.parse(process.argv);
|
|
28
128
|
// Show help if no commands specified
|
|
29
129
|
if (program.args.length === 0) {
|
|
30
130
|
program.help();
|
|
31
131
|
}
|
|
32
132
|
// Graceful shutdown handling
|
|
33
|
-
const handleSignal =
|
|
133
|
+
const handleSignal = (signal) => {
|
|
34
134
|
console.log(`\n${chalk_1.default.yellow(`${figures_1.default.warning} Received ${signal}. Cleaning up...`)}`);
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
try {
|
|
38
|
-
await cleanup();
|
|
39
|
-
}
|
|
40
|
-
catch (error) {
|
|
41
|
-
console.error(`Cleanup error:`, error);
|
|
42
|
-
}
|
|
135
|
+
if (cleanupRunner) {
|
|
136
|
+
cleanupRunner();
|
|
43
137
|
}
|
|
138
|
+
// Give cleanup a moment, then exit
|
|
44
139
|
setTimeout(() => process.exit(0), 500);
|
|
45
140
|
};
|
|
46
|
-
process.on('SIGINT', () => handleSignal('SIGINT')
|
|
47
|
-
process.on('SIGTERM', () => handleSignal('SIGTERM')
|
|
48
|
-
process.on('SIGQUIT', () => handleSignal('SIGQUIT')
|
|
141
|
+
process.on('SIGINT', () => handleSignal('SIGINT')); // Ctrl+C
|
|
142
|
+
process.on('SIGTERM', () => handleSignal('SIGTERM'));
|
|
143
|
+
process.on('SIGQUIT', () => handleSignal('SIGQUIT'));
|
|
49
144
|
}
|
|
50
145
|
exports.default = cli;
|
package/dist/src/index.js
CHANGED
|
@@ -23,9 +23,7 @@ async function run(commands, options) {
|
|
|
23
23
|
stopOnError: (_f = options === null || options === void 0 ? void 0 : options.stopOnError) !== null && _f !== void 0 ? _f : false,
|
|
24
24
|
minimalOutput: (_g = options === null || options === void 0 ? void 0 : options.minimalOutput) !== null && _g !== void 0 ? _g : false,
|
|
25
25
|
groupOutput: (_h = options === null || options === void 0 ? void 0 : options.groupOutput) !== null && _h !== void 0 ? _h : false,
|
|
26
|
-
isServerMode: (_j = options === null || options === void 0 ? void 0 : options.isServerMode) !== null && _j !== void 0 ? _j : false
|
|
27
|
-
retry: options === null || options === void 0 ? void 0 : options.retry,
|
|
28
|
-
retryDelay: options === null || options === void 0 ? void 0 : options.retryDelay
|
|
26
|
+
isServerMode: (_j = options === null || options === void 0 ? void 0 : options.isServerMode) !== null && _j !== void 0 ? _j : false
|
|
29
27
|
};
|
|
30
28
|
const runner = new runner_1.Runner(runOptions);
|
|
31
29
|
if (options === null || options === void 0 ? void 0 : options.registerCleanup) {
|
package/dist/src/logger.js
CHANGED
|
@@ -7,7 +7,6 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
7
7
|
const chalk_1 = __importDefault(require("chalk"));
|
|
8
8
|
const figures_1 = __importDefault(require("figures"));
|
|
9
9
|
const string_width_1 = __importDefault(require("string-width"));
|
|
10
|
-
const utils_1 = require("./utils");
|
|
11
10
|
class Logger {
|
|
12
11
|
constructor() {
|
|
13
12
|
this.prefixLength = 0;
|
|
@@ -121,9 +120,6 @@ class Logger {
|
|
|
121
120
|
// Clear buffer after printing
|
|
122
121
|
this.outputBuffer.set(command, []);
|
|
123
122
|
}
|
|
124
|
-
clearBuffer(command) {
|
|
125
|
-
this.outputBuffer.set(command, []);
|
|
126
|
-
}
|
|
127
123
|
printLine(message, level = 'info') {
|
|
128
124
|
if (level === 'error') {
|
|
129
125
|
console.error(chalk_1.default.red(`${figures_1.default.cross} ${message}`));
|
|
@@ -140,12 +136,6 @@ class Logger {
|
|
|
140
136
|
this.startTimes.set(command, new Date());
|
|
141
137
|
const prefix = this.formatPrefix(command);
|
|
142
138
|
const color = this.commandColors.get(command) || chalk_1.default.white;
|
|
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
139
|
console.log(`${prefix} ${color('Starting...')}`);
|
|
150
140
|
// Start spinner for this command
|
|
151
141
|
this.startSpinner(command);
|
|
@@ -207,32 +197,6 @@ class Logger {
|
|
|
207
197
|
console.error(`${prefix} ${chalk_1.default.red(error.message)}`);
|
|
208
198
|
}
|
|
209
199
|
}
|
|
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
|
-
}
|
|
224
|
-
}
|
|
225
|
-
else {
|
|
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
|
-
}
|
|
234
|
-
}
|
|
235
|
-
}
|
|
236
200
|
printSummary(results) {
|
|
237
201
|
// Stop any remaining spinners
|
|
238
202
|
this.stopAllSpinners();
|
package/dist/src/runner.js
CHANGED
|
@@ -35,7 +35,6 @@ const chalk_1 = __importDefault(require("chalk"));
|
|
|
35
35
|
const logger_1 = __importDefault(require("./logger"));
|
|
36
36
|
const p_map_1 = __importDefault(require("p-map"));
|
|
37
37
|
const npm_run_path_1 = __importDefault(require("npm-run-path"));
|
|
38
|
-
const fs = __importStar(require("fs"));
|
|
39
38
|
class Runner {
|
|
40
39
|
constructor(options) {
|
|
41
40
|
this.activeProcesses = new Map();
|
|
@@ -45,41 +44,6 @@ class Runner {
|
|
|
45
44
|
this.options = options;
|
|
46
45
|
this.activeProcesses = new Map();
|
|
47
46
|
}
|
|
48
|
-
async expandWildcardCommands(commands) {
|
|
49
|
-
const expandedCommands = [];
|
|
50
|
-
let packageJson;
|
|
51
|
-
try {
|
|
52
|
-
const packageJsonPath = path.join(process.cwd(), 'package.json');
|
|
53
|
-
if (fs.existsSync(packageJsonPath)) {
|
|
54
|
-
const packageJsonContent = await fsPromises.readFile(packageJsonPath, 'utf-8');
|
|
55
|
-
packageJson = JSON.parse(packageJsonContent);
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
catch (error) {
|
|
59
|
-
logger_1.default.printLine(`Could not read or parse package.json: ${error.message}`, 'warn');
|
|
60
|
-
packageJson = { scripts: {} };
|
|
61
|
-
}
|
|
62
|
-
for (const command of commands) {
|
|
63
|
-
if (command.includes('*') && packageJson && packageJson.scripts) {
|
|
64
|
-
const pattern = new RegExp(`^${command.replace(/\*/g, '.*')}$`);
|
|
65
|
-
let foundMatch = false;
|
|
66
|
-
for (const scriptName in packageJson.scripts) {
|
|
67
|
-
if (pattern.test(scriptName)) {
|
|
68
|
-
expandedCommands.push(scriptName); // Or packageJson.scripts[scriptName] if you want the script value
|
|
69
|
-
foundMatch = true;
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
if (!foundMatch) {
|
|
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
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
else {
|
|
78
|
-
expandedCommands.push(command);
|
|
79
|
-
}
|
|
80
|
-
}
|
|
81
|
-
return expandedCommands;
|
|
82
|
-
}
|
|
83
47
|
async resolveScriptAndCwd(scriptNameOrCommand, baseDir) {
|
|
84
48
|
try {
|
|
85
49
|
const packageJsonPath = path.join(baseDir, 'package.json');
|
|
@@ -139,7 +103,7 @@ class Runner {
|
|
|
139
103
|
// Update server info
|
|
140
104
|
this.serverInfo.set(command, serverInfo);
|
|
141
105
|
}
|
|
142
|
-
async runCommand(originalCommand
|
|
106
|
+
async runCommand(originalCommand) {
|
|
143
107
|
const { executableCommand: command, executionCwd: cwd } = await this.resolveScriptAndCwd(originalCommand, process.cwd());
|
|
144
108
|
const startTime = new Date();
|
|
145
109
|
const result = {
|
|
@@ -153,8 +117,7 @@ class Runner {
|
|
|
153
117
|
if (this.options.printOutput) {
|
|
154
118
|
logger_1.default.printStart(originalCommand);
|
|
155
119
|
}
|
|
156
|
-
return new Promise(
|
|
157
|
-
var _a, _b;
|
|
120
|
+
return new Promise((resolve) => {
|
|
158
121
|
const [cmd, ...args] = command.split(' ');
|
|
159
122
|
const env = {
|
|
160
123
|
...process.env,
|
|
@@ -177,93 +140,96 @@ class Runner {
|
|
|
177
140
|
startTime: new Date()
|
|
178
141
|
});
|
|
179
142
|
}
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
143
|
+
// Capture and display output
|
|
144
|
+
if (this.options.printOutput) {
|
|
145
|
+
proc.stdout.on('data', (data) => {
|
|
146
|
+
const output = {
|
|
147
|
+
command: originalCommand,
|
|
148
|
+
type: 'stdout',
|
|
149
|
+
data: data.toString(),
|
|
150
|
+
timestamp: new Date()
|
|
151
|
+
};
|
|
152
|
+
if (this.options.isServerMode) {
|
|
153
|
+
this.detectServerInfo(originalCommand, data.toString());
|
|
154
|
+
}
|
|
155
|
+
// Store output for logging
|
|
156
|
+
if (result.output)
|
|
157
|
+
result.output.push(output);
|
|
158
|
+
logger_1.default.bufferOutput(output);
|
|
159
|
+
// Print immediately unless we're in group mode
|
|
160
|
+
if (!this.options.groupOutput) {
|
|
161
|
+
logger_1.default.printBuffer(originalCommand);
|
|
162
|
+
}
|
|
163
|
+
});
|
|
164
|
+
proc.stderr.on('data', (data) => {
|
|
165
|
+
const output = {
|
|
166
|
+
command: originalCommand,
|
|
167
|
+
type: 'stderr',
|
|
168
|
+
data: data.toString(),
|
|
169
|
+
timestamp: new Date()
|
|
170
|
+
};
|
|
171
|
+
// Store output for logging
|
|
172
|
+
if (result.output)
|
|
173
|
+
result.output.push(output);
|
|
174
|
+
logger_1.default.bufferOutput(output);
|
|
175
|
+
// Print immediately unless we're in group mode
|
|
176
|
+
if (!this.options.groupOutput) {
|
|
177
|
+
logger_1.default.printBuffer(originalCommand);
|
|
178
|
+
}
|
|
179
|
+
});
|
|
180
|
+
}
|
|
181
|
+
proc.on('close', (code) => {
|
|
182
|
+
const endTime = new Date();
|
|
183
|
+
const duration = endTime.getTime() - startTime.getTime();
|
|
184
|
+
result.endTime = endTime;
|
|
185
|
+
result.duration = duration;
|
|
186
|
+
result.code = code;
|
|
187
|
+
result.success = code === 0;
|
|
213
188
|
this.activeProcesses.delete(originalCommand);
|
|
214
189
|
if (this.options.isServerMode) {
|
|
215
190
|
const serverInfo = this.serverInfo.get(originalCommand);
|
|
216
191
|
if (serverInfo) {
|
|
217
|
-
serverInfo.status = 'error';
|
|
192
|
+
serverInfo.status = code === 0 ? 'stopped' : 'error';
|
|
218
193
|
this.serverInfo.set(originalCommand, serverInfo);
|
|
219
194
|
}
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
if (this.options.printOutput)
|
|
224
|
-
logger_1.default.printEnd(result, this.options.minimalOutput);
|
|
225
|
-
if (this.options.retry && this.options.retry > 0 && currentRetry < this.options.retry) {
|
|
226
|
-
logger_1.default.printLine(`Command "${originalCommand}" failed with error. Retrying (${currentRetry + 1}/${this.options.retry})...`, 'warn');
|
|
227
|
-
if (this.options.retryDelay && this.options.retryDelay > 0) {
|
|
228
|
-
await new Promise(res => setTimeout(res, this.options.retryDelay));
|
|
195
|
+
// If this is server mode and a server failed, print prominent error
|
|
196
|
+
if (code !== 0) {
|
|
197
|
+
logger_1.default.printLine(`Server ${originalCommand} crashed with code ${code}`, 'error');
|
|
229
198
|
}
|
|
230
|
-
logger_1.default.clearBuffer(originalCommand);
|
|
231
|
-
resolve(this.runCommand(originalCommand, currentRetry + 1));
|
|
232
199
|
}
|
|
233
|
-
|
|
234
|
-
|
|
200
|
+
// Print grouped output at the end if enabled
|
|
201
|
+
if (this.options.groupOutput && result.output && result.output.length > 0) {
|
|
202
|
+
logger_1.default.printBuffer(originalCommand);
|
|
203
|
+
}
|
|
204
|
+
if (this.options.printOutput) {
|
|
205
|
+
if (result.success) {
|
|
206
|
+
logger_1.default.printSuccess(result);
|
|
207
|
+
}
|
|
208
|
+
else {
|
|
209
|
+
logger_1.default.printError(result);
|
|
210
|
+
}
|
|
235
211
|
}
|
|
212
|
+
resolve(result);
|
|
236
213
|
});
|
|
237
|
-
proc.on('
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
result.endTime =
|
|
241
|
-
result.duration =
|
|
214
|
+
proc.on('error', (error) => {
|
|
215
|
+
const endTime = new Date();
|
|
216
|
+
const duration = endTime.getTime() - startTime.getTime();
|
|
217
|
+
result.endTime = endTime;
|
|
218
|
+
result.duration = duration;
|
|
219
|
+
result.error = error;
|
|
220
|
+
result.success = false;
|
|
242
221
|
this.activeProcesses.delete(originalCommand);
|
|
243
222
|
if (this.options.isServerMode) {
|
|
244
223
|
const serverInfo = this.serverInfo.get(originalCommand);
|
|
245
224
|
if (serverInfo) {
|
|
246
|
-
serverInfo.status =
|
|
225
|
+
serverInfo.status = 'error';
|
|
247
226
|
this.serverInfo.set(originalCommand, serverInfo);
|
|
248
227
|
}
|
|
249
|
-
if (code !== 0) {
|
|
250
|
-
logger_1.default.printLine(`Server "${originalCommand}" exited with code ${code}`, 'error');
|
|
251
|
-
}
|
|
252
228
|
}
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
logger_1.default.printEnd(result, this.options.minimalOutput);
|
|
256
|
-
if (!result.success && this.options.retry && this.options.retry > 0 && currentRetry < this.options.retry) {
|
|
257
|
-
logger_1.default.printLine(`Command "${originalCommand}" failed with code ${code}. Retrying (${currentRetry + 1}/${this.options.retry})...`, 'warn');
|
|
258
|
-
if (this.options.retryDelay && this.options.retryDelay > 0) {
|
|
259
|
-
await new Promise(res => setTimeout(res, this.options.retryDelay));
|
|
260
|
-
}
|
|
261
|
-
logger_1.default.clearBuffer(originalCommand);
|
|
262
|
-
resolve(this.runCommand(originalCommand, currentRetry + 1));
|
|
263
|
-
}
|
|
264
|
-
else {
|
|
265
|
-
resolve(result);
|
|
229
|
+
if (this.options.printOutput) {
|
|
230
|
+
logger_1.default.printError(result);
|
|
266
231
|
}
|
|
232
|
+
resolve(result);
|
|
267
233
|
});
|
|
268
234
|
});
|
|
269
235
|
}
|
|
@@ -272,6 +238,7 @@ class Runner {
|
|
|
272
238
|
for (const cmd of commands) {
|
|
273
239
|
const result = await this.runCommand(cmd);
|
|
274
240
|
results.push(result);
|
|
241
|
+
// Stop on error if enabled
|
|
275
242
|
if (!result.success && this.options.stopOnError) {
|
|
276
243
|
break;
|
|
277
244
|
}
|
|
@@ -290,19 +257,18 @@ class Runner {
|
|
|
290
257
|
});
|
|
291
258
|
}
|
|
292
259
|
catch (error) {
|
|
260
|
+
// If pMap stops due to stopOnError
|
|
293
261
|
if (this.options.isServerMode) {
|
|
294
262
|
logger_1.default.printLine('One or more servers failed to start. Stopping all servers.', 'error');
|
|
295
263
|
}
|
|
296
264
|
return [];
|
|
297
265
|
}
|
|
298
266
|
}
|
|
299
|
-
async run(
|
|
300
|
-
const commands = await this.expandWildcardCommands(initialCommands);
|
|
267
|
+
async run(commands) {
|
|
301
268
|
if (commands.length === 0) {
|
|
302
|
-
logger_1.default.printLine('No commands to run after wildcard expansion.', 'warn');
|
|
303
269
|
return [];
|
|
304
270
|
}
|
|
305
|
-
//
|
|
271
|
+
// Set up logger with commands
|
|
306
272
|
logger_1.default.setCommands(commands);
|
|
307
273
|
// Run in parallel or sequential mode
|
|
308
274
|
if (this.options.parallel) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "neex",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.5",
|
|
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",
|
|
@@ -12,9 +12,7 @@
|
|
|
12
12
|
"start": "node dist/bin/neex.js",
|
|
13
13
|
"prepublishOnly": "npm run build",
|
|
14
14
|
"test": "jest",
|
|
15
|
-
"dev": "neex
|
|
16
|
-
"w": "neex w \"ts-node src/server.ts\"",
|
|
17
|
-
"test:dev": "node ./dist/bin/neex.js px \"echo Starting frontend\" \"echo Starting backend\"",
|
|
15
|
+
"test:dev": "node ./dist/bin/neex.js runx \"echo Starting frontend\" \"echo Starting backend\"",
|
|
18
16
|
"test:parallel": "node ./dist/src/cli.js parallel \"echo Building frontend\" \"echo Building backend\"",
|
|
19
17
|
"test:sequence": "node ./dist/src/cli.js run \"echo Step 1\" \"echo Step 2\" \"echo Step 3\""
|
|
20
18
|
},
|