neex 0.1.7 → 0.1.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/src/cli.js +19 -685
- package/dist/src/commands/dev-commands.js +190 -0
- package/dist/src/commands/index.js +21 -0
- package/dist/src/commands/process-commands.js +679 -0
- package/dist/src/commands/run-commands.js +87 -0
- package/dist/src/commands/server-commands.js +50 -0
- package/dist/src/process-manager.js +395 -152
- package/package.json +1 -1
package/dist/src/cli.js
CHANGED
|
@@ -1,679 +1,29 @@
|
|
|
1
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
2
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
26
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
27
4
|
};
|
|
28
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
29
|
-
// src/cli.ts -
|
|
6
|
+
// src/cli.ts - Main CLI file (refactored)
|
|
30
7
|
const commander_1 = require("commander");
|
|
31
|
-
const index_js_1 = require("./index.js");
|
|
32
|
-
const dev_runner_js_1 = require("./dev-runner.js");
|
|
33
|
-
const process_manager_js_1 = require("./process-manager.js");
|
|
8
|
+
const index_js_1 = require("./commands/index.js");
|
|
34
9
|
const chalk_1 = __importDefault(require("chalk"));
|
|
35
10
|
const figures_1 = __importDefault(require("figures"));
|
|
36
|
-
const path = __importStar(require("path"));
|
|
37
|
-
const fs = __importStar(require("fs/promises")); // Added for reading package.json
|
|
38
11
|
const { version } = require('../../package.json');
|
|
39
|
-
// Helper function to find default command from package.json
|
|
40
|
-
async function findDefaultCommand() {
|
|
41
|
-
var _a, _b;
|
|
42
|
-
try {
|
|
43
|
-
const packageJsonPath = path.join(process.cwd(), 'package.json');
|
|
44
|
-
await fs.access(packageJsonPath);
|
|
45
|
-
const packageJsonContent = await fs.readFile(packageJsonPath, 'utf-8');
|
|
46
|
-
const packageJson = JSON.parse(packageJsonContent);
|
|
47
|
-
if ((_a = packageJson.scripts) === null || _a === void 0 ? void 0 : _a.dev) {
|
|
48
|
-
console.log(chalk_1.default.blue(`${figures_1.default.info} No command provided. Using "dev" script from package.json: npm run dev`));
|
|
49
|
-
return 'npm run dev';
|
|
50
|
-
}
|
|
51
|
-
if ((_b = packageJson.scripts) === null || _b === void 0 ? void 0 : _b.start) {
|
|
52
|
-
console.log(chalk_1.default.blue(`${figures_1.default.info} No command provided. Using "start" script from package.json: npm run start`));
|
|
53
|
-
return 'npm run start';
|
|
54
|
-
}
|
|
55
|
-
if (packageJson.main) {
|
|
56
|
-
const mainFile = packageJson.main;
|
|
57
|
-
const mainFilePath = path.resolve(process.cwd(), mainFile);
|
|
58
|
-
try {
|
|
59
|
-
await fs.access(mainFilePath);
|
|
60
|
-
if (mainFile.endsWith('.ts') || mainFile.endsWith('.mts') || mainFile.endsWith('.cts')) {
|
|
61
|
-
console.log(chalk_1.default.blue(`${figures_1.default.info} No command or script found. Using "main" field (TypeScript): npx ts-node ${mainFile}`));
|
|
62
|
-
return `npx ts-node ${mainFile}`;
|
|
63
|
-
}
|
|
64
|
-
else {
|
|
65
|
-
console.log(chalk_1.default.blue(`${figures_1.default.info} No command or script found. Using "main" field (JavaScript): node ${mainFile}`));
|
|
66
|
-
return `node ${mainFile}`;
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
catch (e) {
|
|
70
|
-
// Main file doesn't exist, do nothing, will fall through to return null
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
return null;
|
|
74
|
-
}
|
|
75
|
-
catch (error) {
|
|
76
|
-
// package.json doesn't exist or other error, do nothing
|
|
77
|
-
return null;
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
12
|
function cli() {
|
|
81
13
|
const program = new commander_1.Command();
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
let processManager = null;
|
|
14
|
+
// Initialize cleanup handlers
|
|
15
|
+
const cleanupHandlers = [];
|
|
85
16
|
program
|
|
86
17
|
.name('neex')
|
|
87
18
|
.description('Professional script runner with nodemon and PM2 functionality')
|
|
88
19
|
.version(version);
|
|
89
|
-
//
|
|
90
|
-
program
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
.option('-p, --no-prefix', 'Hide command prefix')
|
|
97
|
-
.option('-s, --stop-on-error', 'Stop on first error')
|
|
98
|
-
.option('-o, --no-output', 'Hide command output')
|
|
99
|
-
.option('-m, --minimal', 'Use minimal output format')
|
|
100
|
-
.action(async (commands, options) => {
|
|
101
|
-
try {
|
|
102
|
-
await (0, index_js_1.run)(commands, {
|
|
103
|
-
parallel: false,
|
|
104
|
-
color: options.color,
|
|
105
|
-
showTiming: options.timing,
|
|
106
|
-
prefix: options.prefix,
|
|
107
|
-
stopOnError: options.stopOnError,
|
|
108
|
-
printOutput: options.output,
|
|
109
|
-
minimalOutput: options.minimal,
|
|
110
|
-
registerCleanup: (cleanup) => { cleanupRunner = cleanup; }
|
|
111
|
-
});
|
|
112
|
-
}
|
|
113
|
-
catch (error) {
|
|
114
|
-
if (error instanceof Error) {
|
|
115
|
-
console.error(chalk_1.default.red(`${figures_1.default.cross} Error: ${error.message}`));
|
|
116
|
-
}
|
|
117
|
-
else {
|
|
118
|
-
console.error(chalk_1.default.red(`${figures_1.default.cross} An unknown error occurred`));
|
|
119
|
-
}
|
|
120
|
-
process.exit(1);
|
|
121
|
-
}
|
|
122
|
-
});
|
|
123
|
-
// runx command: parallel execution by default (with alias 'p'), can run sequentially with -q
|
|
124
|
-
program
|
|
125
|
-
.command('px <commands...>', { isDefault: true })
|
|
126
|
-
.description('Run commands in parallel (default) or sequentially with -q. This is the default command.')
|
|
127
|
-
.option('-c, --no-color', 'Disable colored output')
|
|
128
|
-
.option('-t, --no-timing', 'Hide timing information')
|
|
129
|
-
.option('-p, --no-prefix', 'Hide command prefix')
|
|
130
|
-
.option('-s, --stop-on-error', 'Stop on first error')
|
|
131
|
-
.option('-o, --no-output', 'Hide command output')
|
|
132
|
-
.option('-m, --minimal', 'Use minimal output format')
|
|
133
|
-
.option('-x, --max-parallel <number>', 'Maximum number of parallel processes', parseInt)
|
|
134
|
-
.option('-q, --sequential', 'Run commands sequentially instead of in parallel')
|
|
135
|
-
.option('--retry <count>', 'Number of times to retry a failed command', parseInt)
|
|
136
|
-
.option('--retry-delay <ms>', 'Delay in milliseconds between retries', parseInt)
|
|
137
|
-
.action(async (commands, options) => {
|
|
138
|
-
try {
|
|
139
|
-
await (0, index_js_1.run)(commands, {
|
|
140
|
-
parallel: !options.sequential,
|
|
141
|
-
maxParallel: options.maxParallel,
|
|
142
|
-
color: options.color,
|
|
143
|
-
showTiming: options.timing,
|
|
144
|
-
prefix: options.prefix,
|
|
145
|
-
stopOnError: options.stopOnError,
|
|
146
|
-
printOutput: options.output,
|
|
147
|
-
minimalOutput: options.minimal,
|
|
148
|
-
retry: options.retry,
|
|
149
|
-
retryDelay: options.retryDelay,
|
|
150
|
-
registerCleanup: (cleanup) => { cleanupRunner = cleanup; }
|
|
151
|
-
});
|
|
152
|
-
}
|
|
153
|
-
catch (error) {
|
|
154
|
-
if (error instanceof Error) {
|
|
155
|
-
console.error(chalk_1.default.red(`${figures_1.default.cross} Error: ${error.message}`));
|
|
156
|
-
}
|
|
157
|
-
else {
|
|
158
|
-
console.error(chalk_1.default.red(`${figures_1.default.cross} An unknown error occurred`));
|
|
159
|
-
}
|
|
160
|
-
process.exit(1);
|
|
161
|
-
}
|
|
162
|
-
});
|
|
163
|
-
// Servers command specifically optimized for running web servers
|
|
164
|
-
program
|
|
165
|
-
.command('servers <commands...>')
|
|
166
|
-
.alias('srv')
|
|
167
|
-
.description('Run multiple servers with optimized output for API, frontend, etc.')
|
|
168
|
-
.option('-c, --no-color', 'Disable colored output')
|
|
169
|
-
.option('-t, --no-timing', 'Hide timing information')
|
|
170
|
-
.option('-p, --no-prefix', 'Hide command prefix')
|
|
171
|
-
.option('-s, --stop-on-error', 'Stop when any server crashes')
|
|
172
|
-
.option('-x, --max-parallel <number>', 'Maximum number of parallel servers', parseInt)
|
|
173
|
-
.option('-g, --group-output', 'Group outputs by server')
|
|
174
|
-
.action(async (commands, options) => {
|
|
175
|
-
try {
|
|
176
|
-
console.log(chalk_1.default.blue(`${figures_1.default.info} Starting servers in parallel mode...`));
|
|
177
|
-
await (0, index_js_1.run)(commands, {
|
|
178
|
-
parallel: true,
|
|
179
|
-
maxParallel: options.maxParallel,
|
|
180
|
-
color: options.color,
|
|
181
|
-
showTiming: options.timing,
|
|
182
|
-
prefix: options.prefix,
|
|
183
|
-
stopOnError: options.stopOnError,
|
|
184
|
-
printOutput: true,
|
|
185
|
-
registerCleanup: (cleanup) => { cleanupRunner = cleanup; },
|
|
186
|
-
groupOutput: options.groupOutput,
|
|
187
|
-
isServerMode: true
|
|
188
|
-
});
|
|
189
|
-
}
|
|
190
|
-
catch (error) {
|
|
191
|
-
if (error instanceof Error) {
|
|
192
|
-
console.error(chalk_1.default.red(`${figures_1.default.cross} Server Error: ${error.message}`));
|
|
193
|
-
}
|
|
194
|
-
else {
|
|
195
|
-
console.error(chalk_1.default.red(`${figures_1.default.cross} An unknown server error occurred`));
|
|
196
|
-
}
|
|
197
|
-
process.exit(1);
|
|
198
|
-
}
|
|
199
|
-
});
|
|
200
|
-
// Dev command (Nodemon functionality - formerly watch)
|
|
201
|
-
program
|
|
202
|
-
.command('dev [commands...]') // Made commands optional
|
|
203
|
-
.alias('d')
|
|
204
|
-
.description('Run commands with file watching and auto-restart (nodemon functionality)')
|
|
205
|
-
.option('-c, --no-color', 'Disable colored output')
|
|
206
|
-
.option('-t, --no-timing', 'Hide timing information')
|
|
207
|
-
.option('-p, --no-prefix', 'Hide command prefix')
|
|
208
|
-
.option('-s, --stop-on-error', 'Stop on first error')
|
|
209
|
-
.option('-o, --no-output', 'Hide command output')
|
|
210
|
-
.option('-m, --minimal', 'Use minimal output format')
|
|
211
|
-
.option('-w, --watch <paths...>', 'Paths to watch (default: current directory)')
|
|
212
|
-
.option('-i, --ignore <patterns...>', 'Patterns to ignore')
|
|
213
|
-
.option('-e, --ext <extensions...>', 'File extensions to watch (default: js,mjs,json,ts,tsx,jsx)')
|
|
214
|
-
.option('-d, --delay <ms>', 'Delay before restart in milliseconds', parseInt)
|
|
215
|
-
.option('--clear', 'Clear console on restart')
|
|
216
|
-
.option('--verbose', 'Verbose output')
|
|
217
|
-
.option('--signal <signal>', 'Signal to send to processes on restart', 'SIGTERM')
|
|
218
|
-
.action(async (commands, options) => {
|
|
219
|
-
try {
|
|
220
|
-
let effectiveCommands = commands;
|
|
221
|
-
if (!effectiveCommands || effectiveCommands.length === 0) {
|
|
222
|
-
const foundCommand = await findDefaultCommand();
|
|
223
|
-
if (foundCommand) {
|
|
224
|
-
effectiveCommands = [foundCommand];
|
|
225
|
-
console.log(chalk_1.default.blue(`${figures_1.default.info} No command specified for 'neex dev', using default: "${foundCommand}"`));
|
|
226
|
-
}
|
|
227
|
-
else {
|
|
228
|
-
console.error(chalk_1.default.red(`${figures_1.default.cross} No command specified for 'neex dev' and no default script (dev, start) or main file found in package.json.`));
|
|
229
|
-
console.error(chalk_1.default.yellow(`${figures_1.default.pointer} Please specify a command to run (e.g., neex dev "npm run dev") or define a "dev" or "start" script in your package.json.`));
|
|
230
|
-
process.exit(1);
|
|
231
|
-
}
|
|
232
|
-
}
|
|
233
|
-
else { // At least one command/argument is provided
|
|
234
|
-
const firstArg = effectiveCommands[0];
|
|
235
|
-
const remainingArgs = effectiveCommands.slice(1);
|
|
236
|
-
const isLikelyCommandOrScript = firstArg.includes(' ') || firstArg.startsWith('npm') || firstArg.startsWith('yarn') || firstArg.startsWith('pnpm');
|
|
237
|
-
if (!isLikelyCommandOrScript) {
|
|
238
|
-
const filePath = path.resolve(process.cwd(), firstArg);
|
|
239
|
-
try {
|
|
240
|
-
await fs.access(filePath); // Check if file exists
|
|
241
|
-
let commandToExecute = '';
|
|
242
|
-
if (firstArg.endsWith('.js') || firstArg.endsWith('.mjs') || firstArg.endsWith('.cjs')) {
|
|
243
|
-
commandToExecute = `node ${firstArg}`;
|
|
244
|
-
console.log(chalk_1.default.blue(`${figures_1.default.info} Detected .js file, prepending with node.`));
|
|
245
|
-
}
|
|
246
|
-
else if (firstArg.endsWith('.ts') || firstArg.endsWith('.mts') || firstArg.endsWith('.cts')) {
|
|
247
|
-
commandToExecute = `npx ts-node ${firstArg}`;
|
|
248
|
-
console.log(chalk_1.default.blue(`${figures_1.default.info} Detected .ts file, prepending with npx ts-node.`));
|
|
249
|
-
}
|
|
250
|
-
if (commandToExecute) {
|
|
251
|
-
effectiveCommands = [commandToExecute, ...remainingArgs];
|
|
252
|
-
console.log(chalk_1.default.cyan(`${figures_1.default.pointer} Executing: ${effectiveCommands.join(' ')}`));
|
|
253
|
-
}
|
|
254
|
-
else {
|
|
255
|
-
// Not a .js or .ts file, or file doesn't exist but doesn't look like a command either.
|
|
256
|
-
// We'll let it try to run as is. If it was meant to be a file, it will likely fail.
|
|
257
|
-
// If it was a command like 'echo', it will run.
|
|
258
|
-
console.log(chalk_1.default.yellow(`${figures_1.default.warning} First argument "${firstArg}" is not a recognized .js/.ts file and doesn't look like a script. Attempting to run as is.`));
|
|
259
|
-
}
|
|
260
|
-
}
|
|
261
|
-
catch (e) {
|
|
262
|
-
// File doesn't exist. Could be a command like 'echo foo' where 'echo' is firstArg.
|
|
263
|
-
// Or could be 'my-script --arg' where 'my-script' is not found.
|
|
264
|
-
// We'll let it try to run as is. DevRunner will handle if the command is not found.
|
|
265
|
-
console.log(chalk_1.default.yellow(`${figures_1.default.warning} File "${firstArg}" not found. Attempting to run as command.`));
|
|
266
|
-
}
|
|
267
|
-
}
|
|
268
|
-
// If isLikelyCommandOrScript is true, or if the file auto-detection didn't apply,
|
|
269
|
-
// effectiveCommands remains as the user provided it (joined later by DevRunner).
|
|
270
|
-
}
|
|
271
|
-
console.log(chalk_1.default.blue(`${figures_1.default.info} Starting development server with file watching (neex dev) for command(s): ${effectiveCommands.map(cmd => `"${cmd}"`).join(' && ')}...`));
|
|
272
|
-
const watchPaths = options.watch || ['./'];
|
|
273
|
-
const ignorePatterns = options.ignore || [
|
|
274
|
-
'node_modules/**', '.git/**', '*.log', 'dist/**', 'build/**',
|
|
275
|
-
'coverage/**', '.nyc_output/**', '*.tmp', '*.temp'
|
|
276
|
-
];
|
|
277
|
-
const extensions = options.ext || ['js', 'mjs', 'json', 'ts', 'tsx', 'jsx'];
|
|
278
|
-
devRunner = new dev_runner_js_1.DevRunner({
|
|
279
|
-
runnerName: 'neex dev',
|
|
280
|
-
parallel: false,
|
|
281
|
-
color: options.color,
|
|
282
|
-
showTiming: options.timing,
|
|
283
|
-
prefix: options.prefix,
|
|
284
|
-
stopOnError: options.stopOnError,
|
|
285
|
-
printOutput: options.output,
|
|
286
|
-
minimalOutput: options.minimal,
|
|
287
|
-
watch: watchPaths,
|
|
288
|
-
ignore: ignorePatterns,
|
|
289
|
-
ext: extensions,
|
|
290
|
-
delay: options.delay || 1000,
|
|
291
|
-
clearConsole: options.clear,
|
|
292
|
-
verbose: options.verbose,
|
|
293
|
-
signal: options.signal,
|
|
294
|
-
restartOnChange: true,
|
|
295
|
-
groupOutput: false,
|
|
296
|
-
isServerMode: false
|
|
297
|
-
});
|
|
298
|
-
await devRunner.start(effectiveCommands);
|
|
299
|
-
}
|
|
300
|
-
catch (error) {
|
|
301
|
-
if (error instanceof Error) {
|
|
302
|
-
console.error(chalk_1.default.red(`${figures_1.default.cross} Dev Error: ${error.message}`));
|
|
303
|
-
}
|
|
304
|
-
else {
|
|
305
|
-
console.error(chalk_1.default.red(`${figures_1.default.cross} An unknown dev error occurred`));
|
|
306
|
-
}
|
|
307
|
-
process.exit(1);
|
|
308
|
-
}
|
|
309
|
-
});
|
|
310
|
-
// Process management commands
|
|
311
|
-
// Start command
|
|
312
|
-
program
|
|
313
|
-
.command('start <script>')
|
|
314
|
-
.description('Start a new process')
|
|
315
|
-
.option('-n, --name <name>', 'Process name')
|
|
316
|
-
.option('-i, --instances <number>', 'Number of instances', parseInt)
|
|
317
|
-
.option('--cwd <path>', 'Working directory')
|
|
318
|
-
.option('--env <env>', 'Environment variables (JSON string)')
|
|
319
|
-
.option('--no-autorestart', 'Disable auto-restart')
|
|
320
|
-
.option('--max-restarts <number>', 'Maximum restarts', parseInt)
|
|
321
|
-
.option('--restart-delay <ms>', 'Restart delay in ms', parseInt)
|
|
322
|
-
.option('--watch', 'Enable file watching')
|
|
323
|
-
.option('--ignore-watch <patterns...>', 'Patterns to ignore when watching')
|
|
324
|
-
.option('--max-memory <size>', 'Max memory before restart (e.g., 1G, 500M)')
|
|
325
|
-
.action(async (script, options) => {
|
|
326
|
-
try {
|
|
327
|
-
if (!processManager) {
|
|
328
|
-
processManager = new process_manager_js_1.ProcessManager();
|
|
329
|
-
}
|
|
330
|
-
const config = {
|
|
331
|
-
id: '',
|
|
332
|
-
name: options.name || path.basename(script, path.extname(script)),
|
|
333
|
-
script,
|
|
334
|
-
cwd: options.cwd,
|
|
335
|
-
env: options.env ? JSON.parse(options.env) : undefined,
|
|
336
|
-
instances: options.instances || 1,
|
|
337
|
-
autorestart: options.autorestart !== false,
|
|
338
|
-
max_restarts: options.maxRestarts || 10,
|
|
339
|
-
restart_delay: options.restartDelay || 1000,
|
|
340
|
-
watch: options.watch || false,
|
|
341
|
-
ignore_watch: options.ignoreWatch,
|
|
342
|
-
max_memory_restart: options.maxMemory
|
|
343
|
-
};
|
|
344
|
-
const id = await processManager.start(config);
|
|
345
|
-
console.log(chalk_1.default.green(`${figures_1.default.tick} Process started with ID: ${id}`));
|
|
346
|
-
}
|
|
347
|
-
catch (error) {
|
|
348
|
-
if (error instanceof Error) {
|
|
349
|
-
console.error(chalk_1.default.red(`${figures_1.default.cross} Start Error: ${error.message}`));
|
|
350
|
-
}
|
|
351
|
-
else {
|
|
352
|
-
console.error(chalk_1.default.red(`${figures_1.default.cross} An unknown start error occurred`));
|
|
353
|
-
}
|
|
354
|
-
process.exit(1);
|
|
355
|
-
}
|
|
356
|
-
});
|
|
357
|
-
// Stop command
|
|
358
|
-
program
|
|
359
|
-
.command('stop <id>')
|
|
360
|
-
.description('Stop a process')
|
|
361
|
-
.action(async (id) => {
|
|
362
|
-
try {
|
|
363
|
-
if (!processManager) {
|
|
364
|
-
processManager = new process_manager_js_1.ProcessManager();
|
|
365
|
-
await processManager.load();
|
|
366
|
-
}
|
|
367
|
-
if (id === 'all') {
|
|
368
|
-
await processManager.stopAll();
|
|
369
|
-
console.log(chalk_1.default.green(`${figures_1.default.tick} All processes stopped`));
|
|
370
|
-
}
|
|
371
|
-
else {
|
|
372
|
-
await processManager.stop(id);
|
|
373
|
-
console.log(chalk_1.default.green(`${figures_1.default.tick} Process ${id} stopped`));
|
|
374
|
-
}
|
|
375
|
-
}
|
|
376
|
-
catch (error) {
|
|
377
|
-
if (error instanceof Error) {
|
|
378
|
-
console.error(chalk_1.default.red(`${figures_1.default.cross} Stop Error: ${error.message}`));
|
|
379
|
-
}
|
|
380
|
-
else {
|
|
381
|
-
console.error(chalk_1.default.red(`${figures_1.default.cross} An unknown stop error occurred`));
|
|
382
|
-
}
|
|
383
|
-
process.exit(1);
|
|
384
|
-
}
|
|
385
|
-
});
|
|
386
|
-
// Restart command
|
|
387
|
-
program
|
|
388
|
-
.command('restart <id>')
|
|
389
|
-
.description('Restart a process')
|
|
390
|
-
.action(async (id) => {
|
|
391
|
-
try {
|
|
392
|
-
if (!processManager) {
|
|
393
|
-
processManager = new process_manager_js_1.ProcessManager();
|
|
394
|
-
await processManager.load();
|
|
395
|
-
}
|
|
396
|
-
if (id === 'all') {
|
|
397
|
-
await processManager.restartAll();
|
|
398
|
-
console.log(chalk_1.default.green(`${figures_1.default.tick} All processes restarted`));
|
|
399
|
-
}
|
|
400
|
-
else {
|
|
401
|
-
await processManager.restart(id);
|
|
402
|
-
console.log(chalk_1.default.green(`${figures_1.default.tick} Process ${id} restarted`));
|
|
403
|
-
}
|
|
404
|
-
}
|
|
405
|
-
catch (error) {
|
|
406
|
-
if (error instanceof Error) {
|
|
407
|
-
console.error(chalk_1.default.red(`${figures_1.default.cross} Restart Error: ${error.message}`));
|
|
408
|
-
}
|
|
409
|
-
else {
|
|
410
|
-
console.error(chalk_1.default.red(`${figures_1.default.cross} An unknown restart error occurred`));
|
|
411
|
-
}
|
|
412
|
-
process.exit(1);
|
|
413
|
-
}
|
|
414
|
-
});
|
|
415
|
-
// Delete command
|
|
416
|
-
program
|
|
417
|
-
.command('delete <id>')
|
|
418
|
-
.description('Delete a process')
|
|
419
|
-
.action(async (id) => {
|
|
420
|
-
try {
|
|
421
|
-
if (!processManager) {
|
|
422
|
-
processManager = new process_manager_js_1.ProcessManager();
|
|
423
|
-
await processManager.load();
|
|
424
|
-
}
|
|
425
|
-
if (id === 'all') {
|
|
426
|
-
await processManager.deleteAll();
|
|
427
|
-
console.log(chalk_1.default.green(`${figures_1.default.tick} All processes deleted`));
|
|
428
|
-
}
|
|
429
|
-
else {
|
|
430
|
-
await processManager.delete(id);
|
|
431
|
-
console.log(chalk_1.default.green(`${figures_1.default.tick} Process ${id} deleted`));
|
|
432
|
-
}
|
|
433
|
-
}
|
|
434
|
-
catch (error) {
|
|
435
|
-
if (error instanceof Error) {
|
|
436
|
-
console.error(chalk_1.default.red(`${figures_1.default.cross} Delete Error: ${error.message}`));
|
|
437
|
-
}
|
|
438
|
-
else {
|
|
439
|
-
console.error(chalk_1.default.red(`${figures_1.default.cross} An unknown delete error occurred`));
|
|
440
|
-
}
|
|
441
|
-
process.exit(1);
|
|
442
|
-
}
|
|
443
|
-
});
|
|
444
|
-
// List/Status command
|
|
445
|
-
program
|
|
446
|
-
.command('list')
|
|
447
|
-
.alias('status')
|
|
448
|
-
.alias('ls')
|
|
449
|
-
.description('List all processes')
|
|
450
|
-
.action(async () => {
|
|
451
|
-
try {
|
|
452
|
-
if (!processManager) {
|
|
453
|
-
processManager = new process_manager_js_1.ProcessManager();
|
|
454
|
-
await processManager.load();
|
|
455
|
-
}
|
|
456
|
-
const processes = await processManager.list();
|
|
457
|
-
if (processes.length === 0) {
|
|
458
|
-
console.log(chalk_1.default.yellow(`${figures_1.default.info} No processes found`));
|
|
459
|
-
return;
|
|
460
|
-
}
|
|
461
|
-
// Print table header
|
|
462
|
-
console.log('\n' + chalk_1.default.bold('Process Management Status'));
|
|
463
|
-
console.log(chalk_1.default.gray('─'.repeat(80)));
|
|
464
|
-
const header = `${chalk_1.default.bold('ID'.padEnd(15))} ${chalk_1.default.bold('Name'.padEnd(20))} ${chalk_1.default.bold('Status'.padEnd(10))} ${chalk_1.default.bold('PID'.padEnd(8))} ${chalk_1.default.bold('Uptime'.padEnd(10))} ${chalk_1.default.bold('Restarts')}`;
|
|
465
|
-
console.log(header);
|
|
466
|
-
console.log(chalk_1.default.gray('─'.repeat(80)));
|
|
467
|
-
// Print process information
|
|
468
|
-
processes.forEach(proc => {
|
|
469
|
-
const statusColor = proc.status === 'online' ? chalk_1.default.green :
|
|
470
|
-
proc.status === 'stopped' ? chalk_1.default.gray :
|
|
471
|
-
proc.status === 'errored' ? chalk_1.default.red : chalk_1.default.yellow;
|
|
472
|
-
const uptime = formatUptime(proc.uptime);
|
|
473
|
-
const pid = proc.pid ? proc.pid.toString() : '-';
|
|
474
|
-
const row = `${proc.id.padEnd(15)} ${proc.name.padEnd(20)} ${statusColor(proc.status.padEnd(10))} ${pid.padEnd(8)} ${uptime.padEnd(10)} ${proc.restarts}`;
|
|
475
|
-
console.log(row);
|
|
476
|
-
});
|
|
477
|
-
console.log(chalk_1.default.gray('─'.repeat(80)));
|
|
478
|
-
console.log(`\n${chalk_1.default.blue(`${figures_1.default.info} Total: ${processes.length} processes`)}`);
|
|
479
|
-
}
|
|
480
|
-
catch (error) {
|
|
481
|
-
if (error instanceof Error) {
|
|
482
|
-
console.error(chalk_1.default.red(`${figures_1.default.cross} List Error: ${error.message}`));
|
|
483
|
-
}
|
|
484
|
-
else {
|
|
485
|
-
console.error(chalk_1.default.red(`${figures_1.default.cross} An unknown list error occurred`));
|
|
486
|
-
}
|
|
487
|
-
process.exit(1);
|
|
488
|
-
}
|
|
489
|
-
});
|
|
490
|
-
// Logs command
|
|
491
|
-
program
|
|
492
|
-
.command('logs [id]')
|
|
493
|
-
.description('Show process logs')
|
|
494
|
-
.option('-f, --follow', 'Follow log output')
|
|
495
|
-
.option('-n, --lines <number>', 'Number of lines to show', (value) => parseInt(value, 10), 15)
|
|
496
|
-
.action(async (id, options) => {
|
|
497
|
-
try {
|
|
498
|
-
if (!processManager) {
|
|
499
|
-
processManager = new process_manager_js_1.ProcessManager();
|
|
500
|
-
await processManager.load();
|
|
501
|
-
}
|
|
502
|
-
if (id) {
|
|
503
|
-
const logs = await processManager.logs(id, options.lines);
|
|
504
|
-
if (logs.length === 0) {
|
|
505
|
-
console.log(chalk_1.default.yellow(`${figures_1.default.info} No logs found for process ${id}`));
|
|
506
|
-
}
|
|
507
|
-
else {
|
|
508
|
-
logs.forEach(log => console.log(log));
|
|
509
|
-
}
|
|
510
|
-
}
|
|
511
|
-
else {
|
|
512
|
-
console.log(chalk_1.default.yellow(`${figures_1.default.info} Please specify a process ID`));
|
|
513
|
-
}
|
|
514
|
-
if (options.follow) {
|
|
515
|
-
console.log(chalk_1.default.blue(`${figures_1.default.info} Following logs... Press Ctrl+C to stop`));
|
|
516
|
-
// TODO: Implement log following
|
|
517
|
-
}
|
|
518
|
-
}
|
|
519
|
-
catch (error) {
|
|
520
|
-
if (error instanceof Error) {
|
|
521
|
-
console.error(chalk_1.default.red(`${figures_1.default.cross} Logs Error: ${error.message}`));
|
|
522
|
-
}
|
|
523
|
-
else {
|
|
524
|
-
console.error(chalk_1.default.red(`${figures_1.default.cross} An unknown logs error occurred`));
|
|
525
|
-
}
|
|
526
|
-
process.exit(1);
|
|
527
|
-
}
|
|
528
|
-
});
|
|
529
|
-
// Save command
|
|
530
|
-
program
|
|
531
|
-
.command('save')
|
|
532
|
-
.description('Save current process list')
|
|
533
|
-
.action(async () => {
|
|
534
|
-
try {
|
|
535
|
-
if (!processManager) {
|
|
536
|
-
processManager = new process_manager_js_1.ProcessManager();
|
|
537
|
-
await processManager.load();
|
|
538
|
-
}
|
|
539
|
-
await processManager.save();
|
|
540
|
-
console.log(chalk_1.default.green(`${figures_1.default.tick} Process list saved`));
|
|
541
|
-
}
|
|
542
|
-
catch (error) {
|
|
543
|
-
if (error instanceof Error) {
|
|
544
|
-
console.error(chalk_1.default.red(`${figures_1.default.cross} Save Error: ${error.message}`));
|
|
545
|
-
}
|
|
546
|
-
else {
|
|
547
|
-
console.error(chalk_1.default.red(`${figures_1.default.cross} An unknown save error occurred`));
|
|
548
|
-
}
|
|
549
|
-
process.exit(1);
|
|
550
|
-
}
|
|
551
|
-
});
|
|
552
|
-
// Startup command (placeholder for system startup configuration)
|
|
553
|
-
program
|
|
554
|
-
.command('startup')
|
|
555
|
-
.description('Generate startup script')
|
|
556
|
-
.action(() => {
|
|
557
|
-
console.log(chalk_1.default.blue(`${figures_1.default.info} Startup script generation:`));
|
|
558
|
-
console.log('\nTo start neex processes on system boot, you can:');
|
|
559
|
-
console.log('1. Create a systemd service (Linux)');
|
|
560
|
-
console.log('2. Use launchd (macOS)');
|
|
561
|
-
console.log('3. Use Windows Service (Windows)');
|
|
562
|
-
console.log('\nExample systemd service file:');
|
|
563
|
-
console.log(chalk_1.default.gray(`
|
|
564
|
-
[Unit]
|
|
565
|
-
Description=Neex Process Manager
|
|
566
|
-
After=network.target
|
|
567
|
-
|
|
568
|
-
[Service]
|
|
569
|
-
Type=simple
|
|
570
|
-
User=your-user
|
|
571
|
-
WorkingDirectory=/path/to/your/project
|
|
572
|
-
ExecStart=/usr/local/bin/neex pm2 resurrect
|
|
573
|
-
Restart=always
|
|
574
|
-
|
|
575
|
-
[Install]
|
|
576
|
-
WantedBy=multi-user.target
|
|
577
|
-
`));
|
|
578
|
-
});
|
|
579
|
-
// Resurrect command (start saved processes)
|
|
580
|
-
program
|
|
581
|
-
.command('resurrect')
|
|
582
|
-
.description('Resurrect previously saved processes')
|
|
583
|
-
.action(async () => {
|
|
584
|
-
try {
|
|
585
|
-
if (!processManager) {
|
|
586
|
-
processManager = new process_manager_js_1.ProcessManager();
|
|
587
|
-
}
|
|
588
|
-
await processManager.load();
|
|
589
|
-
const processes = await processManager.list();
|
|
590
|
-
let started = 0;
|
|
591
|
-
for (const proc of processes) {
|
|
592
|
-
if (proc.status === 'stopped') {
|
|
593
|
-
try {
|
|
594
|
-
await processManager.restart(proc.id);
|
|
595
|
-
started++;
|
|
596
|
-
}
|
|
597
|
-
catch (error) {
|
|
598
|
-
console.log(chalk_1.default.yellow(`${figures_1.default.warning} Failed to start ${proc.id}: ${error.message}`));
|
|
599
|
-
}
|
|
600
|
-
}
|
|
601
|
-
}
|
|
602
|
-
console.log(chalk_1.default.green(`${figures_1.default.tick} Resurrected ${started} processes`));
|
|
603
|
-
}
|
|
604
|
-
catch (error) {
|
|
605
|
-
if (error instanceof Error) {
|
|
606
|
-
console.error(chalk_1.default.red(`${figures_1.default.cross} Resurrect Error: ${error.message}`));
|
|
607
|
-
}
|
|
608
|
-
else {
|
|
609
|
-
console.error(chalk_1.default.red(`${figures_1.default.cross} An unknown resurrect error occurred`));
|
|
610
|
-
}
|
|
611
|
-
process.exit(1);
|
|
612
|
-
}
|
|
613
|
-
});
|
|
614
|
-
// Monit command (monitoring interface)
|
|
615
|
-
program
|
|
616
|
-
.command('monit')
|
|
617
|
-
.description('Launch monitoring interface')
|
|
618
|
-
.action(async () => {
|
|
619
|
-
try {
|
|
620
|
-
if (!processManager) {
|
|
621
|
-
processManager = new process_manager_js_1.ProcessManager();
|
|
622
|
-
await processManager.load();
|
|
623
|
-
}
|
|
624
|
-
console.log(chalk_1.default.blue(`${figures_1.default.info} Starting monitoring interface...`));
|
|
625
|
-
console.log(chalk_1.default.yellow(`${figures_1.default.warning} Press 'q' to quit, 'r' to refresh`));
|
|
626
|
-
// Simple monitoring loop
|
|
627
|
-
const monitorLoop = async () => {
|
|
628
|
-
console.clear();
|
|
629
|
-
console.log(chalk_1.default.bold.blue('Neex Process Monitor'));
|
|
630
|
-
console.log(chalk_1.default.gray('─'.repeat(80)));
|
|
631
|
-
const processes = await processManager.list();
|
|
632
|
-
if (processes.length === 0) {
|
|
633
|
-
console.log(chalk_1.default.yellow(`${figures_1.default.info} No processes running`));
|
|
634
|
-
}
|
|
635
|
-
else {
|
|
636
|
-
processes.forEach(proc => {
|
|
637
|
-
const statusColor = proc.status === 'online' ? chalk_1.default.green :
|
|
638
|
-
proc.status === 'stopped' ? chalk_1.default.gray :
|
|
639
|
-
proc.status === 'errored' ? chalk_1.default.red : chalk_1.default.yellow;
|
|
640
|
-
console.log(`${statusColor('●')} ${proc.name} (${proc.id}) - ${statusColor(proc.status)}`);
|
|
641
|
-
console.log(` PID: ${proc.pid || 'N/A'} | Uptime: ${formatUptime(proc.uptime)} | Restarts: ${proc.restarts}`);
|
|
642
|
-
console.log();
|
|
643
|
-
});
|
|
644
|
-
}
|
|
645
|
-
console.log(chalk_1.default.gray('─'.repeat(80)));
|
|
646
|
-
console.log(chalk_1.default.blue(`Last updated: ${new Date().toLocaleTimeString()}`));
|
|
647
|
-
};
|
|
648
|
-
// Initial display
|
|
649
|
-
await monitorLoop();
|
|
650
|
-
// Set up keyboard input handling
|
|
651
|
-
process.stdin.setRawMode(true);
|
|
652
|
-
process.stdin.resume();
|
|
653
|
-
process.stdin.setEncoding('utf8');
|
|
654
|
-
const interval = setInterval(monitorLoop, 5000);
|
|
655
|
-
process.stdin.on('data', (key) => {
|
|
656
|
-
if (key.toString() === 'q' || key.toString() === '\u0003') { // 'q' or Ctrl+C
|
|
657
|
-
clearInterval(interval);
|
|
658
|
-
process.stdin.setRawMode(false);
|
|
659
|
-
console.log('\n' + chalk_1.default.green(`${figures_1.default.tick} Monitoring stopped`));
|
|
660
|
-
process.exit(0);
|
|
661
|
-
}
|
|
662
|
-
else if (key.toString() === 'r') {
|
|
663
|
-
monitorLoop();
|
|
664
|
-
}
|
|
665
|
-
});
|
|
666
|
-
}
|
|
667
|
-
catch (error) {
|
|
668
|
-
if (error instanceof Error) {
|
|
669
|
-
console.error(chalk_1.default.red(`${figures_1.default.cross} Monit Error: ${error.message}`));
|
|
670
|
-
}
|
|
671
|
-
else {
|
|
672
|
-
console.error(chalk_1.default.red(`${figures_1.default.cross} An unknown monit error occurred`));
|
|
673
|
-
}
|
|
674
|
-
process.exit(1);
|
|
675
|
-
}
|
|
676
|
-
});
|
|
20
|
+
// Add all command groups
|
|
21
|
+
(0, index_js_1.addRunCommands)(program);
|
|
22
|
+
(0, index_js_1.addServerCommands)(program);
|
|
23
|
+
const devCommands = (0, index_js_1.addDevCommands)(program);
|
|
24
|
+
cleanupHandlers.push(devCommands.cleanupDev);
|
|
25
|
+
const processCommands = (0, index_js_1.addProcessCommands)(program);
|
|
26
|
+
cleanupHandlers.push(processCommands.cleanupProcess);
|
|
677
27
|
program.parse(process.argv);
|
|
678
28
|
// Show help if no commands specified
|
|
679
29
|
if (program.args.length === 0) {
|
|
@@ -682,14 +32,14 @@ WantedBy=multi-user.target
|
|
|
682
32
|
// Graceful shutdown handling
|
|
683
33
|
const handleSignal = async (signal) => {
|
|
684
34
|
console.log(`\n${chalk_1.default.yellow(`${figures_1.default.warning} Received ${signal}. Cleaning up...`)}`);
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
35
|
+
// Run all cleanup handlers
|
|
36
|
+
for (const cleanup of cleanupHandlers) {
|
|
37
|
+
try {
|
|
38
|
+
await cleanup();
|
|
39
|
+
}
|
|
40
|
+
catch (error) {
|
|
41
|
+
console.error(`Cleanup error:`, error);
|
|
42
|
+
}
|
|
693
43
|
}
|
|
694
44
|
setTimeout(() => process.exit(0), 500);
|
|
695
45
|
};
|
|
@@ -698,19 +48,3 @@ WantedBy=multi-user.target
|
|
|
698
48
|
process.on('SIGQUIT', () => handleSignal('SIGQUIT').catch(err => console.error('SIGQUIT handler error:', err)));
|
|
699
49
|
}
|
|
700
50
|
exports.default = cli;
|
|
701
|
-
// Helper function to format uptime
|
|
702
|
-
function formatUptime(seconds) {
|
|
703
|
-
if (seconds < 60) {
|
|
704
|
-
return `${seconds}s`;
|
|
705
|
-
}
|
|
706
|
-
else if (seconds < 3600) {
|
|
707
|
-
const minutes = Math.floor(seconds / 60);
|
|
708
|
-
const remainingSeconds = seconds % 60;
|
|
709
|
-
return `${minutes}m ${remainingSeconds}s`;
|
|
710
|
-
}
|
|
711
|
-
else {
|
|
712
|
-
const hours = Math.floor(seconds / 3600);
|
|
713
|
-
const minutes = Math.floor((seconds % 3600) / 60);
|
|
714
|
-
return `${hours}h ${minutes}m`;
|
|
715
|
-
}
|
|
716
|
-
}
|