gib-runs 2.2.0 → 2.3.2

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/CHANGELOG.md CHANGED
@@ -2,6 +2,43 @@
2
2
 
3
3
  All notable changes to this project will be documented in this file.
4
4
 
5
+ ## [2.3.0] - 2026-02-10
6
+
7
+ ### Fixed - Critical
8
+ - 🔧 **NPM Script Mode** - Fixed major issues with `--npm-script` and `--exec` options
9
+ - No longer creates duplicate HTTP server on port 8080
10
+ - Browser no longer opens to wrong port (8080 instead of dev server port)
11
+ - Static file serving disabled when npm script is running (prevents MIME type conflicts)
12
+ - Fixed "Cannot GET /" and blank page issues with Vite/React/Vue projects
13
+ - GIB-RUNS now acts as pure file watcher for live reload when npm script is active
14
+ - 🚫 **Browser Auto-Open** - Disabled automatic browser opening when using `--npm-script` or `--exec`
15
+ - Prevents confusion with wrong port
16
+ - Let the dev server (Vite, Next.js, etc) handle browser opening
17
+ - 🎯 **File Watcher** - Improved file watching with better ignore patterns
18
+ - Ignores Vite temporary files (`.timestamp-*.mjs`)
19
+ - Ignores common build artifacts (`.log`, `.lock`, `.tmp`)
20
+ - Cleaner console output without spam
21
+
22
+ ### Improved
23
+ - 📝 **Cleaner Logs** - Removed verbose output from process runner
24
+ - No more `[npm]` or `[cmd]` prefixes cluttering output
25
+ - Direct passthrough of npm script output
26
+ - Only show errors when process exits with non-zero code
27
+ - 🎨 **Better UI** - Simplified status display
28
+ - Removed norak "(Access from other devices)" text
29
+ - Network URLs displayed directly without extra labels
30
+ - Cleaner, more professional output
31
+ - ⚡ **Performance** - Optimized server startup
32
+ - Minimal HTTP server for WebSocket when npm script is running
33
+ - Reduced memory footprint in npm script mode
34
+ - Faster startup time
35
+
36
+ ### Technical
37
+ - Fixed JSHint warning about closure in loop (rate-limit middleware)
38
+ - All 32 tests still passing
39
+ - Zero ESLint/JSHint warnings
40
+ - Backward compatible with all existing features
41
+
5
42
  ## [2.2.0] - 2026-02-08
6
43
 
7
44
  ### Added
@@ -71,12 +108,6 @@ All notable changes to this project will be documented in this file.
71
108
  - 🚦 Rate limiting middleware (`--rate-limit=N`) - protect against abuse
72
109
  - 📱 QR code option (`--qr`, `--qrcode`) for mobile access
73
110
  - 🌍 **Public Tunnels** - Share dev server with anyone, anywhere
74
- - LocalTunnel (default, no signup needed)
75
- - Cloudflare Tunnel support
76
- - Ngrok support
77
- - Pinggy support
78
- - Localtonet support
79
- - Tunnelto support
80
111
  - 🚀 **NPM Scripts Integration** - Run npm dev, start, or any script alongside server
81
112
  - ⚙️ **Custom Command Execution** - Execute any command with live reload
82
113
  - 🔄 **PM2 Integration** - Production-ready process management
@@ -113,7 +144,7 @@ All notable changes to this project will be documented in this file.
113
144
  - More informative console output with helpful tips
114
145
  - Enhanced developer experience
115
146
  - Improved documentation
116
- - Network URLs prominently displayed with "Access from other devices" label
147
+ - Network URLs prominently displayed
117
148
 
118
149
  ### Technical
119
150
  - Upgraded chokidar to v3.5.3
package/README.md CHANGED
@@ -372,14 +372,14 @@ gib-runs
372
372
  Network URLs are **ALWAYS shown automatically** when you start the server:
373
373
 
