neex 0.1.5 → 0.1.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -6,7 +6,7 @@
6
6
  </picture>
7
7
  </a>
8
8
 
9
- # Neex v0.1.5
9
+ # Neex v0.1.6
10
10
 
11
11
  ### 🚀 Neex: The Modern Build System for Polyrepo-in-Monorepo Architecture
12
12
 
@@ -25,7 +25,7 @@ Neex is a modern build system and script runner designed for **Polyrepo-in-Monor
25
25
  ## ✨ Key Features
26
26
 
27
27
  - 🎨 **Colored Output** - Distinguish commands with unique colors
28
- - ⚡ **Dual Execution Modes** - Run commands in parallel (`p`, `runx`) or sequence (`s`, `run`)
28
+ - ⚡ **Dual Execution Modes** - Run commands in parallel (`px`) or sequence (`s`, `run`)
29
29
  - ⏱️ **Smart Timing** - Track execution time for each command
30
30
  - 🛑 **Error Control** - Stop on first error (perfect for CI/CD)
31
31
  - 🔢 **Parallel Control** - Limit concurrent processes with `--max-parallel`
@@ -70,7 +70,7 @@ bun add -D neex # bun
70
70
 
71
71
  Neex provides several commands to manage and run your scripts:
72
72
 
73
- - **`runx <commands...>`** (alias: `px`, *default command*)
73
+ - **`px <commands...>`** (*default command*)
74
74
  - Runs specified commands in **parallel** by default.
75
75
  - Use the `-q` or `--sequential` flag to run them sequentially.
76
76
  - Ideal for build steps, tests, or any tasks that can run concurrently.
@@ -105,9 +105,9 @@ Neex provides several commands to manage and run your scripts:
105
105
  ### General Command Examples
106
106
 
107
107
  ```bash
108
- # Parallel execution (default behavior for runx)
109
- neex runx "npm run build:api" "npm run build:frontend" "npm run lint"
110
- # Alias for parallel
108
+ # Parallel execution (default behavior for px)
109
+ neex px "npm run build:api" "npm run build:frontend" "npm run lint"
110
+ # px is the command for parallel execution
111
111
  neex px "npm run test:unit" "npm run test:integration"
112
112
 
113
113
  # Sequential execution
@@ -115,8 +115,8 @@ neex run "npm run clean" "npm run build" "npm run deploy"
115
115
  # Alias for sequential
116
116
  neex s "echo First" "echo Second" "echo Third"
117
117
 
118
- # Run 'runx' commands sequentially using the -q flag
119
- neex runx -q "npm run step1" "npm run step2"
118
+ # Run 'px' commands sequentially using the -q flag
119
+ neex px -q "npm run step1" "npm run step2"
120
120
  ```
121
121
 
122
122
  ### `servers` Command Examples
@@ -167,9 +167,9 @@ neex restart my-app
167
167
  neex delete my-api
