neex 0.2.5 → 0.2.7

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,15 +6,13 @@
6
6
  </picture>
7
7
  </a>
8
8
 
9
- # Neex v0.2.5
10
-
9
+ # Neex v0.2.7
11
10
  ### 🚀 Neex: The Modern Build System for Polyrepo-in-Monorepo Architecture
12
11
 
13
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
13
  [![Download Count](https://img.shields.io/npm/dt/neex.svg?style=for-the-badge&labelColor=000000&color=0066FF&borderRadius=8)](https://www.npmjs.com/package/neex)
15
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)
16
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)
17
- </div>
18
16
 
19
17
  ## 🎯 Overview
20
18
 
@@ -25,7 +23,7 @@ Neex is a modern build system designed to bridge the gap between polyrepo and mo
25
23
  ## ✨ Key Features
26
24
 
27
25
  - 🎨 **Colored Output** - Distinguish commands with unique colors
28
- - ⚡ **Dual Execution Modes** - Run commands in parallel (`p`, `runx`) or sequence (`s`, `run`)
26
+ - ⚡ **Dual Execution Modes** - Run commands in parallel (`p`) or sequence (`s`)
29
27
  - ⏱️ **Smart Timing** - Track execution time for each command
30
28
  - 🛑 **Error Control** - Stop on first error (perfect for CI/CD)
31
29
  - 🔢 **Parallel Control** - Limit concurrent processes with `--max-parallel`
@@ -49,22 +47,45 @@ bun add -D neex # bun
49
47
 
50
48
  ## 🖥️ Usage
51
49
 
52
- ### Commands
50
+ ### Process Management Commands
53
51
 
54
- - `runx` (alias: `p`) - Run in **parallel** (default)
55
- - `run` (alias: `s`) - Run **sequentially**
52
+ ```bash
53
+ # Start a process
54
+ neex startx app.js -n "my-app" -w
55
+
56
+ # startx options
57
+ -n, --name <name> Process name
58
+ -w, --watch Watch for file changes
59
+ -r, --max-restarts <number> Maximum restart attempts
60
+ -d, --restart-delay <ms> Delay between restarts
61
+
62
+ # Stop a process
63
+ neex stopx <process-id>
64
+
65
+ # List processes
66
+ neex list
67
+ neex list -a # Show all processes
68
+ neex list -j # JSON output
69
+
70
+ # Monitor process
71
+ neex monit <process-id>
72
+ neex monit <process-id> -i 1000 # Set update interval
73
+
74
+ # View logs
75
+ neex log <process-id>
76
+ neex log <process-id> -f # Follow logs
77
+ neex log <process-id> -e # Show only errors
78
+ neex log <process-id> -w # Show only warnings
79
+ ```
56
80
 
57
- ### Examples
81
+ ### Script Execution Commands
58
82
 
59
83
  ```bash
60
- # Parallel execution (default)
61
- neex p "echo Task 1" "echo Task 2" "echo Task 3"
62
-
63
84
  # Sequential execution
64
- neex s "echo Step 1" "echo Step 2" "echo Step 3"
85
+ neex s "npm install" "npm run build"
65
86
 
66
- # Parallel with sequential flag
67
- neex p -q "echo Step 1" "echo Step 2" "echo Step 3"
87
+ # Parallel execution
88
+ neex p "npm run dev" "npm run watch"
68
89
  ```
69
90
 
70
91
  ### 🛠️ Options
@@ -79,14 +100,6 @@ neex p -q "echo Step 1" "echo Step 2" "echo Step 3"
79
100
  | `--max-parallel` | `-m` | Max parallel tasks | CPU count |
80
101
  | `--sequential` | `-q` | Force sequential | `false` |
81
102
 
82
-
83
- ### Advanced Example
84
-
85
- ```bash
86
- # Run tests & build with max 2 parallel tasks, stop on error
87
- neex p -s -m 2 -t "npm test" "npm run build" "npm run lint"
88
- ```
89
-
90
103
  ## 📦 Node.js API
91
104
 
92
105
  ```javascript
@@ -115,20 +128,6 @@ async function main() {
115
128
  }
116
129
  ```
117
130
 
118
- ### API Options
119
-
120
- ```typescript
121
- interface RunOptions {
122
- parallel?: boolean; // Run in parallel (default: true)
123
- maxParallel?: number; // Max parallel processes (default: CPU count)
124
- color?: boolean; // Enable colors (default: true)
125
- prefix?: boolean; // Show command prefix (default: true)
126
- showTiming?: boolean; // Show timing info (default: true)
127
- printOutput?: boolean; // Show command output (default: true)
128
- stopOnError?: boolean; // Stop on failure (default: false)
129
- }
130
- ```
131
-
132
131
  ## 🔄 CI/CD Integration
133
132
 
134
133
  ```yaml
@@ -143,17 +142,46 @@ steps:
143
142
 
144
143
  ## 💡 Real-world Examples
145
144
 
146
- ```bash
147
- # Dev servers
148
- neex p "cd frontend && npm dev" "cd api && npm dev"
149
-
150
- # Monorepo build
151
- neex p -m 2 "npm run build:ui" "npm run build:api"
145
+ ### Multi-part Project Execution
146
+
147
+ ```json
148
+ {
149
+ "scripts": {
150
+ "dev": "neex p dev:client dev:server",
151
+ "dev:client": "cd apps/client && npm run dev",
152
+ "dev:server": "cd apps/server && npm run dev",
153
+ "build": "neex s build:client build:server",
154
+ "build:client": "cd apps/client && npm run build",
155
+ "build:server": "cd apps/server && npm run build",
156
+ "start": "neex p start:client start:server",
157
+ "start:client": "cd apps/client && npm run start",
158
+ "start:server": "cd apps/server && npm run start"
159
+ }
160
+ }
161
+ ```
152
162
 
