about-system 0.0.12 → 0.0.14

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.
@@ -1,29 +1,15 @@
1
1
  #!/usr/bin/env node
2
-
3
- /**
4
- * =========================================================
5
- * System Info with Emojis - Node.js Version
6
- * =========================================================
7
- * Node.js script to display key system information with emojis
8
- * The output and order are fully customizable: edit DISPLAY_ORDER
9
- * to control which info blocks are shown and in what order.
10
- * Supported blocks: user, hostname, ip, iplocal, city, domain, isp, os,
11
- * cpu, gpu, disk_used, ram_used, top_process, device, kernel, uptime,
12
- * shell, pacman, ports, containers, memory_available, swap_used,
13
- * load_average, users_logged_in, network_interfaces, mount_points,
14
- * services_running, temperature, battery, screen_resolution.
15
- * Network info (ip, city, domain, isp) is fetched from ipinfo.io
16
- * only if needed.
17
- *
18
- * @author: vtempest
19
- * @license: MIT
20
- */
21
-
22
2
  import os from 'os';
23
3
  import fs from 'fs';
24
4
  import path from 'path';
25
5
  import { execSync } from 'child_process';
26
6
  import https from 'https';
7
+ import { fileURLToPath } from 'url';
8
+
9
+ const __filename = fileURLToPath(import.meta.url);
10
+ import { fileURLToPath } from 'url';
11
+
12
+ const __filename = fileURLToPath(import.meta.url);
27
13
 
28
14
  // Cache configuration
29
15
  const CACHE_FILE = path.join(os.tmpdir(), 'systeminfo-cache.json');