168
168
  ```
169
169
 
170
- ### 🛠️ Global Options (for `run`, `runx`, `servers`)
170
+ ### 🛠️ Global Options (for `run`, `px`, `servers`)
171
171
 
172
- These options can be used with `run`, `runx`, and `servers` commands:
172
+ These options can be used with `run`, `px`, and `servers` commands:
173
173
 
174
174
  | Flag | Alias | Description | Default |
175
175
  |--------------------------|-------|---------------------------------------------------|----------------|
@@ -180,7 +180,7 @@ These options can be used with `run`, `runx`, and `servers` commands:
180
180
  | `--no-output` | `-o` | Hide all `stdout` and `stderr` from commands | `true` (output on) |
181
181
  | `--minimal` | | Use minimal output format (less verbose) | `false` |
182
182
  | `--max-parallel <number>`| | Maximum number of commands to run in parallel | CPU count |
183
- | `--sequential` | `-q` | (For `runx`) Run commands sequentially instead of parallel | `false` |
183
+ | `--sequential` | `-q` | (For `px`) Run commands sequentially instead of parallel | `false` |
184
184
  | `--retry <count>` | | Number of times to retry a failed command | `0` |
185
185
  | `--retry-delay <ms>` | | Delay in milliseconds between retries | `1000` |
186
186
  | `--group-output` | `-g` | (For `servers`) Group output by server | `false` |
package/dist/src/cli.js CHANGED
@@ -34,7 +34,49 @@ const process_manager_js_1 = require("./process-manager.js");
34
34
  const chalk_1 = __importDefault(require("chalk"));
35
35
  const figures_1 = __importDefault(require("figures"));
36
36
  const path = __importStar(require("path"));
37
+ const fs = __importStar(require("fs/promises")); // Added for reading package.json
37
38
  const { version } = require('../../package.json');
39
+ // Helper function to find default command from package.json
40
+ async function findDefaultCommand() {
41
+ var _a, _b;
42
+ try {
43
+ const packageJsonPath = path.join(process.cwd(), 'package.json');
44
+ await fs.access(packageJsonPath);
45
+ const packageJsonContent = await fs.readFile(packageJsonPath, 'utf-8');
46
+ const packageJson = JSON.parse(packageJsonContent);
47
+ if ((_a = packageJson.scripts) === null || _a === void 0 ? void 0 : _a.dev) {
48
+ console.log(chalk_1.default.blue(`${figures_1.default.info} No command provided. Using "dev" script from package.json: npm run dev`));
49
+ return 'npm run dev';
50
+ }
51
+ if ((_b = packageJson.scripts) === null || _b === void 0 ? void 0 : _b.start) {
52
+ console.log(chalk_1.default.blue(`${figures_1.default.info} No command provided. Using "start" script from package.json: npm run start`));
53
+ return 'npm run start';
54
+ }
55
+ if (packageJson.main) {
56
+ const mainFile = packageJson.main;
57
+ const mainFilePath = path.resolve(process.cwd(), mainFile);
58
+ try {
59
+ await fs.access(mainFilePath);
60
+ if (mainFile.endsWith('.ts') || mainFile.endsWith('.mts') || mainFile.endsWith('.cts')) {
61
+ console.log(chalk_1.default.blue(`${figures_1.default.info} No command or script found. Using "main" field (TypeScript): npx ts-node ${mainFile}`));
62
+ return `npx ts-node ${mainFile}`;
63
+ }
64
+ else {
65
+ console.log(chalk_1.default.blue(`${figures_1.default.info} No command or script found. Using "main" field (JavaScript): node ${mainFile}`));
66
+ return `node ${mainFile}`;
67
+ }
68
+ }
69
+ catch (e) {
70
+ // Main file doesn't exist, do nothing, will fall through to return null
71
+ }
72
+ }
73
+ return null;
74
+ }
75
+ catch (error) {
76
+ // package.json doesn't exist or other error, do nothing
77
+ return null;
78
+ }
79
+ }
38
80
  function cli() {
39
81
  const program = new commander_1.Command();
40
82
  let cleanupRunner = null;
@@ -80,9 +122,8 @@ function cli() {
80
122
  });
81
123
  // runx command: parallel execution by default (with alias 'p'), can run sequentially with -q
82
124
  program
83
- .command('runx <commands...>', { isDefault: true })
84
- .alias('px')
85
- .description('Run commands in parallel (default) or sequentially with -q. Alias: px')
125
+ .command('px <commands...>', { isDefault: true })
126
+ .description('Run commands in parallel (default) or sequentially with -q. This is the default command.')
86
127
  .option('-c, --no-color', 'Disable colored output')
87
128
  .option('-t, --no-timing', 'Hide timing information')
88
129
  .option('-p, --no-prefix', 'Hide command prefix')
@@ -158,7 +199,7 @@ function cli() {
158
199
  });
159
200
  // Watch command (Nodemon functionality)
160
201
  program
161
- .command('watch <commands...>')
202
+ .command('watch [commands...]') // Made commands optional
162
203
  .alias('w')
163
204
  .description('Run commands with file watching (nodemon functionality)')
164
205
  .option('-c, --no-color', 'Disable colored output')
@@ -176,21 +217,66 @@ function cli() {
176
217
  .option('--signal <signal>', 'Signal to send to processes on restart', 'SIGTERM')
177
218
  .action(async (commands, options) => {
178
219
  try {
179
- console.log(chalk_1.default.blue(`${figures_1.default.info} Starting development server with file watching...`));
220
+ let effectiveCommands = commands;
221
+ if (!effectiveCommands || effectiveCommands.length === 0) {
222
+ const foundCommand = await findDefaultCommand();
223
+ if (foundCommand) {
224
+ effectiveCommands = [foundCommand];
225
+ console.log(chalk_1.default.blue(`${figures_1.default.info} No command specified for 'neex w', using default: "${foundCommand}"`));
226
+ }
227
+ else {
228
+ console.error(chalk_1.default.red(`${figures_1.default.cross} No command specified for 'neex w' and no default script (dev, start) or main file found in package.json.`));
229
+ console.error(chalk_1.default.yellow(`${figures_1.default.pointer} Please specify a command to run (e.g., neex w "npm run dev") or define a "dev" or "start" script in your package.json.`));
230
+ process.exit(1);
231
+ }
232
+ }
233
+ else { // At least one command/argument is provided
234
+ const firstArg = effectiveCommands[0];
235
+ const remainingArgs = effectiveCommands.slice(1);
236
+ const isLikelyCommandOrScript = firstArg.includes(' ') || firstArg.startsWith('npm') || firstArg.startsWith('yarn') || firstArg.startsWith('pnpm');
237
+ if (!isLikelyCommandOrScript) {
238
+ const filePath = path.resolve(process.cwd(), firstArg);
239
+ try {
240
+ await fs.access(filePath); // Check if file exists
241
+ let commandToExecute = '';
242
+ if (firstArg.endsWith('.js') || firstArg.endsWith('.mjs') || firstArg.endsWith('.cjs')) {
243
+ commandToExecute = `node ${firstArg}`;
244
+ console.log(chalk_1.default.blue(`${figures_1.default.info} Detected .js file, prepending with node.`));
245
+ }
246
+ else if (firstArg.endsWith('.ts') || firstArg.endsWith('.mts') || firstArg.endsWith('.cts')) {
247
+ commandToExecute = `npx ts-node ${firstArg}`;
248
+ console.log(chalk_1.default.blue(`${figures_1.default.info} Detected .ts file, prepending with npx ts-node.`));
249
+ }
250
+ if (commandToExecute) {
251
+ effectiveCommands = [commandToExecute, ...remainingArgs];
252
+ console.log(chalk_1.default.cyan(`${figures_1.default.pointer} Executing: ${effectiveCommands.join(' ')}`));
253
+ }
254
+ else {
255
+ // Not a .js or .ts file, or file doesn't exist but doesn't look like a command either.
256
+ // We'll let it try to run as is. If it was meant to be a file, it will likely fail.
257
+ // If it was a command like 'echo', it will run.
258
+ console.log(chalk_1.default.yellow(`${figures_1.default.warning} First argument "${firstArg}" is not a recognized .js/.ts file and doesn't look like a script. Attempting to run as is.`));
259
+ }
260
+ }
261
+ catch (e) {
262
+ // File doesn't exist. Could be a command like 'echo foo' where 'echo' is firstArg.
263
+ // Or could be 'my-script --arg' where 'my-script' is not found.
264
+ // We'll let it try to run as is. DevRunner will handle if the command is not found.
265
+ console.log(chalk_1.default.yellow(`${figures_1.default.warning} File "${firstArg}" not found. Attempting to run as command.`));
266
+ }
267
+ }
268
+ // If isLikelyCommandOrScript is true, or if the file auto-detection didn't apply,
269
+ // effectiveCommands remains as the user provided it (joined later by DevRunner).
270
+ }
271
+ console.log(chalk_1.default.blue(`${figures_1.default.info} Starting development server with file watching (neex w) for command(s): ${effectiveCommands.map(cmd => `"${cmd}"`).join(' && ')}...`));
180
272
  const watchPaths = options.watch || ['./'];