153
- # Deploy pipeline
154
- neex s -s "npm test" "npm run build" "npm run deploy"
163
+ ### Production Project Management
164
+
165
+ ```json
166
+ {
167
+ "scripts": {
168
+ "startx": "neex startx:client && neex startx:server",
169
+ "startx:client": "neex startx apps/client/index.js -n client -w",
170
+ "startx:server": "neex startx apps/server/index.js -n server -w",
171
+ "stopx": "neex stopx:client && neex stopx:server",
172
+ "stopx:client": "neex stopx client",
173
+ "stopx:server": "neex stopx server"
174
+ }
175
+ }
155
176
  ```
156
177
 
178
+ ## Important Notes
179
+
180
+ - Logs are stored in the `.neex-logs` directory
181
+ - Configuration is stored in `.neex-config.json`
182
+ - Use `Ctrl+C` to stop live monitoring
183
+ - Use `neex stopx -f` for force stop when needed
184
+
157
185
  ## 🤝 Contributing
158
186
 
159
187
  We welcome contributions! Check our [issues page](https://github.com/Neexjs).
package/bun.lock CHANGED
@@ -5,6 +5,7 @@
5
5
  "name": "nextpressx",
6
6
  "dependencies": {
7
7
  "chalk": "^4.1.2",
8
+ "chokidar": "^3.5.3",
8
9
  "commander": "^9.4.0",
9
10
  "figlet": "^1.8.1",
10
11
  "figures": "^3.2.0",
@@ -12,8 +13,11 @@
12
13
  "npm-run-path": "^4.0.1",
13
14
  "p-map": "^4.0.0",
14
15
  "string-width": "^4.2.3",
16
+ "ts-node": "^10.9.1",
17
+ "tsconfig-paths": "^4.2.0",
15
18
  },
16
19
  "devDependencies": {
20
+ "@types/chokidar": "^2.1.7",
17
21
  "@types/figlet": "^1.7.0",
18
22
  "@types/jest": "^29.2.3",
19
23
  "@types/node": "^18.11.9",
@@ -94,6 +98,8 @@
94
98
 
95
99
  "@bcoe/v8-coverage": ["@bcoe/v8-coverage@0.2.3", "", {}, "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw=="],
96
100
 
101
+ "@cspotcode/source-map-support": ["@cspotcode/source-map-support@0.8.1", "", { "dependencies": { "@jridgewell/trace-mapping": "0.3.9" } }, "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw=="],
102
+
97
103
  "@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=="],
98
104
 
99
105
  "@istanbuljs/schema": ["@istanbuljs/schema@0.1.3", "", {}, "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA=="],
@@ -142,6 +148,14 @@
142
148
 
143
149
  "@sinonjs/fake-timers": ["@sinonjs/fake-timers@10.3.0", "", { "dependencies": { "@sinonjs/commons": "^3.0.0" } }, "sha512-V4BG07kuYSUkTCSBHG8G8TNhM+F19jXFWnQtzj+we8DrkpSBCee9Z3Ms8yiGer/dlmhe35/Xdgyo3/0rQKg7YA=="],
144
150
 
151
+ "@tsconfig/node10": ["@tsconfig/node10@1.0.11", "", {}, "sha512-DcRjDCujK/kCk/cUe8Xz8ZSpm8mS3mNNpta+jGCA6USEDfktlNvm1+IuZ9eTcDbNk41BHwpHHeW+N1lKCz4zOw=="],
152
+
153
+ "@tsconfig/node12": ["@tsconfig/node12@1.0.11", "", {}, "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag=="],
154
+
155
+ "@tsconfig/node14": ["@tsconfig/node14@1.0.3", "", {}, "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow=="],
156
+
157
+ "@tsconfig/node16": ["@tsconfig/node16@1.0.4", "", {}, "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA=="],
158
+
145
159
  "@types/babel__core": ["@types/babel__core@7.20.5", "", { "dependencies": { "@babel/parser": "^7.20.7", "@babel/types": "^7.20.7", "@types/babel__generator": "*", "@types/babel__template": "*", "@types/babel__traverse": "*" } }, "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA=="],
146
160
 
147
161
  "@types/babel__generator": ["@types/babel__generator@7.27.0", "", { "dependencies": { "@babel/types": "^7.0.0" } }, "sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg=="],
@@ -150,6 +164,8 @@
150
164
 
151
165
  "@types/babel__traverse": ["@types/babel__traverse@7.20.7", "", { "dependencies": { "@babel/types": "^7.20.7" } }, "sha512-dkO5fhS7+/oos4ciWxyEyjWe48zmG6wbCheo/G2ZnHx4fs3EU6YC6UM8rk56gAjNJ9P3MTH2jo5jb92/K6wbng=="],
152
166
 
167
+ "@types/chokidar": ["@types/chokidar@2.1.7", "", { "dependencies": { "chokidar": "*" } }, "sha512-A7/MFHf6KF7peCzjEC1BBTF8jpmZTokb3vr/A0NxRGfwRLK3Ws+Hq6ugVn6cJIMfM6wkCak/aplWrxbTcu8oig=="],
168
+
153
169
  "@types/figlet": ["@types/figlet@1.7.0", "", {}, "sha512-KwrT7p/8Eo3Op/HBSIwGXOsTZKYiM9NpWRBJ5sVjWP/SmlS+oxxRvJht/FNAtliJvja44N3ul1yATgohnVBV0Q=="],
154
170
 
155
171
  "@types/graceful-fs": ["@types/graceful-fs@4.1.9", "", { "dependencies": { "@types/node": "*" } }, "sha512-olP3sd1qOEe5dXTSaFvQG+02VdRXcdytWLAZsAq1PecU8uqQAhkrnbli7DagjtXKW/Bl7YJbUsa8MPcuc8LHEQ=="],
@@ -172,6 +188,10 @@
172
188
 
173
189
  "@types/yargs-parser": ["@types/yargs-parser@21.0.3", "", {}, "sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ=="],
174
190
 
191
+ "acorn": ["acorn@8.15.0", "", { "bin": { "acorn": "bin/acorn" } }, "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg=="],
192
+
193
+ "acorn-walk": ["acorn-walk@8.3.4", "", { "dependencies": { "acorn": "^8.11.0" } }, "sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g=="],
194
+
175
195
  "aggregate-error": ["aggregate-error@3.1.0", "", { "dependencies": { "clean-stack": "^2.0.0", "indent-string": "^4.0.0" } }, "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA=="],
176
196
 
177
197
  "ansi-escapes": ["ansi-escapes@4.3.2", "", { "dependencies": { "type-fest": "^0.21.3" } }, "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ=="],
@@ -182,6 +202,8 @@
182
202
 
183
203
  "anymatch": ["anymatch@3.1.3", "", { "dependencies": { "normalize-path": "^3.0.0", "picomatch": "^2.0.4" } }, "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw=="],
184
204
 
205
+ "arg": ["arg@4.1.3", "", {}, "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA=="],
206
+
185
207
  "argparse": ["argparse@1.0.10", "", { "dependencies": { "sprintf-js": "~1.0.2" } }, "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg=="],
186
208
 
187
209
  "async": ["async@3.2.6", "", {}, "sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA=="],
@@ -198,6 +220,8 @@
198
220
 
199
221
  "balanced-match": ["balanced-match@1.0.2", "", {}, "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="],
200
222
 
223
+ "binary-extensions": ["binary-extensions@2.3.0", "", {}, "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw=="],
224
+
201
225
  "brace-expansion": ["brace-expansion@1.1.11", "", { "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA=="],
202
226
 
203
227
  "braces": ["braces@3.0.3", "", { "dependencies": { "fill-range": "^7.1.1" } }, "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA=="],
@@ -220,6 +244,8 @@
220
244
 
221
245
  "char-regex": ["char-regex@1.0.2", "", {}, "sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw=="],
222
246
 
247
+ "chokidar": ["chokidar@3.6.0", "", { "dependencies": { "anymatch": "~3.1.2", "braces": "~3.0.2", "glob-parent": "~5.1.2", "is-binary-path": "~2.1.0", "is-glob": "~4.0.1", "normalize-path": "~3.0.0", "readdirp": "~3.6.0" }, "optionalDependencies": { "fsevents": "~2.3.2" } }, "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw=="],
248
+
223
249
  "ci-info": ["ci-info@3.9.0", "", {}, "sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ=="],
224
250
 
225
251
  "cjs-module-lexer": ["cjs-module-lexer@1.4.3", "", {}, "sha512-9z8TZaGM1pfswYeXrUpzPrkx8UnWYdhJclsiYMm6x/w5+nN+8Tf/LnAgfLGQCm59qAOxU8WwHEq2vNwF6i4j+Q=="],
@@ -244,6 +270,8 @@
244
270
 
245
271
  "create-jest": ["create-jest@29.7.0", "", { "dependencies": { "@jest/types": "^29.6.3", "chalk": "^4.0.0", "exit": "^0.1.2", "graceful-fs": "^4.2.9", "jest-config": "^29.7.0", "jest-util": "^29.7.0", "prompts": "^2.0.1" }, "bin": "bin/create-jest.js" }, "sha512-Adz2bdH0Vq3F53KEMJOoftQFutWCukm6J24wbPWRO4k1kMY7gS7ds/uoJkNuV8wDCtWWnuwGcJwpWcih+zEW1Q=="],
246
272
 
273
+ "create-require": ["create-require@1.1.1", "", {}, "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ=="],
274
+
247
275
  "cross-spawn": ["cross-spawn@7.0.6", "", { "dependencies": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", "which": "^2.0.1" } }, "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA=="],
248
276
 
249
277
  "debug": ["debug@4.4.0", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA=="],
@@ -254,6 +282,8 @@
254
282
 
255
283
  "detect-newline": ["detect-newline@3.1.0", "", {}, "sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA=="],
256
284
 
285
+ "diff": ["diff@4.0.2", "", {}, "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A=="],
286
+
257
287
  "diff-sequences": ["diff-sequences@29.6.3", "", {}, "sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q=="],
258
288
 
259
289
  "ejs": ["ejs@3.1.10", "", { "dependencies": { "jake": "^10.8.5" }, "bin": "bin/cli.js" }, "sha512-UeJmFfOrAQS8OJWPZ4qtgHyWExa088/MtK5UEyoJGFH67cDEXkZSviOiKRCZ4Xij0zxI3JECgYs3oKx+AizQBA=="],
@@ -308,6 +338,8 @@
308
338
 
309
339
  "glob": ["glob@7.2.3", "", { "dependencies": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", "inherits": "2", "minimatch": "^3.1.1", "once": "^1.3.0", "path-is-absolute": "^1.0.0" } }, "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q=="],
310
340
 
341
+ "glob-parent": ["glob-parent@5.1.2", "", { "dependencies": { "is-glob": "^4.0.1" } }, "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow=="],
342
+
311
343
  "globals": ["globals@11.12.0", "", {}, "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA=="],
312
344
 
313
345
  "graceful-fs": ["graceful-fs@4.2.11", "", {}, "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ=="],
@@ -334,12 +366,18 @@
334
366
 
335
367
  "is-arrayish": ["is-arrayish@0.2.1", "", {}, "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg=="],
336
368
 
369
+ "is-binary-path": ["is-binary-path@2.1.0", "", { "dependencies": { "binary-extensions": "^2.0.0" } }, "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw=="],
370
+
337
371
  "is-core-module": ["is-core-module@2.16.1", "", { "dependencies": { "hasown": "^2.0.2" } }, "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w=="],
338
372
 
373
+ "is-extglob": ["is-extglob@2.1.1", "", {}, "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ=="],
374
+
339
375
  "is-fullwidth-code-point": ["is-fullwidth-code-point@3.0.0", "", {}, "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg=="],
340
376
 
341
377
  "is-generator-fn": ["is-generator-fn@2.1.0", "", {}, "sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ=="],
342
378
 
379
+ "is-glob": ["is-glob@4.0.3", "", { "dependencies": { "is-extglob": "^2.1.1" } }, "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg=="],
380
+
343
381
  "is-number": ["is-number@7.0.0", "", {}, "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng=="],
344
382
 
345
383
  "is-stream": ["is-stream@2.0.1", "", {}, "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg=="],
@@ -446,6 +484,8 @@
446
484
 
447
485
  "minimatch": ["minimatch@3.1.2", "", { "dependencies": { "brace-expansion": "^1.1.7" } }, "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw=="],
448
486
 
487
+ "minimist": ["minimist@1.2.8", "", {}, "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA=="],
488
+
449
489
  "ms": ["ms@2.1.3", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="],
450
490
 
451
491
  "natural-compare": ["natural-compare@1.4.0", "", {}, "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw=="],
@@ -496,6 +536,8 @@
496
536
 
497
537
  "react-is": ["react-is@18.3.1", "", {}, "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg=="],
498
538
 
539
+ "readdirp": ["readdirp@3.6.0", "", { "dependencies": { "picomatch": "^2.2.1" } }, "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA=="],
540
+
499
541
  "require-directory": ["require-directory@2.1.1", "", {}, "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q=="],
500
542
 
501
543
  "resolve": ["resolve@1.22.10", "", { "dependencies": { "is-core-module": "^2.16.0", "path-parse": "^1.0.7", "supports-preserve-symlinks-flag": "^1.0.0" }, "bin": "bin/resolve" }, "sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w=="],
@@ -532,7 +574,7 @@
532
574
 
533
575
  "strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="],
534
576
 
535
- "strip-bom": ["strip-bom@4.0.0", "", {}, "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w=="],
577
+ "strip-bom": ["strip-bom@3.0.0", "", {}, "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA=="],
536
578
 
537
579
  "strip-final-newline": ["strip-final-newline@2.0.0", "", {}, "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA=="],
538
580
 
@@ -554,6 +596,10 @@
554
596
 
555
597
  "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=="],
556
598
 
599
+ "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
+
601
+ "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
+
557
603
  "type-detect": ["type-detect@4.0.8", "", {}, "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g=="],
558
604
 
559
605
  "type-fest": ["type-fest@4.41.0", "", {}, "sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA=="],
@@ -564,6 +610,8 @@
564
610
 
565
611
  "update-browserslist-db": ["update-browserslist-db@1.1.3", "", { "dependencies": { "escalade": "^3.2.0", "picocolors": "^1.1.1" }, "peerDependencies": { "browserslist": ">= 4.21.0" }, "bin": "cli.js" }, "sha512-UxhIZQ+QInVdunkDAaiazvvT/+fXL5Osr0JZlJulepYu6Jd7qJtDZjlur0emRlT71EN3ScPoE7gvsuIKKNavKw=="],
566
612
 
613
+ "v8-compile-cache-lib": ["v8-compile-cache-lib@3.0.1", "", {}, "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg=="],
614
+
567
615
  "v8-to-istanbul": ["v8-to-istanbul@9.3.0", "", { "dependencies": { "@jridgewell/trace-mapping": "^0.3.12", "@types/istanbul-lib-coverage": "^2.0.1", "convert-source-map": "^2.0.0" } }, "sha512-kiGUalWN+rgBJ/1OHZsBtU4rXZOfj/7rKQxULKlIzwzQSvMJUUNgPwJEEh7gU6xEVxC0ahoOBvN2YI8GH6FNgA=="],
568
616
 
569
617
  "walker": ["walker@1.0.8", "", { "dependencies": { "makeerror": "1.0.12" } }, "sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ=="],
@@ -584,12 +632,16 @@
584
632
 
585
633
  "yargs-parser": ["yargs-parser@21.1.1", "", {}, "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw=="],
586
634
 
635
+ "yn": ["yn@3.1.1", "", {}, "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q=="],
636
+
587
637
  "yocto-queue": ["yocto-queue@0.1.0", "", {}, "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q=="],
588
638
 
589
639
  "@babel/core/semver": ["semver@6.3.1", "", { "bin": "bin/semver.js" }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="],
590
640
 
591
641
  "@babel/helper-compilation-targets/semver": ["semver@6.3.1", "", { "bin": "bin/semver.js" }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="],
592
642
 
643
+ "@cspotcode/source-map-support/@jridgewell/trace-mapping": ["@jridgewell/trace-mapping@0.3.9", "", { "dependencies": { "@jridgewell/resolve-uri": "^3.0.3", "@jridgewell/sourcemap-codec": "^1.4.10" } }, "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ=="],
644
+
593
645
  "@istanbuljs/load-nyc-config/camelcase": ["camelcase@5.3.1", "", {}, "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg=="],
594
646
 
595
647
  "ansi-escapes/type-fest": ["type-fest@0.21.3", "", {}, "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w=="],
@@ -600,14 +652,10 @@
600
652
 
601
653
  "gradient-string/chalk": ["chalk@5.4.1", "", {}, "sha512-zgVZuo2WcZgfUEmsn6eO3kINexW8RAE4maiQ8QNs8CtpPCSyMiYsULR3HQYkm3w8FIA3SberyMJMSldGsW+U3w=="],
602
654
 
603
- "istanbul-lib-instrument/semver": ["semver@7.7.2", "", { "bin": "bin/semver.js" }, "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA=="],
604
-
605
- "jest-snapshot/semver": ["semver@7.7.2", "", { "bin": "bin/semver.js" }, "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA=="],
655
+ "jest-runtime/strip-bom": ["strip-bom@4.0.0", "", {}, "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w=="],
606
656
 
607
657
  "jest-worker/supports-color": ["supports-color@8.1.1", "", { "dependencies": { "has-flag": "^4.0.0" } }, "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q=="],
608
658
 
609
- "make-dir/semver": ["semver@7.7.2", "", { "bin": "bin/semver.js" }, "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA=="],
610
-
611
659
  "p-locate/p-limit": ["p-limit@2.3.0", "", { "dependencies": { "p-try": "^2.0.0" } }, "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w=="],
612
660
 
613
661
  "pretty-format/ansi-styles": ["ansi-styles@5.2.0", "", {}, "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA=="],
package/dist/src/cli.js CHANGED
@@ -8,6 +8,11 @@ const commander_1 = require("commander");
8
8
  const index_js_1 = require("./index.js");
9
9
  const chalk_1 = __importDefault(require("chalk"));
10
10
  const figures_1 = __importDefault(require("figures"));
11
+ const chokidar_1 = require("chokidar");
12
+ const child_process_1 = require("child_process");
13
+ const path_1 = require("path");
14
+ const fs_1 = require("fs");
15
+ const process_manager_js_1 = require("./process-manager.js");
11
16
  const { version } = require('../../package.json');
12
17
  function cli() {
13
18
  const program = new commander_1.Command();
@@ -16,9 +21,149 @@ function cli() {
16
21
  .name('neex')
17
22
  .description('Professional script runner with beautiful colored output')
18
23
  .version(version);
19
- // Main command for sequential execution (similar to run-s)
24
+ // Development command for Express.js projects
20
25
  program
21
- .command('run <commands...>')
26
+ .command('dev <entry>')
27
+ .description('Run Express.js project in development mode with TypeScript support')
28
+ .option('-p, --port <number>', 'Port to run the server on', '3000')
29
+ .option('-w, --watch <path>', 'Path to watch for changes', 'src')
30
+ .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')
33
+ .action(async (entry, options) => {
34
+ try {
35
+ const entryPath = (0, path_1.resolve)(process.cwd(), entry);
36
+ if (!(0, fs_1.existsSync)(entryPath)) {
37
+ throw new Error(`Entry file ${entry} not found`);
38
+ }
39
+ 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'
57
+ }
58
+ });
59
+ cleanupRunner = () => {
60
+ server.kill();
61
+ };
62
+ server.on('error', (err) => {
63
+ console.error(chalk_1.default.red(`${figures_1.default.cross} Server error: ${err.message}`));
64
+ process.exit(1);
65
+ });
66
+ }
67
+ catch (error) {
68
+ if (error instanceof Error) {
69
+ console.error(chalk_1.default.red(`${figures_1.default.cross} Error: ${error.message}`));
70
+ }
71
+ else {
72
+ console.error(chalk_1.default.red(`${figures_1.default.cross} An unknown error occurred`));
73
+ }
74
+ process.exit(1);
75
+ }
76
+ });
77
+ // Build command for TypeScript compilation
78
+ program
79
+ .command('build')
80
+ .description('Build TypeScript project')
81
+ .option('-o, --outDir <dir>', 'Output directory', 'dist')
82
+ .action(async (options) => {
83
+ try {
84
+ console.log(chalk_1.default.blue(`${figures_1.default.info} Building project...`));
85
+ const build = (0, child_process_1.spawn)('tsc', [
86
+ '--outDir', options.outDir
87
+ ], {
88
+ stdio: 'inherit'
89
+ });
90
+ build.on('close', (code) => {
91
+ if (code === 0) {
92
+ console.log(chalk_1.default.green(`${figures_1.default.tick} Build completed successfully`));
93
+ }
94
+ else {
95
+ console.error(chalk_1.default.red(`${figures_1.default.cross} Build failed with code ${code}`));
96
+ process.exit(code !== null && code !== void 0 ? code : 1);
97
+ }
98
+ });
99
+ }
100
+ catch (error) {
101
+ if (error instanceof Error) {
102
+ console.error(chalk_1.default.red(`${figures_1.default.cross} Error: ${error.message}`));
103
+ }
104
+ else {
105
+ console.error(chalk_1.default.red(`${figures_1.default.cross} An unknown error occurred`));
106
+ }
107
+ process.exit(1);
108
+ }
109
+ });
110
+ // Start command for production
111
+ program
112
+ .command('start <entry>')
113
+ .description('Start Express.js project in production mode')
114
+ .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) => {
119
+ try {
120
+ const entryPath = (0, path_1.resolve)(process.cwd(), entry);
121
+ if (!(0, fs_1.existsSync)(entryPath)) {
122
+ throw new Error(`Entry file ${entry} not found`);
123
+ }
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);
136
+ }
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
+ }
154
+ catch (error) {
155
+ if (error instanceof Error) {
156
+ console.error(chalk_1.default.red(`${figures_1.default.cross} Error: ${error.message}`));
157
+ }
158
+ else {
159
+ console.error(chalk_1.default.red(`${figures_1.default.cross} An unknown error occurred`));
160
+ }
161
+ process.exit(1);
162
+ }
163
+ });
164
+ // Main command for sequential execution (similar to )
165
+ program
166
+ .command('sequential <commands...>')
22
167
  .alias('s')
23
168
  .description('Run commands sequentially')
24
169
  .option('-c, --no-color', 'Disable colored output')
@@ -52,7 +197,7 @@ function cli() {
52
197
  });
53
198
  // runx command: parallel execution by default (with alias 'p'), can run sequentially with -q
54
199
  program
55
- .command('runx <commands...>', { isDefault: true })
200
+ .command('parallel <commands...>', { isDefault: true })
56
201
  .alias('p')
57
202
  .description('Run commands in parallel (default) or sequentially with -q. Alias: p')
58
203
  .option('-c, --no-color', 'Disable colored output')
@@ -87,39 +232,239 @@ function cli() {
87
232
  process.exit(1);
88
233
  }
89
234
  });
