about-system 0.0.12 → 0.0.15

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