374
374
  ```
375
- 🚀 GIB-RUNS v2.2.0
375
+ 🚀 GIB-RUNS v2.3.2
376
376
  "Unlike Gibran, this actually works through merit"
377
377
  ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
378
378
  📁 Root: /home/user/project
379
- 🌐 Local: http://127.0.0.1:8080
380
- 🔗 Network: (Access from other devices)
381
- http://192.168.1.100:8080
382
- http://10.0.0.5:8080
379
+ 🌐 Local: 🔗 Network: http://127.0.0.1:8080
380
+ 🔗 Network:
381
+ 🔗 Network: http://192.168.1.100:8080
382
+ 🔗 Network: http://10.0.0.5:8080
383
383
  🔄 Live Reload: Enabled (no dynasty needed)
384
384
  📦 Compression: Enabled (earned, not inherited)
385
385
  ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
@@ -491,13 +491,13 @@ gib-runs --tunnel-service=tunnelto
491
491
  ### Example Output
492
492
 
493
493
  ```
494
- 🚀 GIB-RUNS v2.2.0
494
+ 🚀 GIB-RUNS v2.3.2
495
495
  "Unlike Gibran, this actually works through merit"
496
496
  ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
497
497
  📁 Root: /home/user/project
498
- 🌐 Local: http://127.0.0.1:8080
499
- 🔗 Network: (Access from other devices)
500
- http://192.168.1.100:8080
498
+ 🌐 Local: 🔗 Network: http://127.0.0.1:8080
499
+ 🔗 Network:
500
+ 🔗 Network: http://192.168.1.100:8080
501
501
  🔄 Live Reload: Enabled (no dynasty needed)
502
502
  ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
503
503
 
@@ -541,12 +541,21 @@ The password is automatically fetched and displayed when you start the tunnel. I
541
541
 
542
542
  ## 🚀 NPM Scripts & Process Management
543
543
 
544
- **Run your development scripts alongside the live server - unlike some VPs, these processes actually work!**
544
+ **Run your development scripts with live reload - GIB-RUNS acts as a smart file watcher!**
545
+
546
+ ### How It Works
547
+
548
+ When you use `--npm-script` or `--exec`, GIB-RUNS:
549
+ - ✅ **Does NOT create HTTP server** on port 8080
550
+ - ✅ **Does NOT open browser** automatically
551
+ - ✅ **Only watches files** for live reload
552
+ - ✅ **Lets your dev server** (Vite, Next.js, etc) handle everything
553
+ - ✅ **No port conflicts** - clean and simple
545
554
 
546
555
  ### Run NPM Scripts
547
556
 
548
557
  ```bash
549
- # Run npm dev script
558
+ # Run npm dev script (Vite, Next.js, etc)
550
559
  gib-runs --npm-script=dev
551
560
 
552
561
  # Run npm start script
@@ -556,6 +565,13 @@ gib-runs --npm-script=start
556
565
  gib-runs --npm-script=build
557
566
  ```
558
567
 
568
+ **What happens:**
569
+ - Your npm script runs normally (e.g., Vite on port 3000)
570
+ - GIB-RUNS watches files for changes
571
+ - Live reload works via WebSocket
572
+ - No duplicate servers, no conflicts
573
+ - Clean output directly from your dev server
574
+
559
575
  ### Run Custom Commands
560
576
 
561
577
  ```bash
@@ -605,13 +621,13 @@ pm2 list
605
621
  ### Example Output
606
622
 
607
623
  ```
608
- 🚀 GIB-RUNS v2.2.0
624
+ 🚀 GIB-RUNS v2.3.2
609
625
  "Unlike Gibran, this actually works through merit"
610
626
  ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
611
627
  📁 Root: /home/user/project
612
- 🌐 Local: http://127.0.0.1:8080
613
- 🔗 Network: (Access from other devices)
614
- http://192.168.1.100:8080
628
+ 🌐 Local: 🔗 Network: http://127.0.0.1:8080
629
+ 🔗 Network:
630
+ 🔗 Network: http://192.168.1.100:8080
615
631
  🔄 Live Reload: Enabled (no dynasty needed)
616
632
  📦 Compression: Enabled (earned, not inherited)
617
633
  📦 NPM Script: dev
package/gib-run.js CHANGED
@@ -182,9 +182,11 @@ for (var i = process.argv.length - 1; i >= 2; --i) {
182
182
  }
183
183
  else if (arg.indexOf("--rate-limit=") > -1) {
184
184
  var limit = parseInt(arg.substring(13), 10);
185
- opts.middleware.push(function() {
186
- return require('./middleware/rate-limit')({ max: limit });
187
- });
185
+ opts.middleware.push((function(maxLimit) {
186
+ return function() {
187
+ return require('./middleware/rate-limit')({ max: maxLimit });
188
+ };
189
+ })(limit));
188
190
  process.argv.splice(i, 1);
189
191
  }