90
- // Add a new servers command specifically optimized for running web servers
235
+ // Process Management Commands
91
236
  program
92
- .command('servers <commands...>')
93
- .alias('srv')
94
- .description('Run multiple servers with optimized output for API, frontend, etc.')
95
- .option('-c, --no-color', 'Disable colored output')
96
- .option('-t, --no-timing', 'Hide timing information')
97
- .option('-p, --no-prefix', 'Hide command prefix')
98
- .option('-s, --stop-on-error', 'Stop when any server crashes')
99
- .option('-x, --max-parallel <number>', 'Maximum number of parallel servers', parseInt)
100
- .option('-g, --group-output', 'Group outputs by server')
101
- .action(async (commands, options) => {
237
+ .command('startx <path>')
238
+ .description('Start a process with monitoring and auto-restart')
239
+ .option('-n, --name <name>', 'Process name')
240
+ .option('-w, --watch', 'Watch for file changes and auto-restart')
241
+ .option('-r, --max-restarts <number>', 'Maximum number of restart attempts', '5')
242
+ .option('-d, --restart-delay <number>', 'Delay between restarts in milliseconds', '1000')
243
+ .action(async (path, options) => {
102
244
  try {
103
- console.log(chalk_1.default.blue(`${figures_1.default.info} Starting servers in parallel mode...`));
104
- await (0, index_js_1.run)(commands, {
105
- parallel: true,
106
- maxParallel: options.maxParallel,
107
- color: options.color,
108
- showTiming: options.timing,
109
- prefix: options.prefix,
110
- stopOnError: options.stopOnError,
111
- printOutput: true,
112
- registerCleanup: (cleanup) => { cleanupRunner = cleanup; },
113
- groupOutput: options.groupOutput,
114
- isServerMode: true // Special flag for server mode formatting
245
+ const process = await process_manager_js_1.processManager.startx(path, {
246
+ name: options.name,
247
+ watch: options.watch,
248
+ maxRestarts: parseInt(options.maxRestarts),
249
+ restartDelay: parseInt(options.restartDelay)
250
+ });
251
+ console.log(chalk_1.default.green(`${figures_1.default.tick} Process started successfully`));
252
+ console.log(chalk_1.default.blue(`ID: ${process.id}`));
253
+ console.log(chalk_1.default.blue(`Name: ${process.name}`));
254
+ console.log(chalk_1.default.blue(`PID: ${process.pid}`));
255
+ console.log(chalk_1.default.blue(`Max Restarts: ${process.maxRestarts}`));
256
+ console.log(chalk_1.default.blue(`Restart Delay: ${process.restartDelay}ms`));
257
+ }
258
+ catch (error) {
259
+ if (error instanceof Error) {
260
+ console.error(chalk_1.default.red(`${figures_1.default.cross} Error: ${error.message}`));
261
+ }
262
+ else {
263
+ console.error(chalk_1.default.red(`${figures_1.default.cross} An unknown error occurred`));
264
+ }
265
+ process.exit(1);
266
+ }
267
+ });
268
+ program
269
+ .command('stopx <id>')
270
+ .description('Stop a running process')
271
+ .option('-f, --force', 'Force stop the process')
272
+ .action(async (id, options) => {
273
+ try {
274
+ await process_manager_js_1.processManager.stopx(id);
275
+ console.log(chalk_1.default.green(`${figures_1.default.tick} Process stopped successfully`));
276
+ }
277
+ catch (error) {
278
+ if (error instanceof Error) {
279
+ console.error(chalk_1.default.red(`${figures_1.default.cross} Error: ${error.message}`));
280
+ }
281
+ else {
282
+ console.error(chalk_1.default.red(`${figures_1.default.cross} An unknown error occurred`));
283
+ }
284
+ process.exit(1);
285
+ }
286
+ });
287
+ program
288
+ .command('list')
289
+ .description('List all running processes')
290
+ .option('-a, --all', 'Show all processes including stopped ones')
291
+ .option('-j, --json', 'Output in JSON format')
292
+ .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;
302
+ }
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)}`);
317
+ }
318
+ });
319
+ });
320
+ program
321
+ .command('monit <id>')
322
+ .description('Monitor a specific process')
323
+ .option('-i, --interval <number>', 'Update interval in milliseconds', '1000')
324
+ .action((id, options) => {
325
+ 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)}`);
337
+ }
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
+ // Start real-time monitoring
351
+ const interval = setInterval(() => {
352
+ try {
353
+ const updatedProcess = process_manager_js_1.processManager.monit(id);
354
+ 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 => {
368
+ if (log.includes('error') || log.includes('Error')) {
369
+ console.log(chalk_1.default.red(log));
370
+ }
371
+ else if (log.includes('warn') || log.includes('Warn')) {
372
+ console.log(chalk_1.default.yellow(log));
373
+ }
374
+ else {
375
+ console.log(log);
376
+ }
377
+ });
378
+ }
379
+ catch (error) {
380
+ clearInterval(interval);
381
+ console.error(chalk_1.default.red(`${figures_1.default.cross} Error monitoring process: ${error}`));
382
+ process.exit(1);
383
+ }
384
+ }, parseInt(options.interval));
385
+ // Handle cleanup
386
+ process.on('SIGINT', () => {
387
+ clearInterval(interval);
388
+ process.exit(0);
389
+ });
390
+ }
391
+ catch (error) {
392
+ if (error instanceof Error) {
393
+ console.error(chalk_1.default.red(`${figures_1.default.cross} Error: ${error.message}`));
394
+ }
395
+ else {
396
+ console.error(chalk_1.default.red(`${figures_1.default.cross} An unknown error occurred`));
397
+ }
398
+ process.exit(1);
399
+ }
400
+ });
401
+ program
402
+ .command('log <id>')
403
+ .description('View process logs')
404
+ .option('-l, --lines <number>', 'Number of lines to show', '100')
405
+ .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) => {
409
+ 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') ||
413
+ 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
+ }
418
+ if (options.warn) {
419
+ const warnLogs = logs.filter(log => log.toLowerCase().includes('warn') ||
420
+ 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
+ }
425
+ console.log(chalk_1.default.blue(`${figures_1.default.info} Process Logs:`));
426
+ logs.forEach(log => {
427
+ if (log.includes('error') || log.includes('Error')) {
428
+ console.log(chalk_1.default.red(log));
429
+ }
430
+ else if (log.includes('warn') || log.includes('Warn')) {
431
+ console.log(chalk_1.default.yellow(log));
432
+ }
433
+ else {
434
+ console.log(log);
435
+ }
115
436
  });
437
+ if (options.follow) {
438
+ const watcher = (0, chokidar_1.watch)(process_manager_js_1.processManager.getLogPath(id), {
439
+ persistent: true
440
+ });
441
+ watcher.on('change', () => {
442
+ const newLogs = process_manager_js_1.processManager.log(id, 1);
443
+ if (newLogs.length > 0) {
444
+ const log = newLogs[0];
445
+ if (log.includes('error') || log.includes('Error')) {
446
+ console.log(chalk_1.default.red(log));
447
+ }
448
+ else if (log.includes('warn') || log.includes('Warn')) {
449
+ console.log(chalk_1.default.yellow(log));
450
+ }
451
+ else {
452
+ console.log(log);
453
+ }
454
+ }
455
+ });
456
+ process.on('SIGINT', () => {
457
+ watcher.close();
458
+ process.exit(0);
459
+ });
460
+ }
116
461
  }