181
273
  const ignorePatterns = options.ignore || [
182
- 'node_modules/**',
183
- '.git/**',
184
- '*.log',
185
- 'dist/**',
186
- 'build/**',
187
- 'coverage/**',
188
- '.nyc_output/**',
189
- '*.tmp',
190
- '*.temp'
274
+ 'node_modules/**', '.git/**', '*.log', 'dist/**', 'build/**',
275
+ 'coverage/**', '.nyc_output/**', '*.tmp', '*.temp'
191
276
  ];
192
277
  const extensions = options.ext || ['js', 'mjs', 'json', 'ts', 'tsx', 'jsx'];
193
278
  devRunner = new dev_runner_js_1.DevRunner({
279
+ runnerName: 'neex w',
194
280
  parallel: false,
195
281
  color: options.color,
196
282
  showTiming: options.timing,
@@ -207,9 +293,9 @@ function cli() {
207
293
  signal: options.signal,
208
294
  restartOnChange: true,
209
295
  groupOutput: false,
210
- isServerMode: false // Added missing property
296
+ isServerMode: false
211
297
  });
212
- await devRunner.start(commands);
298
+ await devRunner.start(effectiveCommands);
213
299
  }
214
300
  catch (error) {
215
301
  if (error instanceof Error) {
@@ -44,6 +44,7 @@ class DevRunner {
44
44
  ext: ['js', 'mjs', 'json', 'ts', 'tsx', 'jsx'],
45
45
  delay: 1000,
46
46
  verbose: false,
47
+ runnerName: 'watch', // Default runner name if not specified
47
48
  };
48
49
  this.options = {
49
50
  ...defaultOptions,
@@ -66,7 +67,8 @@ class DevRunner {
66
67
  });
67
68
  }
68
69
  async handleFileChange(event) {
69
- logger_1.default.printLine(`File changed: ${chalk_1.default.yellow(event.relativePath)}`, 'info');
70
+ const prefix = chalk_1.default.cyan(`[${this.options.runnerName}]`);
71
+ logger_1.default.printLine(`${prefix} File changed: ${chalk_1.default.yellow(event.relativePath)}`, 'info');
70
72
  if (this.options.clearConsole) {
71
73
  console.clear();
72
74
  }
@@ -87,17 +89,18 @@ class DevRunner {
87
89
  }
88
90
  }
89
91
  printDevBanner() {
90
- var _a;
92
+ var _a, _b;
93
+ const prefix = chalk_1.default.cyan(`[${this.options.runnerName}]`);
91
94
  const uptime = Math.floor((Date.now() - this.startTime.getTime()) / 1000);
92
95
  const uptimeStr = this.formatUptime(uptime);
93
- console.log('\n' + chalk_1.default.bgGreen.black(' DEV MODE ') + '\n');
96
+ console.log('\n' + chalk_1.default.bgGreen.black(` ${(_a = this.options.runnerName) === null || _a === void 0 ? void 0 : _a.toUpperCase()} MODE `) + '\n');
94
97
  if (this.restartCount > 0) {
95
- console.log(chalk_1.default.green(`${figures_1.default.arrowUp} Restarted ${this.restartCount} times`));
98
+ console.log(`${prefix} ${chalk_1.default.green(`${figures_1.default.arrowUp} Restarted ${this.restartCount} times`)}`);
96
99
  }
97
- console.log(chalk_1.default.blue(`${figures_1.default.info} Uptime: ${uptimeStr}`));
98
- console.log(chalk_1.default.blue(`${figures_1.default.info} Watching: ${((_a = this.options.watch) === null || _a === void 0 ? void 0 : _a.join(', ')) || 'current directory'}`));
100
+ console.log(`${prefix} ${chalk_1.default.blue(`${figures_1.default.info} Uptime: ${uptimeStr}`)}`);
101
+ console.log(`${prefix} ${chalk_1.default.blue(`${figures_1.default.info} Watching: ${((_b = this.options.watch) === null || _b === void 0 ? void 0 : _b.join(', ')) || 'current directory'}`)}`);
99
102
  if (this.options.ext && this.options.ext.length > 0) {
100
- console.log(chalk_1.default.blue(`${figures_1.default.info} Extensions: ${this.options.ext.join(', ')}`));
103
+ console.log(`${prefix} ${chalk_1.default.blue(`${figures_1.default.info} Extensions: ${this.options.ext.join(', ')}`)}`);
101
104
  }
102
105
  console.log('');
103
106
  }
@@ -129,18 +132,20 @@ class DevRunner {
129
132
  await this.fileWatcher.start();
130
133
  }
131
134
  // Run initial commands
132
- logger_1.default.printLine('Starting development server...', 'info');
135
+ const prefix = chalk_1.default.cyan(`[${this.options.runnerName}]`);
136
+ logger_1.default.printLine(`${prefix} Starting development server...`, 'info');
133
137
  await this.runCommands();
134
138
  // Set up graceful shutdown
135
139
  this.setupGracefulShutdown();
136
- logger_1.default.printLine('Development server started. Watching for changes...', 'info');
137
- logger_1.default.printLine(`Press ${chalk_1.default.cyan('Ctrl+C')} to stop`, 'info');
140
+ logger_1.default.printLine(`${prefix} Development server started. Watching for changes...`, 'info');
141
+ logger_1.default.printLine(`${prefix} Press ${chalk_1.default.cyan('Ctrl+C')} to stop`, 'info');
138
142
  }
