neex 0.2.6 → 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 +11 -2
- package/bun.lock +27 -1
- package/dist/src/cli.js +177 -141
- package/dist/src/process-manager.js +110 -60
- package/package.json +4 -1
package/README.md
CHANGED
|
@@ -1,5 +1,12 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
<div align="center">
|
|
2
|
+
<a href="https://github.com/Neexjs">
|
|
3
|
+
<picture>
|
|
4
|
+
<source media="(prefers-color-scheme: dark)" srcset="https://neex.storage.c2.liara.space/Neex.png">
|
|
5
|
+
<img alt="Neex logo" src="https://neex.storage.c2.liara.space/Neex.png" height="150" style="border-radius: 12px;">
|
|
6
|
+
</picture>
|
|
7
|
+
</a>
|
|
8
|
+
|
|
9
|
+
# Neex v0.2.8
|
|
3
10
|
### 🚀 Neex: The Modern Build System for Polyrepo-in-Monorepo Architecture
|
|
4
11
|
|
|
5
12
|
[](https://www.npmjs.com/package/neex)
|
|
@@ -7,6 +14,8 @@
|
|
|
7
14
|
[](https://github.com/neexjs/blob/main/LICENSE)
|
|
8
15
|
[](https://github.com/Neexjs)
|
|
9
16
|
|
|
17
|
+
</div>
|
|
18
|
+
|
|
10
19
|
## 🎯 Overview
|
|
11
20
|
|
|
12
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@
|
|
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,8 +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 <
|
|
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')
|
|
34
|
+
.option('--no-clear', 'Disable screen clearing on restart')
|
|
31
35
|
.action(async (entry, options) => {
|
|
32
36
|
try {
|
|
33
37
|
const entryPath = (0, path_1.resolve)(process.cwd(), entry);
|
|
@@ -35,24 +39,13 @@ function cli() {
|
|
|
35
39
|
throw new Error(`Entry file ${entry} not found`);
|
|
36
40
|
}
|
|
37
41
|
console.log(chalk_1.default.blue(`${figures_1.default.info} Starting development server...`));
|
|
38
|
-
let server =
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
...process.env,
|
|
45
|
-
PORT: options.port
|
|
42
|
+
let server = null;
|
|
43
|
+
let isRestarting = false;
|
|
44
|
+
let restartTimer = null;
|
|
45
|
+
const startServer = () => {
|
|
46
|
+
if (server) {
|
|
47
|
+
server.kill();
|
|
46
48
|
}
|
|
47
|
-
});
|
|
48
|
-
// Setup file watching
|
|
49
|
-
const watcher = (0, chokidar_1.watch)(options.watch, {
|
|
50
|
-
ignored: /(^|[\/\\])\../,
|
|
51
|
-
persistent: true
|
|
52
|
-
});
|
|
53
|
-
watcher.on('change', (path) => {
|
|
54
|
-
console.log(chalk_1.default.yellow(`${figures_1.default.info} File ${path} changed. Restarting...`));
|
|
55
|
-
server.kill();
|
|
56
49
|
server = (0, child_process_1.spawn)('ts-node', [
|
|
57
50
|
'-r', 'tsconfig-paths/register',
|
|
58
51
|
entryPath
|
|
@@ -60,17 +53,73 @@ function cli() {
|
|
|
60
53
|
stdio: 'inherit',
|
|
61
54
|
env: {
|
|
62
55
|
...process.env,
|
|
63
|
-
PORT: options.port
|
|
56
|
+
PORT: options.port,
|
|
57
|
+
NODE_ENV: 'development'
|
|
64
58
|
}
|
|
65
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);
|
|
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));
|
|
66
104
|
});
|
|
105
|
+
// Handle cleanup
|
|
67
106
|
cleanupRunner = () => {
|
|
68
|
-
server
|
|
107
|
+
if (server) {
|
|
108
|
+
server.kill();
|
|
109
|
+
}
|
|
110
|
+
if (restartTimer) {
|
|
111
|
+
clearTimeout(restartTimer);
|
|
112
|
+
}
|
|
69
113
|
watcher.close();
|
|
70
114
|
};
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
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);
|
|
74
123
|
});
|
|
75
124
|
}
|
|
76
125
|
catch (error) {
|
|
@@ -118,31 +167,56 @@ function cli() {
|
|
|
118
167
|
});
|
|
119
168
|
// Start command for production
|
|
120
169
|
program
|
|
121
|
-
.command('start
|
|
122
|
-
.description('Start
|
|
170
|
+
.command('start')
|
|
171
|
+
.description('Start the built application in production mode')
|
|
123
172
|
.option('-p, --port <number>', 'Port to run the server on', '3000')
|
|
124
|
-
.
|
|
173
|
+
.option('-o, --outDir <dir>', 'Output directory', 'dist')
|
|
174
|
+
.option('-e, --entry <file>', 'Entry file name', 'index.js')
|
|
175
|
+
.action(async (options) => {
|
|
125
176
|
try {
|
|
126
|
-
const
|
|
177
|
+
const outDir = options.outDir;
|
|
178
|
+
const entryFile = options.entry;
|
|
179
|
+
const entryPath = (0, path_1.resolve)(process.cwd(), outDir, entryFile);
|
|
127
180
|
if (!(0, fs_1.existsSync)(entryPath)) {
|
|
128
|
-
|
|
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
|
+
});
|
|
198
|
+
}
|
|
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
|
+
});
|
|
129
219
|
}
|
|
130
|
-
console.log(chalk_1.default.blue(`${figures_1.default.info} Starting production server...`));
|
|
131
|
-
const server = (0, child_process_1.spawn)('node', [entryPath], {
|
|
132
|
-
stdio: 'inherit',
|
|
133
|
-
env: {
|
|
134
|
-
...process.env,
|
|
135
|
-
PORT: options.port,
|
|
136
|
-
NODE_ENV: 'production'
|
|
137
|
-
}
|
|
138
|
-
});
|
|
139
|
-
cleanupRunner = () => {
|
|
140
|
-
server.kill();
|
|
141
|
-
};
|
|
142
|
-
server.on('error', (err) => {
|
|
143
|
-
console.error(chalk_1.default.red(`${figures_1.default.cross} Server error: ${err.message}`));
|
|
144
|
-
process.exit(1);
|
|
145
|
-
});
|
|
146
220
|
}
|
|
147
221
|
catch (error) {
|
|
148
222
|
if (error instanceof Error) {
|
|
@@ -227,24 +301,26 @@ function cli() {
|
|
|
227
301
|
});
|
|
228
302
|
// Process Management Commands
|
|
229
303
|
program
|
|
230
|
-
.command('startx <
|
|
304
|
+
.command('startx <command>')
|
|
231
305
|
.description('Start a process with monitoring and auto-restart')
|
|
232
306
|
.option('-n, --name <name>', 'Process name')
|
|
233
307
|
.option('-w, --watch', 'Watch for file changes and auto-restart')
|
|
234
308
|
.option('-r, --max-restarts <number>', 'Maximum number of restart attempts', '5')
|
|
235
309
|
.option('-d, --restart-delay <number>', 'Delay between restarts in milliseconds', '1000')
|
|
236
|
-
.
|
|
310
|
+
.option('-c, --cwd <path>', 'Working directory for the process')
|
|
311
|
+
.action(async (command, options) => {
|
|
237
312
|
try {
|
|
238
|
-
const process = await process_manager_js_1.processManager.startx(
|
|
313
|
+
const process = await process_manager_js_1.processManager.startx(command, {
|
|
239
314
|
name: options.name,
|
|
240
315
|
watch: options.watch,
|
|
241
316
|
maxRestarts: parseInt(options.maxRestarts),
|
|
242
|
-
restartDelay: parseInt(options.restartDelay)
|
|
317
|
+
restartDelay: parseInt(options.restartDelay),
|
|
318
|
+
cwd: options.cwd
|
|
243
319
|
});
|
|
244
320
|
console.log(chalk_1.default.green(`${figures_1.default.tick} Process started successfully`));
|
|
245
|
-
console.log(chalk_1.default.blue(`ID: ${process.id}`));
|
|
246
321
|
console.log(chalk_1.default.blue(`Name: ${process.name}`));
|
|
247
322
|
console.log(chalk_1.default.blue(`PID: ${process.pid}`));
|
|
323
|
+
console.log(chalk_1.default.blue(`Command: ${process.command}`));
|
|
248
324
|
console.log(chalk_1.default.blue(`Max Restarts: ${process.maxRestarts}`));
|
|
249
325
|
console.log(chalk_1.default.blue(`Restart Delay: ${process.restartDelay}ms`));
|
|
250
326
|
}
|
|
@@ -259,12 +335,12 @@ function cli() {
|
|
|
259
335
|
}
|
|
260
336
|
});
|
|
261
337
|
program
|
|
262
|
-
.command('stopx <
|
|
338
|
+
.command('stopx <name>')
|
|
263
339
|
.description('Stop a running process')
|
|
264
340
|
.option('-f, --force', 'Force stop the process')
|
|
265
|
-
.action(async (
|
|
341
|
+
.action(async (name, options) => {
|
|
266
342
|
try {
|
|
267
|
-
await process_manager_js_1.processManager.stopx(
|
|
343
|
+
await process_manager_js_1.processManager.stopx(name);
|
|
268
344
|
console.log(chalk_1.default.green(`${figures_1.default.tick} Process stopped successfully`));
|
|
269
345
|
}
|
|
270
346
|
catch (error) {
|
|
@@ -283,81 +359,42 @@ function cli() {
|
|
|
283
359
|
.option('-a, --all', 'Show all processes including stopped ones')
|
|
284
360
|
.option('-j, --json', 'Output in JSON format')
|
|
285
361
|
.action((options) => {
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
console.log(JSON.stringify(filteredProcesses, null, 2));
|
|
294
|
-
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());
|
|
295
369
|
}
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
process.status === 'error' ? 'red' :
|
|
300
|
-
process.status === 'restarting' ? 'yellow' : 'gray';
|
|
301
|
-
console.log(chalk_1.default.blue(`\nID: ${process.id}`));
|
|
302
|
-
console.log(`Name: ${process.name}`);
|
|
303
|
-
console.log(`Status: ${chalk_1.default[statusColor](process.status)}`);
|
|
304
|
-
console.log(`PID: ${process.pid}`);
|
|
305
|
-
console.log(`Uptime: ${Math.floor(process.uptime)}s`);
|
|
306
|
-
console.log(`Memory: ${process.memory.toFixed(2)}MB`);
|
|
307
|
-
console.log(`Restarts: ${process.restarts}/${process.maxRestarts}`);
|
|
308
|
-
if (process.lastError) {
|
|
309
|
-
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}`));
|
|
310
373
|
}
|
|
311
|
-
|
|
374
|
+
else {
|
|
375
|
+
console.error(chalk_1.default.red(`${figures_1.default.cross} An unknown error occurred`));
|
|
376
|
+
}
|
|
377
|
+
process.exit(1);
|
|
378
|
+
}
|
|
312
379
|
});
|
|
313
380
|
program
|
|
314
|
-
.command('monit <
|
|
315
|
-
.description('Monitor a
|
|
381
|
+
.command('monit <name>')
|
|
382
|
+
.description('Monitor a process in real-time')
|
|
316
383
|
.option('-i, --interval <number>', 'Update interval in milliseconds', '1000')
|
|
317
|
-
.action((
|
|
384
|
+
.action((name, options) => {
|
|
318
385
|
try {
|
|
319
|
-
const
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
console.log(`Name: ${processInfo.name}`);
|
|
323
|
-
console.log(`Status: ${processInfo.status}`);
|
|
324
|
-
console.log(`PID: ${processInfo.pid}`);
|
|
325
|
-
console.log(`Uptime: ${Math.floor(processInfo.uptime)}s`);
|
|
326
|
-
console.log(`Memory: ${processInfo.memory.toFixed(2)}MB`);
|
|
327
|
-
console.log(`Restarts: ${processInfo.restarts}/${processInfo.maxRestarts}`);
|
|
328
|
-
if (processInfo.lastError) {
|
|
329
|
-
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');
|
|
330
389
|
}
|
|
331
|
-
console.log(chalk_1.default.blue(`\nRecent Logs:`));
|
|
332
|
-
processInfo.logs.forEach(log => {
|
|
333
|
-
if (log.includes('error') || log.includes('Error')) {
|
|
334
|
-
console.log(chalk_1.default.red(log));
|
|
335
|
-
}
|
|
336
|
-
else if (log.includes('warn') || log.includes('Warn')) {
|
|
337
|
-
console.log(chalk_1.default.yellow(log));
|
|
338
|
-
}
|
|
339
|
-
else {
|
|
340
|
-
console.log(log);
|
|
341
|
-
}
|
|
342
|
-
});
|
|
343
390
|
// Start real-time monitoring
|
|
344
|
-
const
|
|
391
|
+
const updateDisplay = () => {
|
|
345
392
|
try {
|
|
346
|
-
const
|
|
393
|
+
const { table, logs } = process_manager_js_1.processManager.monit(name);
|
|
347
394
|
process.stdout.write('\x1Bc'); // Clear screen
|
|
348
|
-
console.log(
|
|
349
|
-
console.log(chalk_1.default.blue(
|
|
350
|
-
|
|
351
|
-
console.log(`Status: ${updatedProcess.status}`);
|
|
352
|
-
console.log(`PID: ${updatedProcess.pid}`);
|
|
353
|
-
console.log(`Uptime: ${Math.floor(updatedProcess.uptime)}s`);
|
|
354
|
-
console.log(`Memory: ${updatedProcess.memory.toFixed(2)}MB`);
|
|
355
|
-
console.log(`Restarts: ${updatedProcess.restarts}/${updatedProcess.maxRestarts}`);
|
|
356
|
-
if (updatedProcess.lastError) {
|
|
357
|
-
console.log(`Last Error: ${chalk_1.default.red(updatedProcess.lastError)}`);
|
|
358
|
-
}
|
|
359
|
-
console.log(chalk_1.default.blue(`\nRecent Logs:`));
|
|
360
|
-
updatedProcess.logs.forEach(log => {
|
|
395
|
+
console.log(table);
|
|
396
|
+
console.log(chalk_1.default.blue('\nRecent Logs:'));
|
|
397
|
+
logs.forEach(log => {
|
|
361
398
|
if (log.includes('error') || log.includes('Error')) {
|
|
362
399
|
console.log(chalk_1.default.red(log));
|
|
363
400
|
}
|
|
@@ -370,14 +407,15 @@ function cli() {
|
|
|
370
407
|
});
|
|
371
408
|
}
|
|
372
409
|
catch (error) {
|
|
373
|
-
clearInterval(
|
|
410
|
+
clearInterval(monitorInterval);
|
|
374
411
|
console.error(chalk_1.default.red(`${figures_1.default.cross} Error monitoring process: ${error}`));
|
|
375
412
|
process.exit(1);
|
|
376
413
|
}
|
|
377
|
-
}
|
|
378
|
-
|
|
414
|
+
};
|
|
415
|
+
const monitorInterval = setInterval(updateDisplay, interval);
|
|
416
|
+
updateDisplay(); // Initial display
|
|
379
417
|
process.on('SIGINT', () => {
|
|
380
|
-
clearInterval(
|
|
418
|
+
clearInterval(monitorInterval);
|
|
381
419
|
process.exit(0);
|
|
382
420
|
});
|
|
383
421
|
}
|
|
@@ -392,31 +430,29 @@ function cli() {
|
|
|
392
430
|
}
|
|
393
431
|
});
|
|
394
432
|
program
|
|
395
|
-
.command('log <
|
|
433
|
+
.command('log <name>')
|
|
396
434
|
.description('View process logs')
|
|
397
|
-
.option('-l, --lines <number>', 'Number of lines to show', '100')
|
|
398
435
|
.option('-f, --follow', 'Follow log output')
|
|
399
|
-
.option('-e, --
|
|
400
|
-
.option('-w, --
|
|
401
|
-
.
|
|
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) => {
|
|
402
440
|
try {
|
|
403
|
-
const
|
|
404
|
-
if (
|
|
405
|
-
|
|
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') ||
|
|
406
449
|
log.toLowerCase().includes('exception'));
|
|
407
|
-
console.log(chalk_1.default.blue(`${figures_1.default.info} Error Logs:`));
|
|
408
|
-
errorLogs.forEach(log => console.log(chalk_1.default.red(log)));
|
|
409
|
-
return;
|
|
410
450
|
}
|
|
411
|
-
if (options.
|
|
412
|
-
|
|
451
|
+
else if (options.warnings) {
|
|
452
|
+
filteredLogs = logs.filter(log => log.toLowerCase().includes('warn') ||
|
|
413
453
|
log.toLowerCase().includes('warning'));
|
|
414
|
-
console.log(chalk_1.default.blue(`${figures_1.default.info} Warning Logs:`));
|
|
415
|
-
warnLogs.forEach(log => console.log(chalk_1.default.yellow(log)));
|
|
416
|
-
return;
|
|
417
454
|
}
|
|
418
|
-
|
|
419
|
-
logs.forEach(log => {
|
|
455
|
+
filteredLogs.forEach(log => {
|
|
420
456
|
if (log.includes('error') || log.includes('Error')) {
|
|
421
457
|
console.log(chalk_1.default.red(log));
|
|
422
458
|
}
|
|
@@ -428,11 +464,11 @@ function cli() {
|
|
|
428
464
|
}
|
|
429
465
|
});
|
|
430
466
|
if (options.follow) {
|
|
431
|
-
const watcher = (0, chokidar_1.watch)(process_manager_js_1.processManager.getLogPath(
|
|
467
|
+
const watcher = (0, chokidar_1.watch)(process_manager_js_1.processManager.getLogPath(name), {
|
|
432
468
|
persistent: true
|
|
433
469
|
});
|
|
434
470
|
watcher.on('change', () => {
|
|
435
|
-
const newLogs = process_manager_js_1.processManager.log(
|
|
471
|
+
const newLogs = process_manager_js_1.processManager.log(name, 1);
|
|
436
472
|
if (newLogs.length > 0) {
|
|
437
473
|
const log = newLogs[0];
|
|
438
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;
|
|
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
|
-
|
|
37
|
-
|
|
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(
|
|
40
|
-
return (0, path_1.join)(this.logDir, `${
|
|
47
|
+
getLogPath(name) {
|
|
48
|
+
return (0, path_1.join)(this.logDir, `${name}.log`);
|
|
41
49
|
}
|
|
42
|
-
async startx(
|
|
43
|
-
const
|
|
44
|
-
const
|
|
45
|
-
|
|
46
|
-
|
|
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
|
-
|
|
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(
|
|
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
|
|
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
|
-
|
|
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.
|
|
93
|
-
this.emit('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.
|
|
99
|
-
this.emit('error', {
|
|
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.
|
|
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.
|
|
117
|
+
this.restart(processInfo.name);
|
|
109
118
|
});
|
|
110
|
-
this.watchers.set(processInfo.
|
|
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 =
|
|
117
|
-
processInfo.memory = stats.
|
|
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', {
|
|
129
|
+
this.emit('stats', { name: processInfo.name, stats: processInfo });
|
|
120
130
|
}
|
|
121
131
|
catch (error) {
|
|
122
|
-
console.error(`Error monitoring process ${processInfo.
|
|
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', {
|
|
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', {
|
|
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', {
|
|
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.
|
|
158
|
+
this.processes.set(processInfo.name, processInfo);
|
|
150
159
|
this.saveConfig();
|
|
151
|
-
this.emit('start', {
|
|
160
|
+
this.emit('start', { name: processInfo.name, processInfo });
|
|
152
161
|
}
|
|
153
|
-
|
|
154
|
-
|
|
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 ${
|
|
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(
|
|
181
|
+
const watcher = this.watchers.get(name);
|
|
161
182
|
if (watcher) {
|
|
162
183
|
watcher.close();
|
|
163
|
-
this.watchers.delete(
|
|
184
|
+
this.watchers.delete(name);
|
|
164
185
|
}
|
|
165
|
-
this.processes.delete(
|
|
186
|
+
this.processes.delete(name);
|
|
166
187
|
this.saveConfig();
|
|
167
|
-
this.emit('stop', {
|
|
188
|
+
this.emit('stop', { name });
|
|
168
189
|
}
|
|
169
190
|
catch (error) {
|
|
170
|
-
throw new Error(`Failed to stop process ${
|
|
191
|
+
throw new Error(`Failed to stop process ${name}: ${error.message}`);
|
|
171
192
|
}
|
|
172
193
|
}
|
|
173
194
|
list() {
|
|
174
|
-
|
|
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(
|
|
177
|
-
const processInfo = this.processes.get(
|
|
215
|
+
monit(name) {
|
|
216
|
+
const processInfo = this.processes.get(name);
|
|
178
217
|
if (!processInfo) {
|
|
179
|
-
throw new Error(`Process ${
|
|
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
|
-
|
|
183
|
-
logs: processInfo.logs.slice(-100)
|
|
228
|
+
table: table.toString(),
|
|
229
|
+
logs: processInfo.logs.slice(-100)
|
|
184
230
|
};
|
|
185
231
|
}
|
|
186
|
-
log(
|
|
187
|
-
const processInfo = this.processes.get(
|
|
232
|
+
log(name, lines = 100) {
|
|
233
|
+
const processInfo = this.processes.get(name);
|
|
188
234
|
if (!processInfo) {
|
|
189
|
-
throw new Error(`Process ${
|
|
235
|
+
throw new Error(`Process ${name} not found`);
|
|
190
236
|
}
|
|
191
|
-
const logPath = this.getLogPath(
|
|
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(
|
|
199
|
-
const processInfo = this.processes.get(
|
|
244
|
+
async restart(name) {
|
|
245
|
+
const processInfo = this.processes.get(name);
|
|
200
246
|
if (!processInfo) {
|
|
201
|
-
throw new Error(`Process ${
|
|
247
|
+
throw new Error(`Process ${name} not found`);
|
|
202
248
|
}
|
|
203
|
-
await this.stopx(
|
|
249
|
+
await this.stopx(name);
|
|
204
250
|
processInfo.restarts++;
|
|
205
|
-
await this.startx(processInfo.
|
|
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.
|
|
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,14 +30,17 @@
|
|
|
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",
|
|
40
42
|
"ts-node": "^10.9.1",
|
|
43
|
+
"ts-node-dev": "^2.0.0",
|
|
41
44
|
"tsconfig-paths": "^4.2.0"
|
|
42
45
|
},
|
|
43
46
|
"devDependencies": {
|