117
462
  catch (error) {
118
463
  if (error instanceof Error) {
119
- console.error(chalk_1.default.red(`${figures_1.default.cross} Server Error: ${error.message}`));
464
+ console.error(chalk_1.default.red(`${figures_1.default.cross} Error: ${error.message}`));
120
465
  }
121
466
  else {
122
- console.error(chalk_1.default.red(`${figures_1.default.cross} An unknown server error occurred`));
467
+ console.error(chalk_1.default.red(`${figures_1.default.cross} An unknown error occurred`));
123
468
  }
124
469
  process.exit(1);
125
470
  }
@@ -0,0 +1,208 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.processManager = void 0;
4
+ const child_process_1 = require("child_process");
5
+ const chokidar_1 = require("chokidar");
6
+ const fs_1 = require("fs");
7
+ const path_1 = require("path");
8
+ const events_1 = require("events");
9
+ class ProcessManager extends events_1.EventEmitter {
10
+ constructor() {
11
+ super();
12
+ this.processes = new Map();
13
+ this.watchers = new Map();
14
+ this.defaultMaxRestarts = 5;
15
+ this.defaultRestartDelay = 1000; // 1 second
16
+ this.logDir = (0, path_1.resolve)(process.cwd(), '.neex-logs');
17
+ this.configFile = (0, path_1.resolve)(process.cwd(), '.neex-config.json');
18
+ this.initialize();
19
+ }
20
+ initialize() {
21
+ if (!(0, fs_1.existsSync)(this.logDir)) {
22
+ (0, fs_1.mkdirSync)(this.logDir, { recursive: true });
23
+ }
24
+ this.loadConfig();
25
+ }
26
+ loadConfig() {
27
+ if ((0, fs_1.existsSync)(this.configFile)) {
28
+ const config = JSON.parse((0, fs_1.readFileSync)(this.configFile, 'utf-8'));
29
+ this.processes = new Map(Object.entries(config));
30
+ }
31
+ }
32
+ saveConfig() {
33
+ const config = Object.fromEntries(this.processes);
34
+ (0, fs_1.writeFileSync)(this.configFile, JSON.stringify(config, null, 2));
35
+ }
36
+ generateId() {
37
+ return Math.random().toString(36).substring(2, 15);
38
+ }
39
+ getLogPath(id) {
40
+ return (0, path_1.join)(this.logDir, `${id}.log`);
41
+ }
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`);
48
+ }
49
+ const processInfo = {
50
+ id,
51
+ name,
52
+ pid: 0,
53
+ status: 'stopped',
54
+ startTime: Date.now(),
55
+ path: fullPath,
56
+ command: `node ${fullPath}`,
57
+ logs: [],
58
+ memory: 0,
59
+ cpu: 0,
60
+ uptime: 0,
61
+ restarts: 0,
62
+ maxRestarts: options.maxRestarts || this.defaultMaxRestarts,
63
+ restartDelay: options.restartDelay || this.defaultRestartDelay,
64
+ watch: options.watch
65
+ };
66
+ try {
67
+ await this.startProcess(processInfo);
68
+ return processInfo;
69
+ }
70
+ catch (error) {
71
+ processInfo.status = 'error';
72
+ processInfo.lastError = error.message;
73
+ this.processes.set(id, processInfo);
74
+ this.saveConfig();
75
+ throw error;
76
+ }
77
+ }
78
+ async startProcess(processInfo) {
79
+ var _a, _b;
80
+ const child = (0, child_process_1.spawn)('node', [processInfo.path], {
81
+ stdio: ['ignore', 'pipe', 'pipe'],
82
+ env: { ...process.env, NODE_ENV: 'production' }
83
+ });
84
+ processInfo.pid = child.pid || 0;
85
+ processInfo.status = 'running';
86
+ processInfo.startTime = Date.now();
87
+ // Setup logging
88
+ const logStream = (0, fs_1.writeFileSync)(this.getLogPath(processInfo.id), '', { flag: 'a' });
89
+ (_a = child.stdout) === null || _a === void 0 ? void 0 : _a.on('data', (data) => {
90
+ const log = data.toString();
91
+ processInfo.logs.push(log);
92
+ (0, fs_1.writeFileSync)(this.getLogPath(processInfo.id), log, { flag: 'a' });
93
+ this.emit('log', { id: processInfo.id, log });
94
+ });
95
+ (_b = child.stderr) === null || _b === void 0 ? void 0 : _b.on('data', (data) => {
96
+ const log = data.toString();
97
+ processInfo.logs.push(log);
98
+ (0, fs_1.writeFileSync)(this.getLogPath(processInfo.id), log, { flag: 'a' });
99
+ this.emit('error', { id: processInfo.id, log });
100
+ });
101
+ // Setup monitoring
102
+ if (processInfo.watch) {
103
+ const watcher = (0, chokidar_1.watch)(processInfo.path, {
104
+ ignored: /(^|[\/\\])\../,
105
+ persistent: true
106
+ });
107
+ watcher.on('change', () => {
108
+ this.restart(processInfo.id);
109
+ });
110
+ this.watchers.set(processInfo.id, watcher);
111
+ }
112
+ // Monitor process
113
+ const monitorInterval = setInterval(() => {
114
+ if (child.pid) {
115
+ try {
116
+ const stats = process.memoryUsage();
117
+ processInfo.memory = stats.heapUsed / 1024 / 1024; // MB
118
+ processInfo.uptime = (Date.now() - processInfo.startTime) / 1000;
119
+ this.emit('stats', { id: processInfo.id, stats: processInfo });
120
+ }
121
+ catch (error) {
122
+ console.error(`Error monitoring process ${processInfo.id}:`, error);
123
+ }
124
+ }
125
+ }, 1000);
126
+ child.on('exit', async (code) => {
127
+ clearInterval(monitorInterval);
128
+ if (code !== 0) {
129
+ processInfo.status = 'error';
130
+ processInfo.lastError = `Process exited with code ${code}`;
131
+ this.emit('error', { id: processInfo.id, code });
132
+ // Auto-restart logic
133
+ if (processInfo.restarts < processInfo.maxRestarts) {
134
+ processInfo.status = 'restarting';
135
+ this.emit('restart', { id: processInfo.id, attempt: processInfo.restarts + 1 });
136
+ await new Promise(resolve => setTimeout(resolve, processInfo.restartDelay));
137
+ processInfo.restarts++;
138
+ await this.startProcess(processInfo);
139
+ }
140
+ else {
141
+ this.emit('max-restarts', { id: processInfo.id, maxRestarts: processInfo.maxRestarts });
142
+ }
143
+ }
144
+ else {
145
+ processInfo.status = 'stopped';
146
+ }
147
+ this.saveConfig();
148
+ });
149
+ this.processes.set(processInfo.id, processInfo);
150
+ this.saveConfig();
151
+ this.emit('start', { id: processInfo.id, processInfo });
152
+ }
153
+ async stopx(id) {
154
+ const processInfo = this.processes.get(id);
155
+ if (!processInfo) {
156
+ throw new Error(`Process ${id} not found`);
157
+ }
158
+ try {
159
+ process.kill(processInfo.pid);
160
+ const watcher = this.watchers.get(id);
161
+ if (watcher) {
162
+ watcher.close();
163
+ this.watchers.delete(id);
164
+ }
165
+ this.processes.delete(id);
166
+ this.saveConfig();
167
+ this.emit('stop', { id });
168
+ }
169
+ catch (error) {
170
+ throw new Error(`Failed to stop process ${id}: ${error.message}`);
171
+ }
172
+ }
173
+ list() {
174
+ return Array.from(this.processes.values());
175
+ }
176
+ monit(id) {
177
+ const processInfo = this.processes.get(id);
178
+ if (!processInfo) {
179
+ throw new Error(`Process ${id} not found`);
180
+ }
181
+ return {
182
+ ...processInfo,
183
+ logs: processInfo.logs.slice(-100) // Last 100 logs
184
+ };
185
+ }
186
+ log(id, lines = 100) {
187
+ const processInfo = this.processes.get(id);
188
+ if (!processInfo) {
189
+ throw new Error(`Process ${id} not found`);
190
+ }
191
+ const logPath = this.getLogPath(id);
192
+ if (!(0, fs_1.existsSync)(logPath)) {
193
+ return [];
194
+ }
195
+ const logs = (0, fs_1.readFileSync)(logPath, 'utf-8').split('\n');
196
+ return logs.slice(-lines);
197
+ }
198
+ async restart(id) {
199
+ const processInfo = this.processes.get(id);
200
+ if (!processInfo) {
201
+ throw new Error(`Process ${id} not found`);
202
+ }
203
+ await this.stopx(id);
204
+ processInfo.restarts++;
205
+ await this.startx(processInfo.path, { name: processInfo.name, watch: true });
206
+ }
207
+ }
208
+ exports.processManager = new ProcessManager();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "neex",
3
- "version": "0.2.5",
3
+ "version": "0.2.7",
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",
@@ -29,15 +29,20 @@
29
29
  "license": "MIT",
30
30
  "dependencies": {
31
31
  "chalk": "^4.1.2",
32
+ "chokidar": "^3.5.3",
32
33
  "commander": "^9.4.0",
33
34
  "figlet": "^1.8.1",
34
35
  "figures": "^3.2.0",
35
36
  "gradient-string": "^3.0.0",
36
37
  "npm-run-path": "^4.0.1",
37
38
  "p-map": "^4.0.0",
38
- "string-width": "^4.2.3"
39
+ "string-width": "^4.2.3",
40
+ "ts-node": "^10.9.1",
41
+ "ts-node-dev": "^2.0.0",
42
+ "tsconfig-paths": "^4.2.0"
39
43
  },
40
44
  "devDependencies": {
45
+ "@types/chokidar": "^2.1.7",
41
46
  "@types/figlet": "^1.7.0",
42
47
  "@types/jest": "^29.2.3",
43
48
  "@types/node": "^18.11.9",