190
192
  else if (arg.indexOf("--https=") > -1) {
package/index.js CHANGED
@@ -146,9 +146,16 @@ GibRuns.start = function(options) {
146
146
  var mount = options.mount || [];
147
147
  var watchPaths = options.watch || [root];
148
148
  GibRuns.logLevel = options.logLevel === undefined ? 2 : options.logLevel;
149
+
150
+ // Disable browser opening if npm script or exec command is used
149
151
  var openPath = (options.open === undefined || options.open === true) ?
150
152
  "" : ((options.open === null || options.open === false) ? null : options.open);
151
153
  if (options.noBrowser) openPath = null; // Backwards compatibility with 0.7.0
154
+
155
+ // Force disable browser if npm script or exec is running
156
+ if (options.npmScript || options.exec) {
157
+ openPath = null;
158
+ }
152
159
  var file = options.file;
153
160
  var staticServerHandler = staticServer(root);
154
161
  var wait = options.wait === undefined ? 100 : options.wait;
@@ -186,106 +193,124 @@ GibRuns.start = function(options) {
186
193
  // Setup a web server
187
194
  var app = connect();
188
195
 
196
+ // If npm script is running, don't serve static files (let the npm script handle it)
197
+ var serveStatic = !npmScript && !execCommand;
198
+
189
199
  // Enable compression for better performance
190
- if (enableCompression) {
200
+ if (enableCompression && serveStatic) {
191
201
  app.use(compression());
192
202
  }
193
203
 
194
204
  // Request counter middleware
195
- app.use(function(req, res, next) {
196
- GibRuns.requestCount++;
197
-
198
- // Log requests in verbose mode
199
- if (GibRuns.logLevel >= 3) {
200
- var timestamp = new Date().toLocaleTimeString();
201
- console.log(chalk.gray(' [' + timestamp + '] ') +
202
- chalk.cyan(req.method) + ' ' +
203
- chalk.white(req.url) + ' ' +
204
- chalk.gray('from ' + (req.headers['x-forwarded-for'] || req.connection.remoteAddress)));
205
- }
206
-
207
- next();
208
- });
205
+ if (serveStatic) {
206
+ app.use(function(req, res, next) {
207
+ GibRuns.requestCount++;
208
+
209
+ // Log requests in verbose mode
210
+ if (GibRuns.logLevel >= 3) {
211
+ var timestamp = new Date().toLocaleTimeString();
212
+ console.log(chalk.gray(' [' + timestamp + '] ') +
213
+ chalk.cyan(req.method) + ' ' +
214
+ chalk.white(req.url) + ' ' +
215
+ chalk.gray('from ' + (req.headers['x-forwarded-for'] || req.connection.remoteAddress)));
216
+ }
217
+
218
+ next();
219
+ });
209
220
 
210
- // Add logger. Level 2 logs only errors
211
- if (GibRuns.logLevel === 2) {
212
- app.use(logger('dev', {
213
- skip: function (req, res) { return res.statusCode < 400; }
214
- }));
215
- // Level 2 or above logs all requests
216
- } else if (GibRuns.logLevel > 2) {
217
- app.use(logger('dev'));
221
+ // Add logger. Level 2 logs only errors
222
+ if (GibRuns.logLevel === 2) {
223
+ app.use(logger('dev', {
224
+ skip: function (req, res) { return res.statusCode < 400; }
225
+ }));
226
+ // Level 2 or above logs all requests
227
+ } else if (GibRuns.logLevel > 2) {
228
+ app.use(logger('dev'));
229
+ }
218
230
  }
219
- if (options.spa) {
231
+
232
+ if (options.spa && serveStatic) {
220
233
  middleware.push("spa");
221
234
  }
222
- // Add middleware
223
- middleware.map(function(mw) {
224
- if (typeof mw === "string") {
225
- var ext = path.extname(mw).toLocaleLowerCase();
226
- if (ext !== ".js") {
227
- mw = require(path.join(__dirname, "middleware", mw + ".js"));
228
- } else {
229
- mw = require(mw);
235
+
236
+ // Add middleware only if serving static
237
+ if (serveStatic) {
238
+ middleware.map(function(mw) {
239
+ if (typeof mw === "string") {
240
+ var ext = path.extname(mw).toLocaleLowerCase();
241
+ if (ext !== ".js") {
242
+ mw = require(path.join(__dirname, "middleware", mw + ".js"));
243
+ } else {
244
+ mw = require(mw);
245
+ }
246
+ }
247
+ app.use(mw);
248
+
249
+ // Log middleware loading in verbose mode
250
+ if (GibRuns.logLevel >= 3) {
251
+ console.log(chalk.gray(' ✓ Loaded middleware: ') + chalk.cyan(typeof mw === 'function' ? mw.name || 'anonymous' : mw));
230
252
  }
253
+ });
254
+
255
+ // Use http-auth if configured
256
+ if (htpasswd !== null) {
257
+ var auth = require('http-auth');
258
+ var basic = auth.basic({
259
+ realm: "Please authorize",
260
+ file: htpasswd
261
+ });
262
+ // Create middleware wrapper for http-auth v4
263
+ app.use(function(req, res, next) {
264
+ var authHandler = basic.check(function() {
265
+ next();
266
+ });
267
+ authHandler(req, res);
268
+ });
231
269
  }
232
- app.use(mw);
233
-
234
- // Log middleware loading in verbose mode
235
- if (GibRuns.logLevel >= 3) {
236
- console.log(chalk.gray(' ✓ Loaded middleware: ') + chalk.cyan(typeof mw === 'function' ? mw.name || 'anonymous' : mw));
270
+ if (cors) {
271
+ app.use(require("cors")({
272
+ origin: true, // reflecting request origin
273
+ credentials: true // allowing requests with credentials
274
+ }));
237
275
  }
238
- });
239
-
240
- // Use http-auth if configured
241
- if (htpasswd !== null) {
242
- var auth = require('http-auth');
243
- var basic = auth.basic({
244
- realm: "Please authorize",
245
- file: htpasswd
276
+ mount.forEach(function(mountRule) {
277
+ var mountPath = path.resolve(process.cwd(), mountRule[1]);
278
+ if (!options.watch) // Auto add mount paths to wathing but only if exclusive path option is not given
279
+ watchPaths.push(mountPath);
280
+ app.use(mountRule[0], staticServer(mountPath));
281
+ if (GibRuns.logLevel >= 1)
282
+ console.log(chalk.cyan(' 📂 Mapping ') + chalk.yellow(mountRule[0]) + chalk.gray(' to ') + chalk.white('"' + mountPath + '"'));
246
283
  });
247
- // Create middleware wrapper for http-auth v4
248
- app.use(function(req, res, next) {
249
- var authHandler = basic.check(function() {
250
- next();
251
- });
252
- authHandler(req, res);
284
+ proxy.forEach(function(proxyRule) {
285
+ var proxyUrl = new URL(proxyRule[1]);
286
+ var proxyOpts = {
287
+ protocol: proxyUrl.protocol,
288
+ host: proxyUrl.hostname,
289
+ port: proxyUrl.port,
290
+ pathname: proxyUrl.pathname,
291
+ via: true,
292
+ preserveHost: true
293
+ };
294
+ app.use(proxyRule[0], require('proxy-middleware')(proxyOpts));
295
+ if (GibRuns.logLevel >= 1)
296
+ console.log(chalk.cyan(' 🔀 Proxying ') + chalk.yellow(proxyRule[0]) + chalk.gray(' to ') + chalk.white('"' + proxyRule[1] + '"'));
253
297
  });
298
+ app.use(staticServerHandler) // Custom static server
299
+ .use(entryPoint(staticServerHandler, file))
300
+ .use(serveIndex(root, { icons: true }));
254
301
  }
255
- if (cors) {
256
- app.use(require("cors")({
257
- origin: true, // reflecting request origin
258
- credentials: true // allowing requests with credentials
259
- }));
260
- }
261
- mount.forEach(function(mountRule) {
262
- var mountPath = path.resolve(process.cwd(), mountRule[1]);
263
- if (!options.watch) // Auto add mount paths to wathing but only if exclusive path option is not given
264
- watchPaths.push(mountPath);
265
- app.use(mountRule[0], staticServer(mountPath));
266
- if (GibRuns.logLevel >= 1)
267
- console.log(chalk.cyan(' 📂 Mapping ') + chalk.yellow(mountRule[0]) + chalk.gray(' to ') + chalk.white('"' + mountPath + '"'));
268
- });
269
- proxy.forEach(function(proxyRule) {
270
- var proxyUrl = new URL(proxyRule[1]);
271
- var proxyOpts = {
272
- protocol: proxyUrl.protocol,
273
- host: proxyUrl.hostname,
274
- port: proxyUrl.port,
275
- pathname: proxyUrl.pathname,
276
- via: true,
277
- preserveHost: true
278
- };
279
- app.use(proxyRule[0], require('proxy-middleware')(proxyOpts));
280
- if (GibRuns.logLevel >= 1)
281
- console.log(chalk.cyan(' 🔀 Proxying ') + chalk.yellow(proxyRule[0]) + chalk.gray(' to ') + chalk.white('"' + proxyRule[1] + '"'));
282
- });
283
- app.use(staticServerHandler) // Custom static server
284
- .use(entryPoint(staticServerHandler, file))
285
- .use(serveIndex(root, { icons: true }));
286
302
 
287
303
  var server, protocol;
288
- if (https !== null) {
304
+
305
+ // If npm script or exec command is running, skip HTTP server entirely
306
+ if (npmScript || execCommand) {
307
+ // Create a minimal server just for WebSocket
308
+ server = http.createServer(function(req, res) {
309
+ res.writeHead(200);
310
+ res.end('GIB-RUNS Live Reload Server');
311
+ });
312
+ protocol = "http";
313
+ } else if (https !== null) {
289
314
  var httpsConfig = https;
290
315
  if (typeof https === "string") {
291
316
  httpsConfig = require(path.resolve(process.cwd(), https));
@@ -322,6 +347,67 @@ GibRuns.start = function(options) {
322
347
  GibRuns.server = server;
323
348
 
324
349
  var address = server.address();
350
+
351
+ // If npm script is running, don't show server info
352
+ if (npmScript || execCommand) {
353
+ // Show info about what's running
354
+ if (GibRuns.logLevel >= 1) {
355
+ console.log('\n' + chalk.cyan.bold('━'.repeat(60)));
356
+ console.log(chalk.cyan.bold(' 🚀 GIB-RUNS') + chalk.gray(' v2.3.2'));
357
+ console.log(chalk.gray(' "Unlike Gibran, this actually works through merit"'));
358
+ console.log(chalk.cyan.bold('━'.repeat(60)));
359
+ console.log(chalk.white(' 📁 Root: ') + chalk.yellow(root));
360
+ if (npmScript) {
361
+ console.log(chalk.white(' 📦 NPM Script: ') + chalk.yellow(npmScript));
362
+ }
363
+ if (execCommand) {
364
+ console.log(chalk.white(' ⚙️ Command: ') + chalk.yellow(execCommand));
365
+ }
366
+ if (usePM2) {
367
+ console.log(chalk.white(' 🔄 PM2: ') + chalk.green(' Enabled') + chalk.gray(' (process manager)'));
368
+ }
369
+ console.log(chalk.white(' 🔄 Live Reload:') + chalk.green(' Enabled') + chalk.gray(' (watching for changes)'));
370
+ console.log(chalk.cyan.bold('━'.repeat(60)));
371
+ console.log(chalk.gray(' Press Ctrl+C to stop\n'));
372
+ }
373
+
374
+ // Run the npm script or command
375
+ setTimeout(function() {
376
+ var processRunner = require('./lib/process-runner');
377
+ GibRuns.processRunner = processRunner;
378
+
379
+ if (usePM2 && npmScript) {
380
+ processRunner.runWithPM2('npm run ' + npmScript, {
381
+ cwd: root,
382
+ name: pm2Name
383
+ });
384
+ } else if (usePM2 && execCommand) {
385
+ processRunner.runWithPM2(execCommand, {
386
+ cwd: root,
387
+ name: pm2Name
388
+ });
389
+ } else if (npmScript) {
390
+ processRunner.runNpmScript(npmScript, { cwd: root });
391
+ } else if (execCommand) {
392
+ processRunner.runCommand(execCommand, { cwd: root });
393
+ }
394
+
395
+ // Start tunnel if requested (for npm/exec mode)
396
+ if (enableTunnel) {
397
+ var tunnel = require('./lib/tunnel');
398
+ GibRuns.tunnel = tunnel;
399
+ setTimeout(function() {
400
+ // For npm/exec mode, we need to detect the port from the process output
401
+ // For now, use a default port or let user specify via --port
402
+ var tunnelPort = port || 8080;
403
+ tunnel.startTunnel(tunnelPort, tunnelService, tunnelOptions);
404
+ }, 2000);
405
+ }
406
+ }, 500);
407
+
408
+ return;
409
+ }
410
+
325
411
  var serveHost = address.address === "0.0.0.0" ? "127.0.0.1" : address.address;
326
412
  var openHost = host === "0.0.0.0" ? "127.0.0.1" : host;
327
413
 
@@ -356,18 +442,17 @@ GibRuns.start = function(options) {
356
442
 
357
443
  // Output with beautiful formatting
358
444
  if (GibRuns.logLevel >= 1) {
359
- console.log('\\n' + chalk.cyan.bold('━'.repeat(60)));
360
- console.log(chalk.cyan.bold(' 🚀 GIB-RUNS') + chalk.gray(' v2.2.0'));
445
+ console.log('\n' + chalk.cyan.bold('━'.repeat(60)));
446
+ console.log(chalk.cyan.bold(' 🚀 GIB-RUNS') + chalk.gray(' v2.3.2'));
361
447
  console.log(chalk.gray(' "Unlike Gibran, this actually works through merit"'));
362
448
  console.log(chalk.cyan.bold('━'.repeat(60)));
363
449
  console.log(chalk.white(' 📁 Root: ') + chalk.yellow(root));
364
450
  console.log(chalk.white(' 🌐 Local: ') + chalk.green(serveURL));
365
451
 
366
- // Always show network URLs when available
452
+ // Show network URLs when available
367
453
  if (networkURLs.length > 0) {
368
- console.log(chalk.white(' 🔗 Network: ') + chalk.magenta('(Access from other devices)'));
369
454
  networkURLs.forEach(function(urlItem) {
370
- console.log(chalk.white(' ') + chalk.green(urlItem));
455
+ console.log(chalk.white(' 🔗 Network: ') + chalk.green(urlItem));
371
456
  });
372
457
  }
373
458
 
@@ -381,24 +466,15 @@ GibRuns.start = function(options) {
381
466
  if (https) {
382
467
  console.log(chalk.white(' 🔒 HTTPS: ') + chalk.green(' Enabled') + chalk.gray(' (real security)'));
383
468
  }
384
- if (execCommand) {
385
- console.log(chalk.white(' ⚙️ Command: ') + chalk.yellow(execCommand));
386
- }
387
- if (npmScript) {
388
- console.log(chalk.white(' 📦 NPM Script: ') + chalk.yellow(npmScript));
389
- }
390
- if (usePM2) {
391
- console.log(chalk.white(' 🔄 PM2: ') + chalk.green(' Enabled') + chalk.gray(' (process manager)'));
392
- }
393
469
  console.log(chalk.cyan.bold('━'.repeat(60)));
394
470
  console.log(chalk.gray(' Press Ctrl+C to stop'));
395
- console.log(chalk.yellow(' 💡 Tip: Share network URLs with your team!\\n'));
471
+ console.log(chalk.yellow(' 💡 Tip: Share network URLs with your team!\n'));
396
472
  }
397
473
 
398
474
  // Show QR code for easy mobile access
399
475
  if (showQR && networkURLs.length > 0) {
400
476
  console.log(chalk.cyan(' 📱 Scan QR code to open on mobile:'));
401
- console.log(chalk.gray(' (Install qrcode-terminal: npm i -g qrcode-terminal)\\n'));
477
+ console.log(chalk.gray(' (Install qrcode-terminal: npm i -g qrcode-terminal)\n'));
402
478
  }
403
479
 
404
480
  // Start tunnel if requested
@@ -409,30 +485,6 @@ GibRuns.start = function(options) {
409
485
  tunnel.startTunnel(address.port, tunnelService, tunnelOptions);
410
486
  }, 1000);
411
487
  }
412
-
413
- // Run npm script or command if specified
414
- if (npmScript || execCommand || usePM2) {
415
- var processRunner = require('./lib/process-runner');
416
- GibRuns.processRunner = processRunner;
417
-
418
- setTimeout(function() {
419
- if (usePM2 && npmScript) {
420
- processRunner.runWithPM2('npm run ' + npmScript, {
421
- cwd: root,
422
- name: pm2Name
423
- });
424
- } else if (usePM2 && execCommand) {
425
- processRunner.runWithPM2(execCommand, {
426
- cwd: root,
427
- name: pm2Name
428
- });
429
- } else if (npmScript) {
430
- processRunner.runNpmScript(npmScript, { cwd: root });
431
- } else if (execCommand) {
432
- processRunner.runCommand(execCommand, { cwd: root });
433
- }
434
- }, 500);
435
- }
436
488
 
437
489
  // Launch browser
438
490
  if (openPath !== null)
@@ -450,8 +502,16 @@ GibRuns.start = function(options) {
450
502
  }
451
503
  });
452
504
 
453
- // Setup server to listen at port
454
- server.listen(port, host);
505
+ // Setup server to listen at port (skip if npm script is running)
506
+ if (serveStatic) {
507
+ server.listen(port, host);
508
+ } else {
509
+ // For npm script mode, just setup websocket server without HTTP
510
+ GibRuns.server = server;
511
+
512
+ // Start listening on a random port for WebSocket only
513
+ server.listen(0, '127.0.0.1');
514
+ }
455
515
 
456
516
  // WebSocket
457
517
  var clients = [];
@@ -485,6 +545,12 @@ GibRuns.start = function(options) {
485
545
  var ignored = [
486
546
  function(testPath) { // Always ignore dotfiles (important e.g. because editor hidden temp files)
487
547
  return testPath !== "." && /(^[.#]|(?:__|~)$)/.test(path.basename(testPath));
548
+ },
549
+ function(testPath) { // Ignore vite temp files
550
+ return /\.timestamp-.*\.mjs$/.test(testPath);
551
+ },
552
+ function(testPath) { // Ignore common build artifacts
553
+ return /\.(log|lock|tmp)$/.test(testPath);
488
554
  }
489
555
  ];
490
556
  if (options.ignore) {
@@ -524,7 +590,7 @@ GibRuns.start = function(options) {
524
590
  .on("unlinkDir", handleChange)
525
591
  .on("ready", function () {
526
592
  if (GibRuns.logLevel >= 1)
527
- console.log(chalk.cyan(" ✓ Watching for file changes...\\n"));
593
+ console.log(chalk.cyan(" ✓ Watching for file changes...\n"));
528
594
  })
529
595
  .on("error", function (err) {
530
596
  console.log(chalk.red(" ✖ Watcher Error: ") + err);
@@ -536,13 +602,13 @@ GibRuns.start = function(options) {
536
602
  GibRuns.shutdown = function() {
537
603
  if (GibRuns.logLevel >= 1 && GibRuns.startTime) {
538
604
  var uptime = ((Date.now() - GibRuns.startTime) / 1000).toFixed(2);
539
- console.log('\\n' + chalk.cyan.bold('━'.repeat(60)));
605
+ console.log('\n' + chalk.cyan.bold('━'.repeat(60)));
540
606
  console.log(chalk.yellow(' 👋 Shutting down GIB-RUNS...'));
541
607
  console.log(chalk.gray(' 📊 Statistics:'));
542
608
  console.log(chalk.gray(' • Uptime: ') + chalk.white(uptime + 's'));
543
609
  console.log(chalk.gray(' • Requests: ') + chalk.white(GibRuns.requestCount));
544
610
  console.log(chalk.gray(' • Reloads: ') + chalk.white(GibRuns.reloadCount));
545
- console.log(chalk.cyan.bold('━'.repeat(60)) + '\\n');
611
+ console.log(chalk.cyan.bold('━'.repeat(60)) + '\n');
546
612
  }
547
613
 
548
614
  // Stop process runner if active
@@ -16,10 +16,6 @@ function runNpmScript(script, options) {
16
16
  options = options || {};
17
17
  var cwd = options.cwd || process.cwd();
18
18
 
19
- console.log(chalk.cyan.bold(' 🚀 Running npm script: ') + chalk.yellow(script));
20
- console.log(chalk.gray(' Working directory: ') + chalk.white(cwd));
21
- console.log(chalk.gray(' (Earned through merit, not inheritance)\n'));
22
-
23
19
  // Check if package.json exists
24
20
  var packagePath = path.join(cwd, 'package.json');
25
21
  if (!fs.existsSync(packagePath)) {
@@ -40,7 +36,6 @@ function runNpmScript(script, options) {
40
36
  }
41
37
  return null;
42
38
  }
43
- console.log(chalk.green(' ✓ Found script: ') + chalk.gray(pkg.scripts[script]));
44
39
  } catch (e) {
45
40
  console.error(chalk.red(' ✖ Error reading package.json: ') + e.message);
46
41
  return null;
@@ -56,31 +51,24 @@ function runNpmScript(script, options) {
56
51
 
57
52
  activeProcess = proc;
58
53
 
59
- console.log(chalk.green(' ✓ Process started (PID: ' + proc.pid + ')'));
60
- console.log(chalk.cyan('━'.repeat(60)) + '\n');
61
-
62
54
  // Handle stdout
63
55
  proc.stdout.on('data', function(data) {
64
56
  var output = data.toString();
65
57
  logOutput('stdout', output);
66
- process.stdout.write(chalk.gray('[npm] ') + output);
58
+ process.stdout.write(output);
67
59
  });
68
60
 
69
61
  // Handle stderr
70
62
  proc.stderr.on('data', function(data) {
71
63
  var output = data.toString();
72
64
  logOutput('stderr', output);
73
- process.stderr.write(chalk.yellow('[npm] ') + output);
65
+ process.stderr.write(output);
74
66
  });
75
67
 
76
68
  // Handle exit
77
69
  proc.on('exit', function(code, signal) {
78
- if (code !== null) {
79
- if (code === 0) {
80
- console.log(chalk.green('\n ✓ Process exited successfully (code: ' + code + ')'));
81
- } else {
82
- console.log(chalk.red('\n ✖ Process exited with code: ' + code));
83
- }
70
+ if (code !== null && code !== 0) {
71
+ console.log(chalk.red('\n ✖ Process exited with code: ' + code));
84
72
  }
85
73
  if (signal) {
86
74
  console.log(chalk.yellow(' ⚠ Process killed with signal: ' + signal));
@@ -171,10 +159,6 @@ function runCommand(command, options) {
171
159
  options = options || {};
172
160
  var cwd = options.cwd || process.cwd();
173
161
 
174
- console.log(chalk.cyan.bold(' 🚀 Running command: ') + chalk.yellow(command));
175
- console.log(chalk.gray(' Working directory: ') + chalk.white(cwd));
176
- console.log(chalk.gray(' (Real execution, not just a title)\n'));
177
-
178
162
  var proc = spawn(command, {
179
163
  cwd: cwd,
180
164
  stdio: ['inherit', 'pipe', 'pipe'],
@@ -183,31 +167,24 @@ function runCommand(command, options) {
183
167
 
184
168
  activeProcess = proc;
185
169
 
186
- console.log(chalk.green(' ✓ Process started (PID: ' + proc.pid + ')'));
187
- console.log(chalk.cyan('━'.repeat(60)) + '\n');
188
-
189
170
  // Handle stdout
190
171
  proc.stdout.on('data', function(data) {
191
172
  var output = data.toString();
192
173
  logOutput('stdout', output);
193
- process.stdout.write(chalk.gray('[cmd] ') + output);
174
+ process.stdout.write(output);
194
175
  });
195
176
 
196
177
  // Handle stderr
197
178
  proc.stderr.on('data', function(data) {
198
179
  var output = data.toString();
199
180
  logOutput('stderr', output);
200
- process.stderr.write(chalk.yellow('[cmd] ') + output);
181
+ process.stderr.write(output);
201
182
  });
202
183
 
203
184
  // Handle exit
204
185
  proc.on('exit', function(code, signal) {
205
- if (code !== null) {
206
- if (code === 0) {
207
- console.log(chalk.green('\n ✓ Command completed successfully (code: ' + code + ')'));
208
- } else {
209
- console.log(chalk.red('\n ✖ Command exited with code: ' + code));
210
- }
186
+ if (code !== null && code !== 0) {
187
+ console.log(chalk.red('\n ✖ Command exited with code: ' + code));
211
188
  }
212
189
  if (signal) {
213
190
  console.log(chalk.yellow(' ⚠ Process killed with signal: ' + signal));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gib-runs",
3
- "version": "2.2.0",
3
+ "version": "2.3.2",
4
4
  "description": "Modern development server with live reload, hot module replacement, and advanced features for all project types - runs on merit, not nepotism",
5
5
  "keywords": [
6
6
  "development",