@@ -37,12 +23,12 @@ const CACHE_DURATION = {
37
23
  device: 24 * 60 * 60 * 1000, // 24 hours for device info
38
24
  kernel: 60 * 60 * 1000, // 1 hour for kernel (can change on updates)
39
25
  pacman: 10 * 60 * 1000, // 10 minutes for installed packages
40
- ports: 30 * 1000, // 30 seconds for ports (changes frequently)
41
- containers: 30 * 1000, // 30 seconds for containers
26
+ ports: 5 * 60 * 1000, // 30 seconds for ports (changes frequently)
27
+ containers: 5 * 60 * 1000, // 30 seconds for containers
42
28
  top_process: 5 * 1000, // 5 seconds for top process
43
29
  disk_used: 60 * 1000, // 1 minute for disk usage
44
30
  ram_used: 10 * 1000, // 10 seconds for RAM usage
45
- services_running: 30 * 1000, // 30 seconds for services
31
+ services_running: 5 * 60 * 1000, // 30 seconds for services
46
32
  temperature: 30 * 1000, // 30 seconds for temperature
47
33
  battery: 60 * 1000, // 1 minute for battery
48
34
  network_interfaces: 5 * 60 * 1000, // 5 minutes for network interfaces
@@ -52,20 +38,21 @@ const CACHE_DURATION = {
52
38
  // Default settings
53
39
  const DEFAULT_SETTINGS = {
54
40
  display_order: [
55
- ['user', 'hostname', 'os', 'device', 'kernel', 'cpu', 'gpu', ],
41
+ ['user', 'hostname', 'os', 'device', 'kernel', 'cpu', 'gpu',],
56
42
  ['disk_used', 'ram_used', 'top_process', 'uptime', 'temperature', 'battery', 'load_average'],
57
43
  ['ip', 'iplocal', 'city', 'domain', 'isp'],
58
- ['shell', 'pacman', 'ports', 'services_running', 'containers']
44
+ ['shell', 'pacman', 'services_running', 'containers']
45
+ // ['ports']
59
46
  ],
60
47
  colors: {
61
48
  user: "red",
62
- hostname: "orange",
49
+ hostname: "orange",
63
50
  disk_used: "purple",
64
51
  ram_used: "yellow",
65
52
  top_process: "magenta",
66
53
  uptime: "cyan",
67
54
  ip: "green",
68
- iplocal: "yellow",
55
+ iplocal: "yellow",
69
56
  city: "green",
70
57
  domain: "gray",
71
58
  isp: "lightblue",
@@ -165,13 +152,13 @@ function isCacheValid(cacheEntry, key) {
165
152
  // Cache helper functions
166
153
  function getCachedValue(cache, key, settings = null) {
167
154
  if (!cache[key]) return null;
168
-
155
+
169
156
  const cacheEntry = cache[key];
170
157
  if (!isCacheValid(cacheEntry, key)) {
171
158
  delete cache[key];
172
159
  return null;
173
160
  }
174
-
161
+
175
162
  return cacheEntry.value;
176
163
  }
177
164
 
@@ -216,11 +203,11 @@ function loadSettings() {
216
203
  function execCommand(command, options = {}) {
217
204
  try {
218
205
  const cmd = IS_WINDOWS ? `cmd /c ${command}` : command;
219
- return execSync(cmd, {
220
- encoding: 'utf8',
206
+ return execSync(cmd, {
207
+ encoding: 'utf8',
221
208
  timeout: 10000,
222
209
  stdio: ['pipe', 'pipe', 'ignore'],
223
- ...options
210
+ ...options
224
211
  }).toString().trim();
225
212
  } catch (error) {
226
213
  return '';
@@ -247,7 +234,7 @@ async function fetchIPInfo(settings) {
247
234
  const token = settings.network.ipinfo_token;
248
235
  const timeout = settings.network.timeout;
249
236
  const url = `https://ipinfo.io/json${token ? `?token=${token}` : ''}`;
250
-
237
+
251
238
  const req = https.get(url, (res) => {
252
239
  let data = '';
253
240
  res.on('data', (chunk) => data += chunk);
@@ -259,7 +246,7 @@ async function fetchIPInfo(settings) {
259
246
  }
260
247
  });
261
248
  });
262
-
249
+
263
250
  req.on('error', () => resolve({}));
264
251
  req.setTimeout(timeout, () => {
265
252
  req.destroy();
@@ -285,10 +272,10 @@ const infoFunctions = {
285
272
  async ip(settings) {
286
273
  const cached = getCachedValue(this.cache, 'ip', settings);
287
274
  if (cached) return cached;
288
-
275
+
289
276
  if (!this.ipInfo) {
290
277
  const emoji = settings.display.show_emojis ? '🌎 ' : '';
291
- const result = settings.network.show_offline_message ?
278
+ const result = settings.network.show_offline_message ?
292
279
  `${colors.gray}${emoji}No Network` : '';
293
280
  setCachedValue(this.cache, 'ip', result);
294
281
  return result;
@@ -304,7 +291,7 @@ const infoFunctions = {
304
291
  iplocal(settings) {
305
292
  const color = colors[settings.colors.iplocal] || colors.yellow;
306
293
  const emoji = settings.display.show_emojis ? '🌐 ' : '';
307
-
294
+
308
295
  if (IS_LINUX) {
309
296
  // Try ifconfig first (like bash script)
310
297
  try {
@@ -313,8 +300,8 @@ const infoFunctions = {
313
300
  if (wlanMatch) {
314
301
  return `${color}${emoji}${wlanMatch[1]}`;
315
302
  }
316
- } catch {}
317
-
303
+ } catch { }
304
+
318
305
  // Fallback to ip command (like bash script)
319
306
  try {
320
307
  const ipAddr = execCommand('ip addr show 2>/dev/null');
@@ -328,13 +315,13 @@ const infoFunctions = {
328
315
  if (addresses.length > 0) {
329
316
  return `${color}${emoji}${addresses.join(' ')}`;
330
317
  }
331
- } catch {}
318
+ } catch { }
332
319
  }
333
-
320
+
334
321
  // Fallback to Node.js method
335
322
  const interfaces = os.networkInterfaces();
336
323
  const addresses = [];
337
-
324
+
338
325
  for (const name of Object.keys(interfaces)) {
339
326
  for (const device of interfaces[name]) {
340
327
  if (device.family === 'IPv4' && !device.internal) {
@@ -342,7 +329,7 @@ const infoFunctions = {
342
329
  }
343
330
  }
344
331
  }
345
-
332
+
346
333
  if (addresses.length === 0) return '';
347
334
  return `${color}${emoji}${addresses.join(' ')}`;
348
335
  },
@@ -350,7 +337,7 @@ const infoFunctions = {
350
337
  async city(settings) {
351
338
  const cached = getCachedValue(this.cache, 'city', settings);
352
339
  if (cached) return cached;
353
-
340
+
354
341
  if (!this.ipInfo || !this.ipInfo.city) {
355
342
  setCachedValue(this.cache, 'city', '');
356
343
  return '';
@@ -365,7 +352,7 @@ const infoFunctions = {
365
352
  async domain(settings) {
366
353
  const cached = getCachedValue(this.cache, 'domain', settings);
367
354
  if (cached) return cached;
368
-
355
+
369
356
  if (!this.ipInfo || !this.ipInfo.hostname) {
370
357
  setCachedValue(this.cache, 'domain', '');
371
358
  return '';
@@ -380,7 +367,7 @@ const infoFunctions = {
380
367
  async isp(settings) {
381
368
  const cached = getCachedValue(this.cache, 'isp', settings);
382
369
  if (cached) return cached;
383
-
370
+
384
371
  if (!this.ipInfo || !this.ipInfo.org) {
385
372
  setCachedValue(this.cache, 'isp', '');
386
373
  return '';
@@ -396,11 +383,11 @@ const infoFunctions = {
396
383
  os(settings) {
397
384
  const cached = getCachedValue(this.cache, 'os', settings);
398
385
  if (cached) return cached;
399
-
386
+
400
387
  const platform = os.platform();
401
388
  const release = os.release();
402
389
  let osName = '';
403
-
390
+
404
391
  if (IS_WINDOWS) {
405
392
  try {
406
393
  const version = execCommand('ver');
@@ -424,7 +411,7 @@ const infoFunctions = {
424
411
  } else {
425
412
  osName = `${platform} ${release}`;
426
413
  }
427
-
414
+
428
415
  const color = colors[settings.colors.os] || colors.blue;
429
416
  const emoji = settings.display.show_emojis ? '⚡ ' : '';
430
417
  const result = `${color}${emoji}${osName}`;
@@ -435,9 +422,9 @@ const infoFunctions = {
435
422
  cpu(settings) {
436
423
  const cached = getCachedValue(this.cache, 'cpu', settings);
437
424
  if (cached) return cached;
438
-
425
+
439
426
  let cpuName = '';
440
-
427
+
441
428
  if (IS_WINDOWS) {
442
429
  // Windows-specific CPU detection using WMIC
443
430
  try {
@@ -446,8 +433,8 @@ const infoFunctions = {
446
433
  if (nameMatch) {
447
434
  cpuName = nameMatch[1].trim();
448
435
  }
449
- } catch {}
450
-
436
+ } catch { }
437
+
451
438
  // Fallback to PowerShell if WMIC fails
452
439
  if (!cpuName) {
453
440
  try {
@@ -455,7 +442,7 @@ const infoFunctions = {
455
442
  if (ps.trim()) {
456
443
  cpuName = ps.trim();
457
444
  }
458
- } catch {}
445
+ } catch { }
459
446
  }
460
447
  } else if (IS_LINUX) {
461
448
  // Try lscpu first (like bash script)
@@ -465,21 +452,21 @@ const infoFunctions = {
465
452
  if (modelMatch) {
466
453
  cpuName = modelMatch[1].trim();
467
454
  }
468
- } catch {}
469
-
455
+ } catch { }
456
+
470
457
  // Fallback to /proc/cpuinfo (like bash script)
471
458
  if (!cpuName) {
472
459
  try {
473
460
  const cpuInfo = fs.readFileSync('/proc/cpuinfo', 'utf8');
474
461
  const modelMatch = cpuInfo.match(/model name\s*:\s*([^\n]+)/);
475
462
  const hardwareMatch = cpuInfo.match(/Hardware\s*:\s*([^\n]+)/);
476
-
463
+
477
464
  if (modelMatch) {
478
465
  cpuName = modelMatch[1].trim();
479
466
  } else if (hardwareMatch) {
480
467
  cpuName = hardwareMatch[1].trim();
481
468
  }
482
- } catch {}
469
+ } catch { }
483
470
  }
484
471
  } else {
485
472
  // Use Node.js os module for other platforms
@@ -488,7 +475,7 @@ const infoFunctions = {
488
475
  cpuName = cpus[0].model.trim().replace(/[\r\n]+/g, ' ');
489
476
  }
490
477
  }
491
-
478
+
492
479
  if (!cpuName) {
493
480
  setCachedValue(this.cache, 'cpu', '');
494
481
  return '';
@@ -496,7 +483,7 @@ const infoFunctions = {
496
483
 
497
484
  //remove "with ..." from cpuName
498
485
  cpuName = cpuName.trim().replace(/with .*/, '');
499
-
486
+
500
487
  const color = colors[settings.colors.cpu] || colors.orange;
501
488
  const emoji = settings.display.show_emojis ? '📈 ' : '';
502
489
  const result = `${color}${emoji}${cpuName}`;
@@ -507,7 +494,7 @@ const infoFunctions = {
507
494
  gpu(settings) {
508
495
  const cached = getCachedValue(this.cache, 'gpu', settings);
509
496
  if (cached) return cached;
510
-
497
+
511
498
  if (IS_WINDOWS) {
512
499
  try {
513
500
  // Get GPU information using WMIC
@@ -523,8 +510,8 @@ const infoFunctions = {
523
510
  return result;
524
511
  }
525
512
  }
526
- } catch {}
527
-
513
+ } catch { }
514
+
528
515
  // Fallback using PowerShell
529
516
  try {
530
517
  const ps = execCommand('powershell.exe -Command "Get-WmiObject -Class Win32_VideoController | Where-Object {$_.Name -notlike \'*Microsoft Basic*\'} | Select-Object -First 1 -ExpandProperty Name"');
@@ -536,7 +523,7 @@ const infoFunctions = {
536
523
  setCachedValue(this.cache, 'gpu', result);
537
524
  return result;
538
525
  }
539
- } catch {}
526
+ } catch { }
540
527
  } else if (IS_LINUX) {
541
528
  try {
542
529
  const lspci = execCommand('lspci');
@@ -544,7 +531,7 @@ const infoFunctions = {
544
531
  const gpuMatch = lspci.match(/VGA.*?(RTX|GeForce|AMD|Intel|NVIDIA)[^\n]*/i);
545
532
  if (gpuMatch) {
546
533
  let gpu = gpuMatch[0];
547
-
534
+
548
535
  // Try to extract clean GPU name from brackets like bash script
549
536
  const bracketMatch = gpu.match(/\[([^\]]+)\]/);
550
537
  if (bracketMatch) {
@@ -553,7 +540,7 @@ const infoFunctions = {
553
540
  // Fallback: clean up the string
554
541
  gpu = gpu.replace(/^.*VGA[^:]*:\s*/, '').replace(/\s*\(.*\)$/, '').trim();
555
542
  }
556
-
543
+
557
544
  if (gpu) {
558
545
  const color = colors[settings.colors.gpu] || colors.yellow;
559
546
  const emoji = settings.display.show_emojis ? '🎮 ' : '';
@@ -562,9 +549,9 @@ const infoFunctions = {
562
549
  return result;
563
550
  }
564
551
  }
565
- } catch {}
552
+ } catch { }
566
553
  }
567
-
554
+
568
555
  setCachedValue(this.cache, 'gpu', '');
569
556
  return '';
570
557
  },
@@ -572,7 +559,7 @@ const infoFunctions = {
572
559
  disk_used(settings) {
573
560
  const cached = getCachedValue(this.cache, 'disk_used', settings);
574
561
  if (cached) return cached;
575
-
562
+
576
563
  if (IS_WINDOWS) {
577
564
  // try {
578
565
  // // Get disk usage for C: drive using PowerShell
@@ -587,13 +574,13 @@ const infoFunctions = {
587
574
  // return result;
588
575
  // }
589
576
  // } catch {}
590
-
577
+
591
578
  // // Fallback using WMIC
592
579
  // try {
593
580
  // const wmic = execCommand('wmic logicaldisk where "DeviceID=\'C:\'" get Size,FreeSpace /format:list');
594
581
  // const sizeMatch = wmic.match(/Size=(\d+)/);
595
582
  // const freeMatch = wmic.match(/FreeSpace=(\d+)/);
596
-
583
+
597
584
  // if (sizeMatch && freeMatch) {
598
585
  // const size = parseInt(sizeMatch[1]);
599
586
  // const free = parseInt(freeMatch[1]);
@@ -610,7 +597,7 @@ const infoFunctions = {
610
597
  try {
611
598
  const df = execCommand('df -h');
612
599
  let diskUsage = '';
613
-
600
+
614
601
  // Check for Android storage first
615
602
  if (df.includes('/storage/emulated')) {
616
603
  const match = df.match(/\s+(\d+%)\s+\/storage\/emulated/);
@@ -629,14 +616,14 @@ const infoFunctions = {
629
616
  }
630
617
  }
631
618
  }
632
-
619
+
633
620
  // Fallback: look for any line with root mount point
634
621
  if (!diskUsage) {
635
622
  const rootMatch = df.match(/(\d+%)\s+\/\s*$/m);
636
623
  diskUsage = rootMatch ? rootMatch[1] : '';
637
624
  }
638
625
  }
639
-
626
+
640
627
  if (diskUsage) {
641
628
  const color = colors[settings.colors.disk_used] || colors.purple;
642
629
  const emoji = settings.display.show_emojis ? '📁 ' : '';
@@ -644,9 +631,9 @@ const infoFunctions = {
644
631
  setCachedValue(this.cache, 'disk_used', result);
645
632
  return result;
646
633
  }
647
- } catch {}
634
+ } catch { }
648
635
  }
649
-
636
+
650
637
  setCachedValue(this.cache, 'disk_used', '');
651
638
  return '';
652
639
  },
@@ -654,39 +641,39 @@ const infoFunctions = {
654
641
  ram_used(settings) {
655
642
  const cached = getCachedValue(this.cache, 'ram_used', settings);
656
643
  if (cached) return cached;
657
-
644
+
658
645
  if (IS_LINUX) {
659
646
  // Use /proc/meminfo for more accurate Linux memory info like bash script
660
647
  try {
661
648
  const meminfo = fs.readFileSync('/proc/meminfo', 'utf8');
662
649
  const totalMatch = meminfo.match(/MemTotal:\s+(\d+) kB/);
663
650
  const freeMatch = meminfo.match(/MemFree:\s+(\d+) kB/);
664
-
651
+
665
652
  if (totalMatch && freeMatch) {
666
653
  const totalMB = Math.round(parseInt(totalMatch[1]) / 1024);
667
654
  const freeMB = Math.round(parseInt(freeMatch[1]) / 1024);
668
655
  const usedMB = totalMB - freeMB;
669
-
656
+
670
657
  const totalGB = Math.round(totalMB / 1024);
671
658
  const usedGB = Math.round(usedMB / 1024);
672
-
659
+
673
660
  const color = colors[settings.colors.ram_used] || colors.yellow;
674
661
  const emoji = settings.display.show_emojis ? '💾 ' : '';
675
662
  const result = `${color}${emoji}${usedGB}/${totalGB}GB`;
676
663
  setCachedValue(this.cache, 'ram_used', result);
677
664
  return result;
678
665
  }
679
- } catch {}
666
+ } catch { }
680
667
  }
681
-
668
+
682
669
  // Fallback to Node.js os module
683
670
  const totalMem = os.totalmem();
684
671
  const freeMem = os.freemem();
685
672
  const usedMem = totalMem - freeMem;
686
-
673
+
687
674
  const totalGB = Math.round(totalMem / (1024 * 1024 * 1024));
688
675
  const usedGB = Math.round(usedMem / (1024 * 1024 * 1024));
689
-
676
+
690
677
  const color = colors[settings.colors.ram_used] || colors.yellow;
691
678
  const emoji = settings.display.show_emojis ? '💾 ' : '';
692
679
  const result = `${color}${emoji}${usedGB}/${totalGB}GB`;
@@ -697,7 +684,7 @@ const infoFunctions = {
697
684
  top_process(settings) {
698
685
  const cached = getCachedValue(this.cache, 'top_process', settings);
699
686
  if (cached) return cached;
700
-
687
+
701
688
  if (IS_LINUX) {
702
689
  try {
703
690
  const ps = execCommand('ps -eo pcpu,comm --sort=-%cpu --no-headers');
@@ -712,9 +699,9 @@ const infoFunctions = {
712
699
  setCachedValue(this.cache, 'top_process', result);
713
700
  return result;
714
701
  }
715
- } catch {}
702
+ } catch { }
716
703
  }
717
-
704
+
718
705
  setCachedValue(this.cache, 'top_process', '');
719
706
  return '';
720
707
  },
@@ -724,7 +711,7 @@ const infoFunctions = {
724
711
  const days = Math.floor(uptimeSeconds / 86400);
725
712
  const hours = Math.floor((uptimeSeconds % 86400) / 3600);
726
713
  const minutes = Math.floor((uptimeSeconds % 3600) / 60);
727
-
714
+
728
715
  const color = colors[settings.colors.uptime] || colors.cyan;
729
716
  const emoji = settings.display.show_emojis ? '⏱️ ' : '';
730
717
  return `${color}${emoji}${days}d ${hours}h ${minutes}m`;
@@ -733,7 +720,7 @@ const infoFunctions = {
733
720
  device(settings) {
734
721
  const cached = getCachedValue(this.cache, 'device', settings);
735
722
  if (cached) return cached;
736
-
723
+
737
724
  if (IS_WINDOWS) {
738
725
  try {
739
726
  // Get computer model using WMIC
@@ -749,8 +736,8 @@ const infoFunctions = {
749
736
  return result;
750
737
  }
751
738
  }
752
- } catch {}
753
-
739
+ } catch { }
740
+
754
741
  // Fallback using PowerShell
755
742
  try {
756
743
  const ps = execCommand('powershell.exe -Command "Get-WmiObject -Class Win32_ComputerSystem | Select-Object -ExpandProperty Model"');
@@ -762,7 +749,7 @@ const infoFunctions = {
762
749
  setCachedValue(this.cache, 'device', result);
763
750
  return result;
764
751
  }
765
- } catch {}
752
+ } catch { }
766
753
  } else if (IS_LINUX) {
767
754
  try {
768
755
  // Check for Android
@@ -776,7 +763,7 @@ const infoFunctions = {
776
763
  return result;
777
764
  }
778
765
  }
779
-
766
+
780
767
  // Check for DMI info
781
768
  const dmiPath = '/sys/devices/virtual/dmi/id/product_name';
782
769
  if (fs.existsSync(dmiPath)) {
@@ -789,9 +776,9 @@ const infoFunctions = {
789
776
  return result;
790
777
  }
791
778
  }
792
- } catch {}
779
+ } catch { }
793
780
  }
794
-
781
+
795
782
  setCachedValue(this.cache, 'device', '');
796
783
  return '';
797
784
  },
@@ -799,7 +786,7 @@ const infoFunctions = {
799
786
  kernel(settings) {
800
787
  const cached = getCachedValue(this.cache, 'kernel', settings);
801
788
  if (cached) return cached;
802
-
789
+
803
790
  const kernel = os.release();
804
791
  const color = colors[settings.colors.kernel] || colors.green;
805
792
  const emoji = settings.display.show_emojis ? '🔧 ' : '';
@@ -816,7 +803,7 @@ const infoFunctions = {
816
803
  const color = colors[settings.colors.shell] || colors.orange;
817
804
  const emoji = settings.display.show_emojis ? '🐚 ' : '';
818
805
  return `${color}${emoji}${shell}`;
819
- } catch {}
806
+ } catch { }
820
807
  }
821
808
  return '';
822
809
  },
@@ -824,16 +811,16 @@ const infoFunctions = {
824
811
  pacman(settings) {
825
812
  const cached = getCachedValue(this.cache, 'pacman', settings);
826
813
  if (cached) return cached;
827
-
828
- const commands = ['apt', 'npm', 'uv', 'docker', 'hx', 'nvim', 'bun', 'yay',
829
- 'pacman', 'yum', 'dnf', 'zypper', 'emerge', 'apk', 'snap', 'flatpak'];
814
+
815
+ const commands = ['apt', 'npm', 'uv', 'docker', 'hx', 'nvim', 'bun', 'yay',
816
+ 'pacman', 'yum', 'dnf', 'zypper', 'emerge', 'apk', 'snap', 'flatpak'];
830
817
  const available = commands.filter(cmd => commandExists(cmd));
831
-
818
+
832
819
  if (available.length === 0) {
833
820
  setCachedValue(this.cache, 'pacman', '');
834
821
  return '';
835
822
  }
836
-
823
+
837
824
  const color = colors[settings.colors.pacman] || colors.cyan;
838
825
  const emoji = settings.display.show_emojis ? '🚀 ' : '';
839
826
  const result = `${color}${emoji}${available.join(' ')}`;
@@ -844,13 +831,13 @@ const infoFunctions = {
844
831
  ports(settings) {
845
832
  const cached = getCachedValue(this.cache, 'ports', settings);
846
833
  if (cached) return cached;
847
-
834
+
848
835
  if (IS_LINUX) {
849
836
  try {
850
837
  const lsof = execCommand('lsof -nP -iTCP -sTCP:LISTEN');
851
838
  const lines = lsof.split('\n').slice(1); // Skip header
852
839
  const ports = new Set();
853
-
840
+
854
841
  lines.forEach(line => {
855
842
  const parts = line.split(/\s+/);
856
843
  if (parts.length >= 9) {
@@ -863,12 +850,12 @@ const infoFunctions = {
863
850
  }
864
851
  }
865
852
  });
866
-
853
+
867
854
  if (ports.size > 0) {
868
855
  const portList = Array.from(ports);
869
856
  const emoji = settings.display.show_emojis ? '🔌 ' : '';
870
857
  let output = ` ${emoji}`;
871
-
858
+
872
859
  if (settings.colors.ports === 'multicolor') {
873
860
  const colorCodes = [31, 32, 33, 34, 35, 36]; // Red, Green, Yellow, Blue, Magenta, Cyan
874
861
  portList.forEach((port, index) => {
@@ -879,14 +866,14 @@ const infoFunctions = {
879
866
  const color = colors[settings.colors.ports] || colors.cyan;
880
867
  output = `${color}${emoji}${portList.join(' ')}`;
881
868
  }
882
-
869
+
883
870
  const result = output.trim();
884
871
  setCachedValue(this.cache, 'ports', result);
885
872
  return result;
886
873
  }
887
- } catch {}
874
+ } catch { }
888
875
  }
889
-
876
+
890
877
  setCachedValue(this.cache, 'ports', '');
891
878
  return '';
892
879
  },
@@ -894,31 +881,31 @@ const infoFunctions = {
894
881
  containers(settings) {
895
882
  const cached = getCachedValue(this.cache, 'containers', settings);
896
883
  if (cached) return cached;
897
-
884
+
898
885
  if (!commandExists('docker')) {
899
886
  setCachedValue(this.cache, 'containers', '');
900
887
  return '';
901
888
  }
902
-
889
+
903
890
  try {
904
891
  const containerCount = execCommand('docker ps -q').split('\n').filter(line => line.trim()).length;
905
892
  if (containerCount === 0) {
906
893
  setCachedValue(this.cache, 'containers', '');
907
894
  return '';
908
895
  }
909
-
896
+
910
897
  const containers = execCommand('docker ps --format "{{.Names}}\t{{.Ports}}"');
911
898
  const lines = containers.split('\n').filter(line => line.trim());
912
-
899
+
913
900
  const emoji = settings.display.show_emojis ? '📦' : '';
914
901
  const color = colors[settings.colors.containers] || colors.green;
915
902
  let output = ` ${color}${emoji}\x1b[0m`;
916
-
903
+
917
904
  lines.forEach(line => {
918
905
  const [name, ports] = line.split('\t');
919
906
  if (name) {
920
907
  output += ` ${color}${name}\x1b[0m`;
921
-
908
+
922
909
  if (ports) {
923
910
  const portMatches = ports.match(/->(\d+(-\d+)?)\//g);
924
911
  if (portMatches) {
@@ -930,11 +917,11 @@ const infoFunctions = {
930
917
  }
931
918
  }
932
919
  });
933
-
920
+
934
921
  setCachedValue(this.cache, 'containers', output);
935
922
  return output;
936
- } catch {}
937
-
923
+ } catch { }
924
+
938
925
  setCachedValue(this.cache, 'containers', '');
939
926
  return '';
940
927
  },
@@ -942,7 +929,7 @@ const infoFunctions = {
942
929
  // Additional Linux system info functions
943
930
  memory_available(settings) {
944
931
  if (!IS_LINUX) return '';
945
-
932
+
946
933
  try {
947
934
  const meminfo = fs.readFileSync('/proc/meminfo', 'utf8');
948
935
  const availableMatch = meminfo.match(/MemAvailable:\s+(\d+) kB/);
@@ -952,23 +939,23 @@ const infoFunctions = {
952
939
  const emoji = settings.display.show_emojis ? '🧠 ' : '';
953
940
  return `${color}${emoji}${availableGB}GB available`;
954
941
  }
955
- } catch {}
942
+ } catch { }
956
943
  return '';
957
944
  },
958
945
 
959
946
  swap_used(settings) {
960
947
  if (!IS_LINUX) return '';
961
-
948
+
962
949
  try {
963
950
  const meminfo = fs.readFileSync('/proc/meminfo', 'utf8');
964
951
  const swapTotalMatch = meminfo.match(/SwapTotal:\s+(\d+) kB/);
965
952
  const swapFreeMatch = meminfo.match(/SwapFree:\s+(\d+) kB/);
966
-
953
+
967
954
  if (swapTotalMatch && swapFreeMatch) {
968
955
  const swapTotal = parseInt(swapTotalMatch[1]);
969
956
  const swapFree = parseInt(swapFreeMatch[1]);
970
957
  const swapUsed = swapTotal - swapFree;
971
-
958
+
972
959
  if (swapTotal > 0) {
973
960
  const swapUsedPercent = Math.round((swapUsed / swapTotal) * 100);
974
961
  const swapUsedMB = Math.round(swapUsed / 1024);
@@ -977,26 +964,26 @@ const infoFunctions = {
977
964
  return `${color}${emoji}${swapUsedPercent}% (${swapUsedMB}MB) swap`;
978
965
  }
979
966
  }
980
- } catch {}
967
+ } catch { }
981
968
  return '';
982
969
  },
983
970
 
984
971
  load_average(settings) {
985
972
  if (!IS_LINUX) return '';
986
-
973
+
987
974
  try {
988
975
  const loadavg = fs.readFileSync('/proc/loadavg', 'utf8');
989
976
  const loads = loadavg.split(' ').slice(0, 3);
990
977
  const color = colors[settings.colors.load_average] || colors.red;
991
978
  const emoji = settings.display.show_emojis ? '⚖️ ' : '';
992
979
  return `${color}${emoji}${loads.join(' ')}`;
993
- } catch {}
980
+ } catch { }
994
981
  return '';
995
982
  },
996
983
 
997
984
  users_logged_in(settings) {
998
985
  if (!IS_LINUX) return '';
999
-
986
+
1000
987
  try {
1001
988
  const who = execCommand('who');
1002
989
  const users = who.split('\n').filter(line => line.trim()).length;
@@ -1005,23 +992,23 @@ const infoFunctions = {
1005
992
  const emoji = settings.display.show_emojis ? '👥 ' : '';
1006
993
  return `${color}${emoji}${users} users`;
1007
994
  }
1008
- } catch {}
995
+ } catch { }
1009
996
  return '';
1010
997
  },
1011
998
 
1012
999
  network_interfaces(settings) {
1013
1000
  const cached = getCachedValue(this.cache, 'network_interfaces', settings);
1014
1001
  if (cached) return cached;
1015
-
1002
+
1016
1003
  if (!IS_LINUX) {
1017
1004
  setCachedValue(this.cache, 'network_interfaces', '');
1018
1005
  return '';
1019
1006
  }
1020
-
1007
+
1021
1008
  try {
1022
1009
  const interfaces = os.networkInterfaces();
1023
1010
  const activeInterfaces = [];
1024
-
1011
+
1025
1012
  for (const [name, addrs] of Object.entries(interfaces)) {
1026
1013
  if (name !== 'lo') { // Skip loopback
1027
1014
  const ipv4Addr = addrs.find(addr => addr.family === 'IPv4' && !addr.internal);
@@ -1030,7 +1017,7 @@ const infoFunctions = {
1030
1017
  }
1031
1018
  }
1032
1019
  }
1033
-
1020
+
1034
1021
  if (activeInterfaces.length > 0) {
1035
1022
  const color = colors[settings.colors.network_interfaces] || colors.yellow;
1036
1023
  const emoji = settings.display.show_emojis ? '🌐 ' : '';
@@ -1038,8 +1025,8 @@ const infoFunctions = {
1038
1025
  setCachedValue(this.cache, 'network_interfaces', result);
1039
1026
  return result;
1040
1027
  }
1041
- } catch {}
1042
-
1028
+ } catch { }
1029
+
1043
1030
  setCachedValue(this.cache, 'network_interfaces', '');
1044
1031
  return '';
1045
1032
  },
@@ -1047,29 +1034,29 @@ const infoFunctions = {
1047
1034
  mount_points(settings) {
1048
1035
  const cached = getCachedValue(this.cache, 'mount_points', settings);
1049
1036
  if (cached) return cached;
1050
-
1037
+
1051
1038
  if (!IS_LINUX) {
1052
1039
  setCachedValue(this.cache, 'mount_points', '');
1053
1040
  return '';
1054
1041
  }
1055
-
1042
+
1056
1043
  try {
1057
1044
  const df = execCommand('df -h');
1058
1045
  const lines = df.split('\n').slice(1); // Skip header
1059
1046
  const mountPoints = [];
1060
-
1047
+
1061
1048
  lines.forEach(line => {
1062
1049
  const parts = line.trim().split(/\s+/);
1063
1050
  if (parts.length >= 6) {
1064
1051
  const mountPoint = parts[5];
1065
1052
  const usage = parts[4];
1066
- if (!mountPoint.startsWith('/dev') && !mountPoint.startsWith('/proc') &&
1067
- !mountPoint.startsWith('/sys') && mountPoint !== '/') {
1053
+ if (!mountPoint.startsWith('/dev') && !mountPoint.startsWith('/proc') &&
1054
+ !mountPoint.startsWith('/sys') && mountPoint !== '/') {
1068
1055
  mountPoints.push(`${mountPoint}(${usage})`);
1069
1056
  }
1070
1057
  }
1071
1058
  });
1072
-
1059
+
1073
1060
  if (mountPoints.length > 0) {
1074
1061
  const color = colors[settings.colors.mount_points] || colors.gray;
1075
1062
  const emoji = settings.display.show_emojis ? '📂 ' : '';
@@ -1077,8 +1064,8 @@ const infoFunctions = {
1077
1064
  setCachedValue(this.cache, 'mount_points', result);
1078
1065
  return result;
1079
1066
  }
1080
- } catch {}
1081
-
1067
+ } catch { }
1068
+
1082
1069
  setCachedValue(this.cache, 'mount_points', '');
1083
1070
  return '';
1084
1071
  },
@@ -1086,15 +1073,15 @@ const infoFunctions = {
1086
1073
  services_running(settings) {
1087
1074
  const cached = getCachedValue(this.cache, 'services_running', settings);
1088
1075
  if (cached) return cached;
1089
-
1076
+
1090
1077
  if (!IS_LINUX) {
1091
1078
  setCachedValue(this.cache, 'services_running', '');
1092
1079
  return '';
1093
1080
  }
1094
-
1081
+
1095
1082
  try {
1096
1083
  let serviceCount = 0;
1097
-
1084
+
1098
1085
  // Try systemctl first
1099
1086
  if (commandExists('systemctl')) {
1100
1087
  const services = execCommand('systemctl list-units --type=service --state=running --no-pager');
@@ -1104,7 +1091,7 @@ const infoFunctions = {
1104
1091
  const services = execCommand('service --status-all');
1105
1092
  serviceCount = services.split('\n').filter(line => line.includes('+')).length;
1106
1093
  }
1107
-
1094
+
1108
1095
  if (serviceCount > 0) {
1109
1096
  const color = colors[settings.colors.services_running] || colors.green;
1110
1097
  const emoji = settings.display.show_emojis ? '⚙️ ' : '';
@@ -1112,8 +1099,8 @@ const infoFunctions = {
1112
1099
  setCachedValue(this.cache, 'services_running', result);
1113
1100
  return result;
1114
1101
  }
1115
- } catch {}
1116
-
1102
+ } catch { }
1103
+
1117
1104
  setCachedValue(this.cache, 'services_running', '');
1118
1105
  return '';
1119
1106
  },
@@ -1121,12 +1108,12 @@ const infoFunctions = {
1121
1108
  temperature(settings) {
1122
1109
  const cached = getCachedValue(this.cache, 'temperature', settings);
1123
1110
  if (cached) return cached;
1124
-
1111
+
1125
1112
  if (!IS_LINUX) {
1126
1113
  setCachedValue(this.cache, 'temperature', '');
1127
1114
  return '';
1128
1115
  }
1129
-
1116
+
1130
1117
  try {
1131
1118
  // Try different temperature sources
1132
1119
  const tempSources = [
@@ -1134,12 +1121,12 @@ const infoFunctions = {
1134
1121
  '/sys/class/hwmon/hwmon0/temp1_input',
1135
1122
  '/sys/class/hwmon/hwmon1/temp1_input'
1136
1123
  ];
1137
-
1124
+
1138
1125
  for (const source of tempSources) {
1139
1126
  if (fs.existsSync(source)) {
1140
1127
  const temp = fs.readFileSync(source, 'utf8').trim();
1141
1128
  const tempC = Math.round(parseInt(temp) / 1000);
1142
-
1129
+
1143
1130
  if (tempC > 0 && tempC < 150) { // Reasonable temperature range
1144
1131
  const color = tempC > 70 ? colors.red : tempC > 50 ? colors.yellow : colors.green;
1145
1132
  const emoji = settings.display.show_emojis ? '🌡️ ' : '';
@@ -1149,8 +1136,8 @@ const infoFunctions = {
1149
1136
  }
1150
1137
  }
1151
1138
  }
1152
- } catch {}
1153
-
1139
+ } catch { }
1140
+
1154
1141
  setCachedValue(this.cache, 'temperature', '');
1155
1142
  return '';
1156
1143
  },
@@ -1158,41 +1145,41 @@ const infoFunctions = {
1158
1145
  battery(settings) {
1159
1146
  const cached = getCachedValue(this.cache, 'battery', settings);
1160
1147
  if (cached) return cached;
1161
-
1148
+
1162
1149
  if (!IS_LINUX) {
1163
1150
  setCachedValue(this.cache, 'battery', '');
1164
1151
  return '';
1165
1152
  }
1166
-
1153
+
1167
1154
  try {
1168
1155
  const batteryPath = '/sys/class/power_supply/BAT0';
1169
1156
  const capacityPath = `${batteryPath}/capacity`;
1170
1157
  const statusPath = `${batteryPath}/status`;
1171
-
1158
+
1172
1159
  if (fs.existsSync(capacityPath)) {
1173
1160
  const capacity = fs.readFileSync(capacityPath, 'utf8').trim();
1174
- const status = fs.existsSync(statusPath) ?
1161
+ const status = fs.existsSync(statusPath) ?
1175
1162
  fs.readFileSync(statusPath, 'utf8').trim() : 'Unknown';
1176
-
1163
+
1177
1164
  const batteryPercent = parseInt(capacity);
1178
1165
  const isCharging = status === 'Charging';
1179
- const color = batteryPercent < 20 ? colors.red :
1180
- batteryPercent < 50 ? colors.yellow : colors.green;
1181
- const emoji = settings.display.show_emojis ?
1166
+ const color = batteryPercent < 20 ? colors.red :
1167
+ batteryPercent < 50 ? colors.yellow : colors.green;
1168
+ const emoji = settings.display.show_emojis ?
1182
1169
  (isCharging ? '🔌 ' : '🔋 ') : '';
1183
1170
  const result = `${color}${emoji}${batteryPercent}%${isCharging ? '+' : ''}`;
1184
1171
  setCachedValue(this.cache, 'battery', result);
1185
1172
  return result;
1186
1173
  }
1187
- } catch {}
1188
-
1174
+ } catch { }
1175
+
1189
1176
  setCachedValue(this.cache, 'battery', '');
1190
1177
  return '';
1191
1178
  },
1192
1179
 
1193
1180
  screen_resolution(settings) {
1194
1181
  if (!IS_LINUX) return '';
1195
-
1182
+
1196
1183
  try {
1197
1184
  if (process.env.DISPLAY) {
1198
1185
  const xrandr = execCommand('xrandr');
@@ -1203,34 +1190,37 @@ const infoFunctions = {
1203
1190
  return `${color}${emoji}${resolutionMatch[1]}`;
1204
1191
  }
1205
1192
  }
1206
- } catch {}
1193
+ } catch { }
1207
1194
  return '';
1208
1195
  }
1209
1196
  };
1210
1197
 
1211
1198
  // Main function to display system info
1212
- async function displaySystemInfo() {
1199
+ async function displaySystemInfo(customDisplayOrder = null) {
1213
1200
  const settings = loadSettings();
1214
1201
  const cache = loadCache();
1215
1202
  const context = { cache, settings };
1216
-
1203
+
1204
+ // Use custom display order if provided, otherwise use settings
1205
+ const displayOrder = customDisplayOrder || settings.display_order;
1206
+
1217
1207
  // Check if we need IP info and it's not cached
1218
- const allKeys = settings.display_order.flat();
1208
+ const allKeys = displayOrder.flat();
1219
1209
  const needIPInfo = allKeys.some(key => ['ip', 'isp', 'domain', 'city'].includes(key));
1220
1210
  const cachedIPInfo = getCachedValue(cache, 'ipInfo', settings);
1221
-
1211
+
1222
1212
  if (needIPInfo && !cachedIPInfo) {
1223
1213
  context.ipInfo = await fetchIPInfo(settings);
1224
1214
  setCachedValue(cache, 'ipInfo', context.ipInfo);
1225
1215
  } else if (needIPInfo && cachedIPInfo) {
1226
1216
  context.ipInfo = cachedIPInfo;
1227
1217
  }
1228
-
1218
+
1229
1219
  // If single line mode is enabled, flatten everything into one line
1230
1220
  if (settings.display.single_line) {
1231
1221
  const allItems = [];
1232
-
1233
- for (const group of settings.display_order) {
1222
+
1223
+ for (const group of displayOrder) {
1234
1224
  for (const key of group) {
1235
1225
  if (infoFunctions[key]) {
1236
1226
  try {
@@ -1246,23 +1236,23 @@ async function displaySystemInfo() {
1246
1236
  }
1247
1237
  }
1248
1238
  }
1249
-
1239
+
1250
1240
  if (allItems.length > 0) {
1251
1241
  const singleLine = allItems.join(' ');
1252
1242
  console.log(singleLine + colors.reset);
1253
1243
  }
1254
-
1244
+
1255
1245
  // Save cache and return early
1256
1246
  saveCache(cache);
1257
1247
  return;
1258
1248
  }
1259
-
1249
+
1260
1250
  // Normal multi-line grouped display with intelligent wrapping
1261
1251
  const lines = [];
1262
1252
  let currentLine = '';
1263
1253
  const maxLineLength = settings.display.line_wrap_length || 120;
1264
-
1265
- for (const group of settings.display_order) {
1254
+
1255
+ for (const group of displayOrder) {
1266
1256
  for (const key of group) {
1267
1257
  if (infoFunctions[key]) {
1268
1258
  try {
@@ -1271,7 +1261,7 @@ async function displaySystemInfo() {
1271
1261
  // Remove ANSI color codes to get actual text length
1272
1262
  const infoLength = info.replace(/\x1b\[[0-9;]*m/g, '').length;
1273
1263
  const currentLineLength = currentLine.replace(/\x1b\[[0-9;]*m/g, '').length;
1274
-
1264
+
1275
1265
  // If adding this item would exceed the line length, start a new line
1276
1266
  if (currentLine && (currentLineLength + infoLength + 1) > maxLineLength) {
1277
1267
  lines.push(currentLine);
@@ -1295,22 +1285,22 @@ async function displaySystemInfo() {
1295
1285
  }
1296
1286
  }
1297
1287
  }
1298
-
1288
+
1299
1289
  // Add the last line if it has content
1300
1290
  if (currentLine) {
1301
1291
  lines.push(currentLine);
1302
1292
  }
1303
-
1293
+
1304
1294
  // Show offline message if no network and IP info was requested but failed
1305
- if (needIPInfo && (!context.ipInfo || Object.keys(context.ipInfo).length === 0) &&
1306
- settings.network.show_offline_message && lines.length === 0) {
1295
+ if (needIPInfo && (!context.ipInfo || Object.keys(context.ipInfo).length === 0) &&
1296
+ settings.network.show_offline_message && lines.length === 0) {
1307
1297
  const emoji = settings.display.show_emojis ? '❌ ' : '';
1308
1298
  lines.push(`${colors.red}${emoji}No internet connection`);
1309
1299
  }
1310
-
1300
+
1311
1301
  // Save cache after all operations
1312
1302
  saveCache(cache);
1313
-
1303
+
1314
1304
  // Output each line
1315
1305
  if (lines.length > 0) {
1316
1306
  lines.forEach(line => {
@@ -1324,7 +1314,7 @@ async function displaySystemInfo() {
1324
1314
  // Settings management commands
1325
1315
  function handleSettingsCommand(args) {
1326
1316
  const settings = loadSettings();
1327
-
1317
+
1328
1318
  if (args.includes('--settings-init')) {
1329
1319
  if (saveSettings(DEFAULT_SETTINGS)) {
1330
1320
  console.log('Settings initialized with defaults');
@@ -1333,13 +1323,13 @@ function handleSettingsCommand(args) {
1333
1323
  }
1334
1324
  return true;
1335
1325
  }
1336
-
1326
+
1337
1327
  if (args.includes('--settings-show')) {
1338
1328
  console.log('Current settings:');
1339
1329
  console.log(JSON.stringify(settings, null, 2));
1340
1330
  return true;
1341
1331
  }
1342
-
1332
+
1343
1333
  if (args.includes('--settings-reset')) {
1344
1334
  if (saveSettings(DEFAULT_SETTINGS)) {
1345
1335
  console.log('Settings reset to defaults');
@@ -1348,7 +1338,7 @@ function handleSettingsCommand(args) {
1348
1338
  }
1349
1339
  return true;
1350
1340
  }
1351
-
1341
+
1352
1342
  const cacheResetIndex = args.indexOf('--refresh');
1353
1343
  if (cacheResetIndex !== -1) {
1354
1344
  try {
@@ -1359,17 +1349,17 @@ function handleSettingsCommand(args) {
1359
1349
  console.error('Error clearing cache:', error.message);
1360
1350
  }
1361
1351
  }
1362
-
1352
+
1363
1353
  const setIndex = args.indexOf('--set');
1364
1354
  if (setIndex !== -1 && args[setIndex + 1] && args[setIndex + 2]) {
1365
1355
  const key = args[setIndex + 1];
1366
1356
  const value = args[setIndex + 2];
1367
-
1357
+
1368
1358
  try {
1369
1359
  // Parse JSON value if it looks like JSON
1370
- const parsedValue = value.startsWith('{') || value.startsWith('[') ?
1360
+ const parsedValue = value.startsWith('{') || value.startsWith('[') ?
1371
1361
  JSON.parse(value) : value;
1372
-
1362
+
1373
1363
  // Set nested property using dot notation
1374
1364
  const keys = key.split('.');
1375
1365
  let current = settings;
@@ -1378,7 +1368,7 @@ function handleSettingsCommand(args) {
1378
1368
  current = current[keys[i]];
1379
1369
  }
1380
1370
  current[keys[keys.length - 1]] = parsedValue;
1381
-
1371
+
1382
1372
  if (saveSettings(settings)) {
1383
1373
  console.log(`Setting ${key} = ${value}`);
1384
1374
  } else {
@@ -1389,14 +1379,14 @@ function handleSettingsCommand(args) {
1389
1379
  }
1390
1380
  return true;
1391
1381
  }
1392
-
1382
+
1393
1383
  return false;
1394
1384
  }
1395
1385
 
1396
1386
  // Installation function - Cross-platform compatible
1397
1387
  function installShellGreeting() {
1398
1388
  const homeDir = os.homedir();
1399
-
1389
+
1400
1390
  let configDir, scriptPath;
1401
1391
  if (IS_WINDOWS) {
1402
1392
  configDir = path.join(homeDir, 'AppData', 'Local');
@@ -1405,21 +1395,21 @@ function installShellGreeting() {
1405
1395
  configDir = path.join(homeDir, '.config');
1406
1396
  scriptPath = path.join(configDir, 'systeminfo.js');
1407
1397
  }
1408
-
1398
+
1409
1399
  const currentScript = path.resolve(__filename);
1410
-
1400
+
1411
1401
  try {
1412
1402
  // Ensure config directory exists
1413
1403
  if (!fs.existsSync(configDir)) {
1414
1404
  fs.mkdirSync(configDir, { recursive: true });
1415
1405
  }
1416
-
1406
+
1417
1407
  // Copy this script
1418
1408
  fs.copyFileSync(currentScript, scriptPath);
1419
1409
  if (!IS_WINDOWS) {
1420
1410
  fs.chmodSync(scriptPath, '755');
1421
1411
  }
1422
-
1412
+
1423
1413
  if (IS_WINDOWS) {
1424
1414
  // Windows-specific installation
1425
1415
  console.log('Windows installation:');
@@ -1427,14 +1417,14 @@ function installShellGreeting() {
1427
1417
  console.log('2. To add to PowerShell profile, run:');
1428
1418
  console.log(` Add-Content $PROFILE "node '${scriptPath}'"`);
1429
1419
  console.log('3. To add to Command Prompt, create a batch file in your startup folder');
1430
-
1420
+
1431
1421
  const startupBat = path.join(configDir, 'systeminfo-startup.bat');
1432
1422
  fs.writeFileSync(startupBat, `@echo off\nnode "${scriptPath}"\n`);
1433
1423
  console.log('4. Batch file created:', startupBat);
1434
-
1424
+
1435
1425
  } else {
1436
1426
  // Unix-like installation
1437
-
1427
+
1438
1428
  // Silence default login messages
1439
1429
  try {
1440
1430
  const hushLoginPath = path.join(homeDir, '.hushlogin');
@@ -1442,11 +1432,11 @@ function installShellGreeting() {
1442
1432
  } catch {
1443
1433
  // Ignore permission errors
1444
1434
  }
1445
-
1435
+
1446
1436
  // Add to bash
1447
1437
  const bashrcPath = path.join(homeDir, '.bashrc');
1448
1438
  const bashLine = `node ${scriptPath}`;
1449
-
1439
+
1450
1440
  if (fs.existsSync(bashrcPath)) {
1451
1441
  const bashrc = fs.readFileSync(bashrcPath, 'utf8');
1452
1442
  if (!bashrc.includes('systeminfo.js')) {
@@ -1455,7 +1445,7 @@ function installShellGreeting() {
1455
1445
  } else {
1456
1446
  fs.writeFileSync(bashrcPath, `${bashLine}\n`);
1457
1447
  }
1458
-
1448
+
1459
1449
  // Add to zsh (common on Mac)
1460
1450
  const zshrcPath = path.join(homeDir, '.zshrc');
1461
1451
  if (fs.existsSync(zshrcPath)) {
@@ -1464,7 +1454,7 @@ function installShellGreeting() {
1464
1454
  fs.appendFileSync(zshrcPath, `\n${bashLine}\n`);
1465
1455
  }
1466
1456
  }
1467
-
1457
+
1468
1458
  // Add to fish if config exists
1469
1459
  const fishConfigPath = path.join(homeDir, '.config', 'fish', 'config.fish');
1470
1460
  if (fs.existsSync(fishConfigPath)) {
@@ -1473,7 +1463,7 @@ function installShellGreeting() {
1473
1463
  fs.appendFileSync(fishConfigPath, `\nset -U fish_greeting ""\n${bashLine}\n`);
1474
1464
  }
1475
1465
  }
1476
-
1466
+
1477
1467
  // Add to nushell if config exists
1478
1468
  const nushellConfigPath = path.join(homeDir, '.config', 'nushell', 'config.nu');
1479
1469
  if (fs.existsSync(nushellConfigPath)) {
@@ -1483,30 +1473,73 @@ function installShellGreeting() {
1483
1473
  }
1484
1474
  }
1485
1475
  }
1486
-
1476
+
1487
1477
  console.log('Shell greeting installation completed!');
1488
-
1478
+
1489
1479
  } catch (error) {
1490
1480
  console.error('Error installing shell greeting:', error.message);
1491
1481
  process.exit(1);
1492
1482
  }
1493
1483
  }
1494
1484
 
1485
+ // Parse CLI mode arguments (comma-separated parts)
1486
+ function parseCLIMode(args) {
1487
+ // Look for arguments that don't start with -- and contain commas
1488
+ for (const arg of args) {
1489
+ if (!arg.startsWith('--') && arg.includes(',')) {
1490
+ return arg.split(',').map(part => part.trim()).filter(part => part.length > 0);
1491
+ }
1492
+ }
1493
+
1494
+ // Look for single part arguments (no comma)
1495
+ for (const arg of args) {
1496
+ if (!arg.startsWith('--') && !arg.includes('=') && arg.length > 0) {
1497
+ return [arg.trim()];
1498
+ }
1499
+ }
1500
+
1501
+ return null;
1502
+ }
1503
+
1495
1504
  // Main execution
1496
1505
  async function main() {
1497
1506
  const args = process.argv.slice(2);
1498
-
1507
+
1499
1508
  // Handle settings commands
1500
1509
  if (handleSettingsCommand(args)) {
1501
1510
  return;
1502
1511
  }
1503
-
1512
+
1513
+ // Check for CLI mode (specific parts requested)
1514
+ const cliParts = parseCLIMode(args);
1515
+ if (cliParts) {
1516
+ // Validate that all requested parts exist
1517
+ const validParts = cliParts.filter(part => infoFunctions[part]);
1518
+ const invalidParts = cliParts.filter(part => !infoFunctions[part]);
1519
+
1520
+ if (invalidParts.length > 0) {
1521
+ console.error(`Invalid parts: ${invalidParts.join(', ')}`);
1522
+ console.error(`Available parts: ${Object.keys(infoFunctions).join(', ')}`);
1523
+ process.exit(1);
1524
+ }
1525
+
1526
+ if (validParts.length === 0) {
1527
+ console.error('No valid parts specified');
1528
+ process.exit(1);
1529
+ }
1530
+
1531
+ // Create custom display order with the requested parts
1532
+ const customDisplayOrder = [validParts];
1533
+ await displaySystemInfo(customDisplayOrder);
1534
+ return;
1535
+ }
1536
+
1504
1537
  // Check for --install argument
1505
1538
  if (args.includes('--install')) {
1506
1539
  installShellGreeting();
1507
1540
  return;
1508
1541
  }
1509
-
1542
+
1510
1543
  // Check for --single-line argument
1511
1544
  if (args.includes('--single-line')) {
1512
1545
  const settings = loadSettings();
@@ -1514,7 +1547,7 @@ async function main() {
1514
1547
  await displaySystemInfo();
1515
1548
  return;
1516
1549
  }
1517
-
1550
+
1518
1551
  // Check for --multi-line argument
1519
1552
  if (args.includes('--multi-line')) {
1520
1553
  const settings = loadSettings();
@@ -1522,7 +1555,7 @@ async function main() {
1522
1555
  await displaySystemInfo();
1523
1556
  return;
1524
1557
  }
1525
-
1558
+
1526
1559
  // Check for --help argument
1527
1560
  if (args.includes('--help') || args.includes('-h')) {
1528
1561
  console.log(`
@@ -1530,6 +1563,7 @@ System Info Script - Node.js Version
1530
1563
 
1531
1564
  Usage:
1532
1565
  node systeminfo.js [options]
1566
+ node systeminfo.js <part1,part2,...> # CLI mode: show specific parts only
1533
1567
 
1534
1568
  Options:
1535
1569
  --help, -h Show this help message
@@ -1541,7 +1575,10 @@ Options:
1541
1575
  --set <key> <value> Set a configuration value (use dot notation)
1542
1576
 
1543
1577
  Examples:
1544
- node systeminfo.js
1578
+ node systeminfo.js # Show all info (default)
1579
+ node systeminfo.js cpu,os # Show only CPU and OS info
1580
+ node systeminfo.js user,hostname,ip # Show user, hostname, and IP
1581
+ node systeminfo.js disk_used # Show only disk usage
1545
1582
  node systeminfo.js --install
1546
1583
  node systeminfo.js --set display.show_emojis false
1547
1584
  node systeminfo.js --set colors.user blue
@@ -1591,17 +1628,17 @@ Linux-specific features:
1591
1628
  `);
1592
1629
  return;
1593
1630
  }
1594
-
1631
+
1595
1632
  // Display system info
1596
1633
  await displaySystemInfo();
1597
1634
  }
1598
1635
 
1599
1636
  // Run the script
1600
1637
  // if (import.meta.url === `file://${process.argv[1]}`) {
1601
- main().catch(error => {
1602
- console.error('Error:', error.message);
1603
- process.exit(1);
1604
- });
1638
+ main().catch(error => {
1639
+ console.error('Error:', error.message);
1640
+ process.exit(1);
1641
+ });
1605
1642
  // }
1606
1643
 
1607
1644
  export { displaySystemInfo, installShellGreeting };