139
143
  async restart() {
144
+ const prefix = chalk_1.default.cyan(`[${this.options.runnerName}]`);
140
145
  if (!this.isRunning) {
141
146
  return;
142
147
  }
143
- logger_1.default.printLine('Restarting due to file changes...', 'info');
148
+ logger_1.default.printLine(`${prefix} Restarting due to file changes...`, 'info');
144
149
  this.restartCount++;
145
150
  // Stop current processes
146
151
  if (this.runner) {
@@ -152,13 +157,14 @@ class DevRunner {
152
157
  this.printDevBanner();
153
158
  // Run commands again
154
159
  await this.runCommands();
155
- logger_1.default.printLine('Restart completed. Watching for changes...', 'info');
160
+ logger_1.default.printLine(`${prefix} Restart completed. Watching for changes...`, 'info');
156
161
  }
157
162
  async stop() {
163
+ const prefix = chalk_1.default.cyan(`[${this.options.runnerName}]`);
158
164
  if (!this.isRunning) {
159
165
  return;
160
166
  }
161
- logger_1.default.printLine('Stopping development server...', 'info');
167
+ logger_1.default.printLine(`${prefix} Stopping development server...`, 'info');
162
168
  this.isRunning = false;
163
169
  // Stop file watcher
164
170
  if (this.fileWatcher) {
@@ -170,9 +176,9 @@ class DevRunner {
170
176
  }
171
177
  const uptime = Math.floor((Date.now() - this.startTime.getTime()) / 1000);
172
178
  const uptimeStr = this.formatUptime(uptime);
173
- logger_1.default.printLine(`Development server stopped after ${uptimeStr}`, 'info');
179
+ logger_1.default.printLine(`${prefix} ${this.options.runnerName} development server stopped after ${uptimeStr}`, 'info');
174
180
  if (this.restartCount > 0) {
175
- logger_1.default.printLine(`Total restarts: ${this.restartCount}`, 'info');
181
+ logger_1.default.printLine(`${prefix} Total restarts: ${this.restartCount}`, 'info');
176
182
  }
177
183
  }
178
184
  setupGracefulShutdown() {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "neex",
3
- "version": "0.1.5",
3
+ "version": "0.1.6",
4
4
  "description": "The Modern Build System for Polyrepo-in-Monorepo Architecture",
5
5
  "main": "dist/src/index.js",
6
6
  "types": "dist/src/index.d.ts",
@@ -12,7 +12,9 @@
12
12
  "start": "node dist/bin/neex.js",
13
13
  "prepublishOnly": "npm run build",
14
14
  "test": "jest",
15
- "test:dev": "node ./dist/bin/neex.js runx \"echo Starting frontend\" \"echo Starting backend\"",
15
+ "dev": "neex w \"ts-node src/server.ts\"",
16
+ "w": "neex w \"ts-node src/server.ts\"",
17
+ "test:dev": "node ./dist/bin/neex.js px \"echo Starting frontend\" \"echo Starting backend\"",
16
18
  "test:parallel": "node ./dist/src/cli.js parallel \"echo Building frontend\" \"echo Building backend\"",
17
19
  "test:sequence": "node ./dist/src/cli.js run \"echo Step 1\" \"echo Step 2\" \"echo Step 3\""
18
20
  },