neex 0.2.7 → 0.2.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 CHANGED
@@ -6,7 +6,7 @@
6
6
  </picture>
7
7
  </a>
8
8
 
9
- # Neex v0.2.7
9
+ # Neex v0.2.8
10
10
  ### 🚀 Neex: The Modern Build System for Polyrepo-in-Monorepo Architecture
11
11
 
12
12
  [![NPM version](https://img.shields.io/npm/v/neex.svg?style=for-the-badge&labelColor=000000&color=0066FF&borderRadius=8)](https://www.npmjs.com/package/neex)
@@ -14,6 +14,8 @@
14
14
  [![MIT License](https://img.shields.io/badge/license-MIT-0066FF.svg?style=for-the-badge&labelColor=000000&borderRadius=8)](https://github.com/neexjs/blob/main/LICENSE)
15
15
  [![GitHub](https://img.shields.io/badge/GitHub-Neex-0066FF.svg?style=for-the-badge&logo=github&labelColor=000000&logoWidth=20&borderRadius=8)](https://github.com/Neexjs)
16
16
 
17
+ </div>
18
+
17
19
  ## 🎯 Overview
18
20
 
19
21
  next + express = neex 🌱
package/bun.lock CHANGED
@@ -6,6 +6,7 @@
6
6
  "dependencies": {
7
7
  "chalk": "^4.1.2",
8
8
  "chokidar": "^3.5.3",
9
+ "cli-table3": "^0.6.5",
9
10
  "commander": "^9.4.0",
10
11
  "figlet": "^1.8.1",
11
12
  "figures": "^3.2.0",
@@ -14,6 +15,7 @@
14
15
  "p-map": "^4.0.0",
15
16
  "string-width": "^4.2.3",
16
17
  "ts-node": "^10.9.1",
18
+ "ts-node-dev": "^2.0.0",
17
19
  "tsconfig-paths": "^4.2.0",
18
20
  },
19
21
  "devDependencies": {
@@ -98,6 +100,8 @@
98
100
 
99
101
  "@bcoe/v8-coverage": ["@bcoe/v8-coverage@0.2.3", "", {}, "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw=="],
100
102
 
103
+ "@colors/colors": ["@colors/colors@1.5.0", "", {}, "sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ=="],
104
+
101
105
  "@cspotcode/source-map-support": ["@cspotcode/source-map-support@0.8.1", "", { "dependencies": { "@jridgewell/trace-mapping": "0.3.9" } }, "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw=="],
102
106
 
103
107
  "@istanbuljs/load-nyc-config": ["@istanbuljs/load-nyc-config@1.1.0", "", { "dependencies": { "camelcase": "^5.3.1", "find-up": "^4.1.0", "get-package-type": "^0.1.0", "js-yaml": "^3.13.1", "resolve-from": "^5.0.0" } }, "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ=="],
@@ -182,6 +186,10 @@
182
186
 
183
187
  "@types/stack-utils": ["@types/stack-utils@2.0.3", "", {}, "sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw=="],
184
188
 
189
+ "@types/strip-bom": ["@types/strip-bom@3.0.0", "", {}, "sha512-xevGOReSYGM7g/kUBZzPqCrR/KYAo+F0yiPc85WFTJa0MSLtyFTVTU6cJu/aV4mid7IffDIWqo69THF2o4JiEQ=="],
190
+
191
+ "@types/strip-json-comments": ["@types/strip-json-comments@0.0.30", "", {}, "sha512-7NQmHra/JILCd1QqpSzl8+mJRc8ZHz3uDm8YV1Ks9IhK0epEiTw8aIErbvH9PI+6XbqhyIQy3462nEsn7UVzjQ=="],
192
+
185
193
  "@types/tinycolor2": ["@types/tinycolor2@1.4.6", "", {}, "sha512-iEN8J0BoMnsWBqjVbWH/c0G0Hh7O21lpR2/+PrvAVgWdzL7eexIFm4JN/Wn10PTcmNdtS6U67r499mlWMXOxNw=="],
186
194
 
187
195
  "@types/yargs": ["@types/yargs@17.0.33", "", { "dependencies": { "@types/yargs-parser": "*" } }, "sha512-WpxBCKWPLr4xSsHgz511rFJAM+wS28w2zEO1QDNY5zM/S8ok70NNfztH0xwhqKyaK0OHCbN98LDAZuy1ctxDkA=="],
@@ -252,6 +260,8 @@
252
260
 
253
261
  "clean-stack": ["clean-stack@2.2.0", "", {}, "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A=="],
254
262
 
263
+ "cli-table3": ["cli-table3@0.6.5", "", { "dependencies": { "string-width": "^4.2.0" }, "optionalDependencies": { "@colors/colors": "1.5.0" } }, "sha512-+W/5efTR7y5HRD7gACw9yQjqMVvEMLBHmboM/kPWam+H+Hmyrgjh6YncVKK122YZkXrLudzTuAukUw9FnMf7IQ=="],
264
+
255
265
  "cliui": ["cliui@8.0.1", "", { "dependencies": { "string-width": "^4.2.0", "strip-ansi": "^6.0.1", "wrap-ansi": "^7.0.0" } }, "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ=="],
256
266
 
257
267
  "co": ["co@4.6.0", "", {}, "sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ=="],
@@ -286,6 +296,8 @@
286
296
 
287
297
  "diff-sequences": ["diff-sequences@29.6.3", "", {}, "sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q=="],
288
298
 
299
+ "dynamic-dedupe": ["dynamic-dedupe@0.3.0", "", { "dependencies": { "xtend": "^4.0.0" } }, "sha512-ssuANeD+z97meYOqd50e04Ze5qp4bPqo8cCkI4TRjZkzAUgIDTrXV1R8QCdINpiI+hw14+rYazvTRdQrz0/rFQ=="],
300
+
289
301
  "ejs": ["ejs@3.1.10", "", { "dependencies": { "jake": "^10.8.5" }, "bin": "bin/cli.js" }, "sha512-UeJmFfOrAQS8OJWPZ4qtgHyWExa088/MtK5UEyoJGFH67cDEXkZSviOiKRCZ4Xij0zxI3JECgYs3oKx+AizQBA=="],
290
302
 
291
303
  "electron-to-chromium": ["electron-to-chromium@1.5.152", "", {}, "sha512-xBOfg/EBaIlVsHipHl2VdTPJRSvErNUaqW8ejTq5OlOlIYx1wOllCHsAvAIrr55jD1IYEfdR86miUEt8H5IeJg=="],
@@ -486,6 +498,8 @@
486
498
 
487
499
  "minimist": ["minimist@1.2.8", "", {}, "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA=="],
488
500
 
501
+ "mkdirp": ["mkdirp@1.0.4", "", { "bin": { "mkdirp": "bin/cmd.js" } }, "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw=="],
502
+
489
503
  "ms": ["ms@2.1.3", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="],
490
504
 
491
505
  "natural-compare": ["natural-compare@1.4.0", "", {}, "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw=="],
@@ -548,6 +562,8 @@
548
562
 
549
563
  "resolve.exports": ["resolve.exports@2.0.3", "", {}, "sha512-OcXjMsGdhL4XnbShKpAcSqPMzQoYkYyhbEaeSko47MjRP9NfEQMhZkXL1DoFlt9LWQn4YttrdnV6X2OiyzBi+A=="],
550
564
 
565
+ "rimraf": ["rimraf@2.7.1", "", { "dependencies": { "glob": "^7.1.3" }, "bin": { "rimraf": "./bin.js" } }, "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w=="],
566
+
551
567
  "semver": ["semver@7.7.2", "", { "bin": "bin/semver.js" }, "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA=="],
552
568
 
553
569
  "shebang-command": ["shebang-command@2.0.0", "", { "dependencies": { "shebang-regex": "^3.0.0" } }, "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA=="],
@@ -578,7 +594,7 @@
578
594
 
579
595
  "strip-final-newline": ["strip-final-newline@2.0.0", "", {}, "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA=="],
580
596
 
581
- "strip-json-comments": ["strip-json-comments@3.1.1", "", {}, "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig=="],
597
+ "strip-json-comments": ["strip-json-comments@2.0.1", "", {}, "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ=="],
582
598
 
583
599
  "supports-color": ["supports-color@7.2.0", "", { "dependencies": { "has-flag": "^4.0.0" } }, "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw=="],
584
600
 
@@ -594,10 +610,16 @@
594
610
 
595
611
  "to-regex-range": ["to-regex-range@5.0.1", "", { "dependencies": { "is-number": "^7.0.0" } }, "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ=="],
596
612
 
613
+ "tree-kill": ["tree-kill@1.2.2", "", { "bin": { "tree-kill": "cli.js" } }, "sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A=="],
614
+
597
615
  "ts-jest": ["ts-jest@29.3.2", "", { "dependencies": { "bs-logger": "^0.2.6", "ejs": "^3.1.10", "fast-json-stable-stringify": "^2.1.0", "jest-util": "^29.0.0", "json5": "^2.2.3", "lodash.memoize": "^4.1.2", "make-error": "^1.3.6", "semver": "^7.7.1", "type-fest": "^4.39.1", "yargs-parser": "^21.1.1" }, "peerDependencies": { "@babel/core": ">=7.0.0-beta.0 <8", "@jest/transform": "^29.0.0", "@jest/types": "^29.0.0", "babel-jest": "^29.0.0", "jest": "^29.0.0", "typescript": ">=4.3 <6" }, "bin": "cli.js" }, "sha512-bJJkrWc6PjFVz5g2DGCNUo8z7oFEYaz1xP1NpeDU7KNLMWPpEyV8Chbpkn8xjzgRDpQhnGMyvyldoL7h8JXyug=="],
598
616
 
599
617
  "ts-node": ["ts-node@10.9.2", "", { "dependencies": { "@cspotcode/source-map-support": "^0.8.0", "@tsconfig/node10": "^1.0.7", "@tsconfig/node12": "^1.0.7", "@tsconfig/node14": "^1.0.0", "@tsconfig/node16": "^1.0.2", "acorn": "^8.4.1", "acorn-walk": "^8.1.1", "arg": "^4.1.0", "create-require": "^1.1.0", "diff": "^4.0.1", "make-error": "^1.1.1", "v8-compile-cache-lib": "^3.0.1", "yn": "3.1.1" }, "peerDependencies": { "@swc/core": ">=1.2.50", "@swc/wasm": ">=1.2.50", "@types/node": "*", "typescript": ">=2.7" }, "optionalPeers": ["@swc/core", "@swc/wasm"], "bin": { "ts-node": "dist/bin.js", "ts-script": "dist/bin-script-deprecated.js", "ts-node-cwd": "dist/bin-cwd.js", "ts-node-esm": "dist/bin-esm.js", "ts-node-script": "dist/bin-script.js", "ts-node-transpile-only": "dist/bin-transpile.js" } }, "sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ=="],
600
618
 
619
+ "ts-node-dev": ["ts-node-dev@2.0.0", "", { "dependencies": { "chokidar": "^3.5.1", "dynamic-dedupe": "^0.3.0", "minimist": "^1.2.6", "mkdirp": "^1.0.4", "resolve": "^1.0.0", "rimraf": "^2.6.1", "source-map-support": "^0.5.12", "tree-kill": "^1.2.2", "ts-node": "^10.4.0", "tsconfig": "^7.0.0" }, "peerDependencies": { "node-notifier": "*", "typescript": "*" }, "optionalPeers": ["node-notifier"], "bin": { "ts-node-dev": "lib/bin.js", "tsnd": "lib/bin.js" } }, "sha512-ywMrhCfH6M75yftYvrvNarLEY+SUXtUvU8/0Z6llrHQVBx12GiFk5sStF8UdfE/yfzk9IAq7O5EEbTQsxlBI8w=="],
620
+
621
+ "tsconfig": ["tsconfig@7.0.0", "", { "dependencies": { "@types/strip-bom": "^3.0.0", "@types/strip-json-comments": "0.0.30", "strip-bom": "^3.0.0", "strip-json-comments": "^2.0.0" } }, "sha512-vZXmzPrL+EmC4T/4rVlT2jNVMWCi/O4DIiSj3UHg1OE5kCKbk4mfrXc6dZksLgRM/TZlKnousKH9bbTazUWRRw=="],
622
+
601
623
  "tsconfig-paths": ["tsconfig-paths@4.2.0", "", { "dependencies": { "json5": "^2.2.2", "minimist": "^1.2.6", "strip-bom": "^3.0.0" } }, "sha512-NoZ4roiN7LnbKn9QqE1amc9DJfzvZXxF4xDavcOWt1BPkdx+m+0gJuPM+S0vCe7zTJMYUP0R8pO2XMr+Y8oLIg=="],
602
624
 
603
625
  "type-detect": ["type-detect@4.0.8", "", {}, "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g=="],
@@ -624,6 +646,8 @@
624
646
 
625
647
  "write-file-atomic": ["write-file-atomic@4.0.2", "", { "dependencies": { "imurmurhash": "^0.1.4", "signal-exit": "^3.0.7" } }, "sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg=="],
626
648
 
649
+ "xtend": ["xtend@4.0.2", "", {}, "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ=="],
650
+
627
651
  "y18n": ["y18n@5.0.8", "", {}, "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA=="],
628
652
 
629
653
  "yallist": ["yallist@3.1.1", "", {}, "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g=="],
@@ -652,6 +676,8 @@
652
676
 
653
677
  "gradient-string/chalk": ["chalk@5.4.1", "", {}, "sha512-zgVZuo2WcZgfUEmsn6eO3kINexW8RAE4maiQ8QNs8CtpPCSyMiYsULR3HQYkm3w8FIA3SberyMJMSldGsW+U3w=="],
654
678
 
679
+ "jest-config/strip-json-comments": ["strip-json-comments@3.1.1", "", {}, "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig=="],
680
+
655
681
  "jest-runtime/strip-bom": ["strip-bom@4.0.0", "", {}, "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w=="],
656
682
 
657
683
  "jest-worker/supports-color": ["supports-color@8.1.1", "", { "dependencies": { "has-flag": "^4.0.0" } }, "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q=="],
package/dist/src/cli.js CHANGED
@@ -26,10 +26,12 @@ function cli() {
26
26
  .command('dev <entry>')
27
27
  .description('Run Express.js project in development mode with TypeScript support')
28
28
  .option('-p, --port <number>', 'Port to run the server on', '3000')
29
- .option('-w, --watch <path>', 'Path to watch for changes', 'src')
29
+ .option('-w, --watch <paths...>', 'Paths to watch for changes', ['src'])
30
+ .option('-i, --ignore <paths...>', 'Paths to ignore', ['node_modules', 'dist', '.git'])
31
+ .option('-e, --ext <extensions...>', 'File extensions to watch', ['ts', 'js', 'json'])
32
+ .option('-d, --delay <number>', 'Delay before restarting in milliseconds', '1000')
30
33
  .option('-c, --no-color', 'Disable colored output')
31
- .option('-t, --transpile-only', 'Use transpileOnly mode for faster compilation', false)
32
- .option('-i, --ignore <patterns>', 'Ignore patterns for file watching', 'node_modules,.git')
34
+ .option('--no-clear', 'Disable screen clearing on restart')
33
35
  .action(async (entry, options) => {
34
36
  try {
35
37
  const entryPath = (0, path_1.resolve)(process.cwd(), entry);
@@ -37,31 +39,87 @@ function cli() {
37
39
  throw new Error(`Entry file ${entry} not found`);
38
40
  }
39
41
  console.log(chalk_1.default.blue(`${figures_1.default.info} Starting development server...`));
40
- const tsNodeDevArgs = [
41
- '--respawn',
42
- '--transpile-only',
43
- '--ignore-watch', options.ignore,
44
- '--watch', options.watch,
45
- '-r', 'tsconfig-paths/register',
46
- entryPath
47
- ];
48
- if (options.transpileOnly) {
49
- tsNodeDevArgs.push('--transpile-only');
50
- }
51
- const server = (0, child_process_1.spawn)('ts-node-dev', tsNodeDevArgs, {
52
- stdio: 'inherit',
53
- env: {
54
- ...process.env,
55
- PORT: options.port,
56
- NODE_ENV: 'development'
42
+ let server = null;
43
+ let isRestarting = false;
44
+ let restartTimer = null;
45
+ const startServer = () => {
46
+ if (server) {
47
+ server.kill();
48
+ }
49
+ server = (0, child_process_1.spawn)('ts-node', [
50
+ '-r', 'tsconfig-paths/register',
51
+ entryPath
52
+ ], {
53
+ stdio: 'inherit',
54
+ env: {
55
+ ...process.env,
56
+ PORT: options.port,
57
+ NODE_ENV: 'development'
58
+ }
59
+ });
60
+ server.on('error', (err) => {
61
+ console.error(chalk_1.default.red(`${figures_1.default.cross} Server error: ${err.message}`));
62
+ });
63
+ server.on('exit', (code) => {
64
+ if (code !== 0 && !isRestarting) {
65
+ console.error(chalk_1.default.red(`${figures_1.default.cross} Server crashed with code ${code}`));
66
+ }
67
+ });
68
+ };
69
+ // Initial server start
70
+ startServer();
71
+ // Setup file watching with chokidar
72
+ const watcher = (0, chokidar_1.watch)(options.watch, {
73
+ ignored: [
74
+ ...options.ignore,
75
+ /(^|[\/\\])\../,
76
+ '**/*.map' // Ignore source maps
77
+ ],
78
+ persistent: true,
79
+ ignoreInitial: true,
80
+ awaitWriteFinish: {
81
+ stabilityThreshold: 300,
82
+ pollInterval: 100
83
+ }
84
+ });
85
+ // Handle file changes
86
+ watcher.on('change', (path) => {
87
+ var _a;
88
+ const ext = (_a = path.split('.').pop()) === null || _a === void 0 ? void 0 : _a.toLowerCase();
89
+ if (!ext || !options.ext.includes(ext)) {
90
+ return;
91
+ }
92
+ if (restartTimer) {
93
+ clearTimeout(restartTimer);
57
94
  }
95
+ isRestarting = true;
96
+ restartTimer = setTimeout(() => {
97
+ if (options.clear) {
98
+ process.stdout.write('\x1Bc'); // Clear screen
99
+ }
100
+ console.log(chalk_1.default.yellow(`${figures_1.default.info} File ${path} changed. Restarting...`));
101
+ startServer();
102
+ isRestarting = false;
103
+ }, parseInt(options.delay));
58
104
  });
105
+ // Handle cleanup
59
106
  cleanupRunner = () => {
60
- server.kill();
107
+ if (server) {
108
+ server.kill();
109
+ }
110
+ if (restartTimer) {
111
+ clearTimeout(restartTimer);
112
+ }
113
+ watcher.close();
61
114
  };
62
- server.on('error', (err) => {
63
- console.error(chalk_1.default.red(`${figures_1.default.cross} Server error: ${err.message}`));
64
- process.exit(1);
115
+ // Handle process signals
116
+ process.on('SIGINT', () => {
117
+ cleanupRunner === null || cleanupRunner === void 0 ? void 0 : cleanupRunner();
118
+ process.exit(0);
119
+ });
120
+ process.on('SIGTERM', () => {
121
+ cleanupRunner === null || cleanupRunner === void 0 ? void 0 : cleanupRunner();
122
+ process.exit(0);
65
123
  });
66
124
  }
67
125
  catch (error) {
@@ -109,47 +167,56 @@ function cli() {
109
167
  });
110
168
  // Start command for production
111
169
  program
112
- .command('start <entry>')
113
- .description('Start Express.js project in production mode')
170
+ .command('start')
171
+ .description('Start the built application in production mode')
114
172
  .option('-p, --port <number>', 'Port to run the server on', '3000')
115
- .option('-e, --env <env>', 'Environment to run in', 'production')
116
- .option('-m, --max-memory <size>', 'Maximum memory size (e.g., 512M, 1G)', '512M')
117
- .option('-c, --cluster <number>', 'Number of cluster workers', '1')
118
- .action(async (entry, options) => {
173
+ .option('-o, --outDir <dir>', 'Output directory', 'dist')
174
+ .option('-e, --entry <file>', 'Entry file name', 'index.js')
175
+ .action(async (options) => {
119
176
  try {
120
- const entryPath = (0, path_1.resolve)(process.cwd(), entry);
177
+ const outDir = options.outDir;
178
+ const entryFile = options.entry;
179
+ const entryPath = (0, path_1.resolve)(process.cwd(), outDir, entryFile);
121
180
  if (!(0, fs_1.existsSync)(entryPath)) {
122
- throw new Error(`Entry file ${entry} not found`);
181
+ console.log(chalk_1.default.yellow(`${figures_1.default.warning} Build not found. Building project first...`));
182
+ // Run build command first
183
+ const build = (0, child_process_1.spawn)('tsc', [
184
+ '--outDir', outDir
185
+ ], {
186
+ stdio: 'inherit'
187
+ });
188
+ build.on('close', (code) => {
189
+ if (code === 0) {
190
+ console.log(chalk_1.default.green(`${figures_1.default.tick} Build completed successfully`));
191
+ startServer();
192
+ }
193
+ else {
194
+ console.error(chalk_1.default.red(`${figures_1.default.cross} Build failed with code ${code}`));
195
+ process.exit(code !== null && code !== void 0 ? code : 1);
196
+ }
197
+ });
123
198
  }
124
- console.log(chalk_1.default.blue(`${figures_1.default.info} Starting production server...`));
125
- // Check if the entry file is TypeScript
126
- const isTypeScript = entryPath.endsWith('.ts');
127
- const executable = isTypeScript ? 'ts-node' : 'node';
128
- const args = isTypeScript
129
- ? ['-r', 'tsconfig-paths/register', entryPath]
130
- : [entryPath];
131
- // Add cluster support if specified
132
- if (parseInt(options.cluster) > 1) {
133
- args.unshift('--max-old-space-size=' + options.maxMemory);
134
- args.unshift('--max-memory=' + options.maxMemory);
135
- args.unshift('--cluster=' + options.cluster);
199
+ else {
200
+ startServer();
201
+ }
202
+ function startServer() {
203
+ console.log(chalk_1.default.blue(`${figures_1.default.info} Starting production server...`));
204
+ const server = (0, child_process_1.spawn)('node', [entryPath], {
205
+ stdio: 'inherit',
206
+ env: {
207
+ ...process.env,
208
+ PORT: options.port,
209
+ NODE_ENV: 'production'
210
+ }
211
+ });
212
+ cleanupRunner = () => {
213
+ server.kill();
214
+ };
215
+ server.on('error', (err) => {
216
+ console.error(chalk_1.default.red(`${figures_1.default.cross} Server error: ${err.message}`));
217
+ process.exit(1);
218
+ });
136
219
  }
137
- const server = (0, child_process_1.spawn)(executable, args, {
138
- stdio: 'inherit',
139
- env: {
140
- ...process.env,
141
- PORT: options.port,
142
- NODE_ENV: options.env,
143
- MAX_MEMORY: options.maxMemory
144
- }
145
- });
146
- cleanupRunner = () => {
147
- server.kill();
148
- };
149
- server.on('error', (err) => {
150
- console.error(chalk_1.default.red(`${figures_1.default.cross} Server error: ${err.message}`));
151
- process.exit(1);
152
- });
153
220
  }
154
221
  catch (error) {
155
222
  if (error instanceof Error) {
@@ -234,24 +301,26 @@ function cli() {
234
301
  });
235
302
  // Process Management Commands
236
303
  program
237
- .command('startx <path>')
304
+ .command('startx <command>')
238
305
  .description('Start a process with monitoring and auto-restart')
239
306
  .option('-n, --name <name>', 'Process name')
240
307
  .option('-w, --watch', 'Watch for file changes and auto-restart')
241
308
  .option('-r, --max-restarts <number>', 'Maximum number of restart attempts', '5')
242
309
  .option('-d, --restart-delay <number>', 'Delay between restarts in milliseconds', '1000')
243
- .action(async (path, options) => {
310
+ .option('-c, --cwd <path>', 'Working directory for the process')
311
+ .action(async (command, options) => {
244
312
  try {
245
- const process = await process_manager_js_1.processManager.startx(path, {
313
+ const process = await process_manager_js_1.processManager.startx(command, {
246
314
  name: options.name,
247
315
  watch: options.watch,
248
316
  maxRestarts: parseInt(options.maxRestarts),
249
- restartDelay: parseInt(options.restartDelay)
317
+ restartDelay: parseInt(options.restartDelay),
318
+ cwd: options.cwd
250
319
  });
251
320
  console.log(chalk_1.default.green(`${figures_1.default.tick} Process started successfully`));
252
- console.log(chalk_1.default.blue(`ID: ${process.id}`));
253
321
  console.log(chalk_1.default.blue(`Name: ${process.name}`));
254
322
  console.log(chalk_1.default.blue(`PID: ${process.pid}`));
323
+ console.log(chalk_1.default.blue(`Command: ${process.command}`));
255
324
  console.log(chalk_1.default.blue(`Max Restarts: ${process.maxRestarts}`));
256
325
  console.log(chalk_1.default.blue(`Restart Delay: ${process.restartDelay}ms`));
257
326
  }
@@ -266,12 +335,12 @@ function cli() {
266
335
  }
267
336
  });
268
337
  program
269
- .command('stopx <id>')
338
+ .command('stopx <name>')
270
339
  .description('Stop a running process')
271
340
  .option('-f, --force', 'Force stop the process')
272
- .action(async (id, options) => {
341
+ .action(async (name, options) => {
273
342
  try {
274
- await process_manager_js_1.processManager.stopx(id);
343
+ await process_manager_js_1.processManager.stopx(name);
275
344
  console.log(chalk_1.default.green(`${figures_1.default.tick} Process stopped successfully`));
276
345
  }
277
346
  catch (error) {
@@ -290,81 +359,42 @@ function cli() {
290
359
  .option('-a, --all', 'Show all processes including stopped ones')
291
360
  .option('-j, --json', 'Output in JSON format')
292
361
  .action((options) => {
293
- const processes = process_manager_js_1.processManager.list();
294
- const filteredProcesses = options.all ? processes : processes.filter(p => p.status === 'running');
295
- if (filteredProcesses.length === 0) {
296
- console.log(chalk_1.default.yellow(`${figures_1.default.info} No processes running`));
297
- return;
298
- }
299
- if (options.json) {
300
- console.log(JSON.stringify(filteredProcesses, null, 2));
301
- return;
362
+ try {
363
+ if (options.json) {
364
+ const processes = Array.from(process_manager_js_1.processManager.list());
365
+ console.log(JSON.stringify(processes, null, 2));
366
+ return;
367
+ }
368
+ console.log(process_manager_js_1.processManager.list());
302
369
  }
303
- console.log(chalk_1.default.blue(`${figures_1.default.info} Running Processes:`));
304
- filteredProcesses.forEach(process => {
305
- const statusColor = process.status === 'running' ? 'green' :
306
- process.status === 'error' ? 'red' :
307
- process.status === 'restarting' ? 'yellow' : 'gray';
308
- console.log(chalk_1.default.blue(`\nID: ${process.id}`));
309
- console.log(`Name: ${process.name}`);
310
- console.log(`Status: ${chalk_1.default[statusColor](process.status)}`);
311
- console.log(`PID: ${process.pid}`);
312
- console.log(`Uptime: ${Math.floor(process.uptime)}s`);
313
- console.log(`Memory: ${process.memory.toFixed(2)}MB`);
314
- console.log(`Restarts: ${process.restarts}/${process.maxRestarts}`);
315
- if (process.lastError) {
316
- console.log(`Last Error: ${chalk_1.default.red(process.lastError)}`);
370
+ catch (error) {
371
+ if (error instanceof Error) {
372
+ console.error(chalk_1.default.red(`${figures_1.default.cross} Error: ${error.message}`));
373
+ }
374
+ else {
375
+ console.error(chalk_1.default.red(`${figures_1.default.cross} An unknown error occurred`));
317
376
  }
318
- });
377
+ process.exit(1);
378
+ }
319
379
  });
320
380
  program
321
- .command('monit <id>')
322
- .description('Monitor a specific process')
381
+ .command('monit <name>')
382
+ .description('Monitor a process in real-time')
323
383
  .option('-i, --interval <number>', 'Update interval in milliseconds', '1000')
324
- .action((id, options) => {
384
+ .action((name, options) => {
325
385
  try {
326
- const processInfo = process_manager_js_1.processManager.monit(id);
327
- console.log(chalk_1.default.blue(`${figures_1.default.info} Process Monitor:`));
328
- console.log(chalk_1.default.blue(`\nID: ${processInfo.id}`));
329
- console.log(`Name: ${processInfo.name}`);
330
- console.log(`Status: ${processInfo.status}`);
331
- console.log(`PID: ${processInfo.pid}`);
332
- console.log(`Uptime: ${Math.floor(processInfo.uptime)}s`);
333
- console.log(`Memory: ${processInfo.memory.toFixed(2)}MB`);
334
- console.log(`Restarts: ${processInfo.restarts}/${processInfo.maxRestarts}`);
335
- if (processInfo.lastError) {
336
- console.log(`Last Error: ${chalk_1.default.red(processInfo.lastError)}`);
386
+ const interval = parseInt(options.interval);
387
+ if (isNaN(interval) || interval < 100) {
388
+ throw new Error('Interval must be a number greater than 100ms');
337
389
  }
338
- console.log(chalk_1.default.blue(`\nRecent Logs:`));
339
- processInfo.logs.forEach(log => {
340
- if (log.includes('error') || log.includes('Error')) {
341
- console.log(chalk_1.default.red(log));
342
- }
343
- else if (log.includes('warn') || log.includes('Warn')) {
344
- console.log(chalk_1.default.yellow(log));
345
- }
346
- else {
347
- console.log(log);
348
- }
349
- });
350
390
  // Start real-time monitoring
351
- const interval = setInterval(() => {
391
+ const updateDisplay = () => {
352
392
  try {
353
- const updatedProcess = process_manager_js_1.processManager.monit(id);
393
+ const { table, logs } = process_manager_js_1.processManager.monit(name);
354
394
  process.stdout.write('\x1Bc'); // Clear screen
355
- console.log(chalk_1.default.blue(`${figures_1.default.info} Process Monitor (Live):`));
356
- console.log(chalk_1.default.blue(`\nID: ${updatedProcess.id}`));
357
- console.log(`Name: ${updatedProcess.name}`);
358
- console.log(`Status: ${updatedProcess.status}`);
359
- console.log(`PID: ${updatedProcess.pid}`);
360
- console.log(`Uptime: ${Math.floor(updatedProcess.uptime)}s`);
361
- console.log(`Memory: ${updatedProcess.memory.toFixed(2)}MB`);
362
- console.log(`Restarts: ${updatedProcess.restarts}/${updatedProcess.maxRestarts}`);
363
- if (updatedProcess.lastError) {
364
- console.log(`Last Error: ${chalk_1.default.red(updatedProcess.lastError)}`);
365
- }
366
- console.log(chalk_1.default.blue(`\nRecent Logs:`));
367
- updatedProcess.logs.forEach(log => {
395
+ console.log(table);
396
+ console.log(chalk_1.default.blue('\nRecent Logs:'));
397
+ logs.forEach(log => {
368
398
  if (log.includes('error') || log.includes('Error')) {
369
399
  console.log(chalk_1.default.red(log));
370
400
  }
@@ -377,14 +407,15 @@ function cli() {
377
407
  });
378
408
  }
379
409
  catch (error) {
380
- clearInterval(interval);
410
+ clearInterval(monitorInterval);
381
411
  console.error(chalk_1.default.red(`${figures_1.default.cross} Error monitoring process: ${error}`));
382
412
  process.exit(1);
383
413
  }
384
- }, parseInt(options.interval));
385
- // Handle cleanup
414
+ };
415
+ const monitorInterval = setInterval(updateDisplay, interval);
416
+ updateDisplay(); // Initial display
386
417
  process.on('SIGINT', () => {
387
- clearInterval(interval);
418
+ clearInterval(monitorInterval);
388
419
  process.exit(0);
389
420
  });
390
421
  }
@@ -399,31 +430,29 @@ function cli() {
399
430
  }
400
431
  });
401
432
  program
402
- .command('log <id>')
433
+ .command('log <name>')
403
434
  .description('View process logs')
404
- .option('-l, --lines <number>', 'Number of lines to show', '100')
405
435
  .option('-f, --follow', 'Follow log output')
406
- .option('-e, --error', 'Show only error logs')
407
- .option('-w, --warn', 'Show only warning logs')
408
- .action((id, options) => {
436
+ .option('-e, --errors', 'Show only errors')
437
+ .option('-w, --warnings', 'Show only warnings')
438
+ .option('-l, --lines <number>', 'Number of lines to show', '100')
439
+ .action((name, options) => {
409
440
  try {
410
- const logs = process_manager_js_1.processManager.log(id, parseInt(options.lines));
411
- if (options.error) {
412
- const errorLogs = logs.filter(log => log.toLowerCase().includes('error') ||
441
+ const lines = parseInt(options.lines);
442
+ if (isNaN(lines) || lines < 1) {
443
+ throw new Error('Lines must be a positive number');
444
+ }
445
+ const logs = process_manager_js_1.processManager.log(name, lines);
446
+ let filteredLogs = logs;
447
+ if (options.errors) {
448
+ filteredLogs = logs.filter(log => log.toLowerCase().includes('error') ||
413
449
  log.toLowerCase().includes('exception'));
414
- console.log(chalk_1.default.blue(`${figures_1.default.info} Error Logs:`));
415
- errorLogs.forEach(log => console.log(chalk_1.default.red(log)));
416
- return;
417
450
  }
418
- if (options.warn) {
419
- const warnLogs = logs.filter(log => log.toLowerCase().includes('warn') ||
451
+ else if (options.warnings) {
452
+ filteredLogs = logs.filter(log => log.toLowerCase().includes('warn') ||
420
453
  log.toLowerCase().includes('warning'));
421
- console.log(chalk_1.default.blue(`${figures_1.default.info} Warning Logs:`));
422
- warnLogs.forEach(log => console.log(chalk_1.default.yellow(log)));
423
- return;
424
454
  }
425
- console.log(chalk_1.default.blue(`${figures_1.default.info} Process Logs:`));
426
- logs.forEach(log => {
455
+ filteredLogs.forEach(log => {
427
456
  if (log.includes('error') || log.includes('Error')) {
428
457
  console.log(chalk_1.default.red(log));
429
458
  }
@@ -435,11 +464,11 @@ function cli() {
435
464
  }
436
465
  });
437
466
  if (options.follow) {
438
- const watcher = (0, chokidar_1.watch)(process_manager_js_1.processManager.getLogPath(id), {
467
+ const watcher = (0, chokidar_1.watch)(process_manager_js_1.processManager.getLogPath(name), {
439
468
  persistent: true
440
469
  });
441
470
  watcher.on('change', () => {
442
- const newLogs = process_manager_js_1.processManager.log(id, 1);
471
+ const newLogs = process_manager_js_1.processManager.log(name, 1);
443
472
  if (newLogs.length > 0) {
444
473
  const log = newLogs[0];
445
474
  if (log.includes('error') || log.includes('Error')) {
@@ -1,18 +1,24 @@
1
1
  "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
2
5
  Object.defineProperty(exports, "__esModule", { value: true });
3
6
  exports.processManager = void 0;
4
7
  const child_process_1 = require("child_process");
5
8
  const chokidar_1 = require("chokidar");
6
9
  const fs_1 = require("fs");
7
10
  const path_1 = require("path");
11
+ const chalk_1 = __importDefault(require("chalk"));
8
12
  const events_1 = require("events");
13
+ const cli_table3_1 = __importDefault(require("cli-table3"));
14
+ const child_process_2 = require("child_process");
9
15
  class ProcessManager extends events_1.EventEmitter {
10
16
  constructor() {
11
17
  super();
12
18
  this.processes = new Map();
13
19
  this.watchers = new Map();
14
20
  this.defaultMaxRestarts = 5;
15
- this.defaultRestartDelay = 1000; // 1 second
21
+ this.defaultRestartDelay = 1000;
16
22
  this.logDir = (0, path_1.resolve)(process.cwd(), '.neex-logs');
17
23
  this.configFile = (0, path_1.resolve)(process.cwd(), '.neex-config.json');
18
24
  this.initialize();
@@ -33,27 +39,26 @@ class ProcessManager extends events_1.EventEmitter {
33
39
  const config = Object.fromEntries(this.processes);
34
40
  (0, fs_1.writeFileSync)(this.configFile, JSON.stringify(config, null, 2));
35
41
  }
36
- generateId() {
37
- return Math.random().toString(36).substring(2, 15);
42
+ generateName(command) {
43
+ const baseName = command.split(' ')[0].replace(/[^a-zA-Z0-9]/g, '');
44
+ const timestamp = Date.now().toString(36);
45
+ return `${baseName}-${timestamp}`;
38
46
  }
39
- getLogPath(id) {
40
- return (0, path_1.join)(this.logDir, `${id}.log`);
47
+ getLogPath(name) {
48
+ return (0, path_1.join)(this.logDir, `${name}.log`);
41
49
  }
42
- async startx(path, options = {}) {
43
- const id = this.generateId();
44
- const name = options.name || `process-${id}`;
45
- const fullPath = (0, path_1.resolve)(process.cwd(), path);
46
- if (!(0, fs_1.existsSync)(fullPath)) {
47
- throw new Error(`Path ${path} does not exist`);
50
+ async startx(command, options = {}) {
51
+ const name = options.name || this.generateName(command);
52
+ const cwd = options.cwd || process.cwd();
53
+ if (this.processes.has(name)) {
54
+ throw new Error(`Process with name ${name} already exists`);
48
55
  }
49
56
  const processInfo = {
50
- id,
51
57
  name,
52
58
  pid: 0,
53
59
  status: 'stopped',
54
60
  startTime: Date.now(),
55
- path: fullPath,
56
- command: `node ${fullPath}`,
61
+ command,
57
62
  logs: [],
58
63
  memory: 0,
59
64
  cpu: 0,
@@ -61,7 +66,8 @@ class ProcessManager extends events_1.EventEmitter {
61
66
  restarts: 0,
62
67
  maxRestarts: options.maxRestarts || this.defaultMaxRestarts,
63
68
  restartDelay: options.restartDelay || this.defaultRestartDelay,
64
- watch: options.watch
69
+ watch: options.watch,
70
+ cwd
65
71
  };
66
72
  try {
67
73
  await this.startProcess(processInfo);
@@ -70,56 +76,60 @@ class ProcessManager extends events_1.EventEmitter {
70
76
  catch (error) {
71
77
  processInfo.status = 'error';
72
78
  processInfo.lastError = error.message;
73
- this.processes.set(id, processInfo);
79
+ this.processes.set(name, processInfo);
74
80
  this.saveConfig();
75
81
  throw error;
76
82
  }
77
83
  }
78
84
  async startProcess(processInfo) {
79
85
  var _a, _b;
80
- const child = (0, child_process_1.spawn)('node', [processInfo.path], {
86
+ const [cmd, ...args] = processInfo.command.split(' ');
87
+ const child = (0, child_process_1.spawn)(cmd, args, {
81
88
  stdio: ['ignore', 'pipe', 'pipe'],
82
- env: { ...process.env, NODE_ENV: 'production' }
89
+ env: { ...process.env, NODE_ENV: 'production' },
90
+ cwd: processInfo.cwd,
91
+ shell: true
83
92
  });
84
93
  processInfo.pid = child.pid || 0;
85
94
  processInfo.status = 'running';
86
95
  processInfo.startTime = Date.now();
87
96
  // Setup logging
88
- const logStream = (0, fs_1.writeFileSync)(this.getLogPath(processInfo.id), '', { flag: 'a' });
97
+ (0, fs_1.writeFileSync)(this.getLogPath(processInfo.name), '', { flag: 'a' });
89
98
  (_a = child.stdout) === null || _a === void 0 ? void 0 : _a.on('data', (data) => {
90
99
  const log = data.toString();
91
100
  processInfo.logs.push(log);
92
- (0, fs_1.writeFileSync)(this.getLogPath(processInfo.id), log, { flag: 'a' });
93
- this.emit('log', { id: processInfo.id, log });
101
+ (0, fs_1.writeFileSync)(this.getLogPath(processInfo.name), log, { flag: 'a' });
102
+ this.emit('log', { name: processInfo.name, log });
94
103
  });
95
104
  (_b = child.stderr) === null || _b === void 0 ? void 0 : _b.on('data', (data) => {
96
105
  const log = data.toString();
97
106
  processInfo.logs.push(log);
98
- (0, fs_1.writeFileSync)(this.getLogPath(processInfo.id), log, { flag: 'a' });
99
- this.emit('error', { id: processInfo.id, log });
107
+ (0, fs_1.writeFileSync)(this.getLogPath(processInfo.name), log, { flag: 'a' });
108
+ this.emit('error', { name: processInfo.name, log });
100
109
  });
101
110
  // Setup monitoring
102
- if (processInfo.watch) {
103
- const watcher = (0, chokidar_1.watch)(processInfo.path, {
111
+ if (processInfo.watch && processInfo.cwd) {
112
+ const watcher = (0, chokidar_1.watch)(processInfo.cwd, {
104
113
  ignored: /(^|[\/\\])\../,
105
114
  persistent: true
106
115
  });
107
116
  watcher.on('change', () => {
108
- this.restart(processInfo.id);
117
+ this.restart(processInfo.name);
109
118
  });
110
- this.watchers.set(processInfo.id, watcher);
119
+ this.watchers.set(processInfo.name, watcher);
111
120
  }
112
121
  // Monitor process
113
122
  const monitorInterval = setInterval(() => {
114
123
  if (child.pid) {
115
124
  try {
116
- const stats = process.memoryUsage();
117
- processInfo.memory = stats.heapUsed / 1024 / 1024; // MB
125
+ const stats = this.getProcessStats(child.pid);
126
+ processInfo.memory = stats.memory;
127
+ processInfo.cpu = stats.cpu;
118
128
  processInfo.uptime = (Date.now() - processInfo.startTime) / 1000;
119
- this.emit('stats', { id: processInfo.id, stats: processInfo });
129
+ this.emit('stats', { name: processInfo.name, stats: processInfo });
120
130
  }
121
131
  catch (error) {
122
- console.error(`Error monitoring process ${processInfo.id}:`, error);
132
+ console.error(`Error monitoring process ${processInfo.name}:`, error);
123
133
  }
124
134
  }
125
135
  }, 1000);
@@ -128,17 +138,16 @@ class ProcessManager extends events_1.EventEmitter {
128
138
  if (code !== 0) {
129
139
  processInfo.status = 'error';
130
140
  processInfo.lastError = `Process exited with code ${code}`;
131
- this.emit('error', { id: processInfo.id, code });
132
- // Auto-restart logic
141
+ this.emit('error', { name: processInfo.name, code });
133
142
  if (processInfo.restarts < processInfo.maxRestarts) {
134
143
  processInfo.status = 'restarting';
135
- this.emit('restart', { id: processInfo.id, attempt: processInfo.restarts + 1 });
144
+ this.emit('restart', { name: processInfo.name, attempt: processInfo.restarts + 1 });
136
145
  await new Promise(resolve => setTimeout(resolve, processInfo.restartDelay));
137
146
  processInfo.restarts++;
138
147
  await this.startProcess(processInfo);
139
148
  }
140
149
  else {
141
- this.emit('max-restarts', { id: processInfo.id, maxRestarts: processInfo.maxRestarts });
150
+ this.emit('max-restarts', { name: processInfo.name, maxRestarts: processInfo.maxRestarts });
142
151
  }
143
152
  }
144
153
  else {
@@ -146,63 +155,104 @@ class ProcessManager extends events_1.EventEmitter {
146
155
  }
147
156
  this.saveConfig();
148
157
  });
149
- this.processes.set(processInfo.id, processInfo);
158
+ this.processes.set(processInfo.name, processInfo);
150
159
  this.saveConfig();
151
- this.emit('start', { id: processInfo.id, processInfo });
160
+ this.emit('start', { name: processInfo.name, processInfo });
152
161
  }
153
- async stopx(id) {
154
- const processInfo = this.processes.get(id);
162
+ getProcessStats(pid) {
163
+ try {
164
+ const stats = (0, child_process_2.execSync)(`ps -p ${pid} -o %mem,%cpu`).toString().split('\n')[1].trim().split(/\s+/);
165
+ return {
166
+ memory: parseFloat(stats[0]),
167
+ cpu: parseFloat(stats[1])
168
+ };
169
+ }
170
+ catch (_a) {
171
+ return { memory: 0, cpu: 0 };
172
+ }
173
+ }
174
+ async stopx(name) {
175
+ const processInfo = this.processes.get(name);
155
176
  if (!processInfo) {
156
- throw new Error(`Process ${id} not found`);
177
+ throw new Error(`Process ${name} not found`);
157
178
  }
158
179
  try {
159
180
  process.kill(processInfo.pid);
160
- const watcher = this.watchers.get(id);
181
+ const watcher = this.watchers.get(name);
161
182
  if (watcher) {
162
183
  watcher.close();
163
- this.watchers.delete(id);
184
+ this.watchers.delete(name);
164
185
  }
165
- this.processes.delete(id);
186
+ this.processes.delete(name);
166
187
  this.saveConfig();
167
- this.emit('stop', { id });
188
+ this.emit('stop', { name });
168
189
  }
169
190
  catch (error) {
170
- throw new Error(`Failed to stop process ${id}: ${error.message}`);
191
+ throw new Error(`Failed to stop process ${name}: ${error.message}`);
171
192
  }
172
193
  }
173
194
  list() {
174
- return Array.from(this.processes.values());
195
+ const table = new cli_table3_1.default({
196
+ head: ['Name', 'Status', 'PID', 'Memory', 'CPU', 'Uptime', 'Restarts'],
197
+ style: { head: ['cyan'] }
198
+ });
199
+ Array.from(this.processes.values()).forEach(process => {
200
+ const statusColor = process.status === 'running' ? 'green' :
201
+ process.status === 'error' ? 'red' :
202
+ process.status === 'restarting' ? 'yellow' : 'gray';
203
+ table.push([
204
+ process.name,
205
+ chalk_1.default[statusColor](process.status),
206
+ process.pid || '-',
207
+ `${process.memory.toFixed(2)}MB`,
208
+ `${process.cpu.toFixed(1)}%`,
209
+ `${Math.floor(process.uptime)}s`,
210
+ `${process.restarts}/${process.maxRestarts}`
211
+ ]);
212
+ });
213
+ return table.toString();
175
214
  }
176
- monit(id) {
177
- const processInfo = this.processes.get(id);
215
+ monit(name) {
216
+ const processInfo = this.processes.get(name);
178
217
  if (!processInfo) {
179
- throw new Error(`Process ${id} not found`);
218
+ throw new Error(`Process ${name} not found`);
219
+ }
220
+ const table = new cli_table3_1.default({
221
+ style: { head: ['cyan'] }
222
+ });
223
+ table.push(['Name', processInfo.name], ['Status', chalk_1.default[processInfo.status === 'running' ? 'green' : 'red'](processInfo.status)], ['PID', processInfo.pid.toString()], ['Memory', `${processInfo.memory.toFixed(2)}MB`], ['CPU', `${processInfo.cpu.toFixed(1)}%`], ['Uptime', `${Math.floor(processInfo.uptime)}s`], ['Restarts', `${processInfo.restarts}/${processInfo.maxRestarts}`]);
224
+ if (processInfo.lastError) {
225
+ table.push(['Last Error', chalk_1.default.red(processInfo.lastError)]);
180
226
  }
181
227
  return {
182
- ...processInfo,
183
- logs: processInfo.logs.slice(-100) // Last 100 logs
228
+ table: table.toString(),
229
+ logs: processInfo.logs.slice(-100)
184
230
  };
185
231
  }
186
- log(id, lines = 100) {
187
- const processInfo = this.processes.get(id);
232
+ log(name, lines = 100) {
233
+ const processInfo = this.processes.get(name);
188
234
  if (!processInfo) {
189
- throw new Error(`Process ${id} not found`);
235
+ throw new Error(`Process ${name} not found`);
190
236
  }
191
- const logPath = this.getLogPath(id);
237
+ const logPath = this.getLogPath(name);
192
238
  if (!(0, fs_1.existsSync)(logPath)) {
193
239
  return [];
194
240
  }
195
241
  const logs = (0, fs_1.readFileSync)(logPath, 'utf-8').split('\n');
196
242
  return logs.slice(-lines);
197
243
  }
198
- async restart(id) {
199
- const processInfo = this.processes.get(id);
244
+ async restart(name) {
245
+ const processInfo = this.processes.get(name);
200
246
  if (!processInfo) {
201
- throw new Error(`Process ${id} not found`);
247
+ throw new Error(`Process ${name} not found`);
202
248
  }
203
- await this.stopx(id);
249
+ await this.stopx(name);
204
250
  processInfo.restarts++;
205
- await this.startx(processInfo.path, { name: processInfo.name, watch: true });
251
+ await this.startx(processInfo.command, {
252
+ name: processInfo.name,
253
+ watch: true,
254
+ cwd: processInfo.cwd
255
+ });
206
256
  }
207
257
  }
208
258
  exports.processManager = new ProcessManager();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "neex",
3
- "version": "0.2.7",
3
+ "version": "0.2.8",
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",
@@ -30,10 +30,12 @@
30
30
  "dependencies": {
31
31
  "chalk": "^4.1.2",
32
32
  "chokidar": "^3.5.3",
33
+ "cli-table3": "^0.6.5",
33
34
  "commander": "^9.4.0",
34
35
  "figlet": "^1.8.1",
35
36
  "figures": "^3.2.0",
36
37
  "gradient-string": "^3.0.0",
38
+ "node-notifier": "^10.0.1",
37
39
  "npm-run-path": "^4.0.1",
38
40
  "p-map": "^4.0.0",
39
41
  "string-width": "^4.2.3",