about-system 0.0.4 → 0.0.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -101,7 +101,7 @@ npx about-system
101
101
 
102
102
  The script uses a JSON settings file located at:
103
103
  - **Linux/macOS**: `~/.config/systeminfo-settings.json`
104
- - **Windows**: `%APPDATA%\Local\systeminfo-settings.json`
104
+ - **Windows**: `%APPDATA%\systeminfo-settings.json`
105
105
 
106
106
  #### Settings Commands
107
107
 
package/package.json CHANGED
@@ -1,22 +1,31 @@
1
1
  {
2
2
  "name": "about-system",
3
- "version": "0.0.4",
3
+ "version": "0.0.8",
4
4
  "description": "A Node.js script to display key system information with emojis. Cross-platform support for Windows, macOS, and Linux with customizable output and caching.",
5
- "main": "about-system.js",
5
+ "main": "src/about-system.js",
6
6
  "bin": {
7
- "about-system": "./about-system.js"
7
+ "about-system": "./src/about-system.js",
8
+ "test-speed": "./src/test-speed-cloudflare.js"
9
+ },
10
+ "type": "module",
11
+ "exports": {
12
+ ".": {
13
+ "types": "./src/systeminfo-types.d.ts",
14
+ "import": "./src/about-system.js"
15
+ }
8
16
  },
9
17
  "scripts": {
10
18
  "ship": "npx standard-version --release-as patch; npm publish",
11
- "start": "node about-system.js",
12
- "install-greeting": "node about-system.js --install",
13
- "show-settings": "node about-system.js --settings-show",
14
- "reset-settings": "node about-system.js --settings-reset",
15
- "clear-cache": "node about-system.js --cache-clear",
16
- "help": "node about-system.js --help"
19
+ "start": "node src/about-system.js",
20
+ "test-speed": "node src/test-speed-cloudflare.js",
21
+ "install-greeting": "node src/about-system.js --install",
22
+ "show-settings": "node src/about-system.js --settings-show",
23
+ "reset-settings": "node src/about-system.js --settings-reset",
24
+ "clear-cache": "node src/about-system.js --cache-clear",
25
+ "help": "node src/about-system.js --help"
17
26
  },
18
27
  "keywords": [
19
- "about-system",
28
+ "src/about-system",
20
29
  "system",
21
30
  "information",
22
31
  "cli",
@@ -38,7 +47,7 @@
38
47
  },
39
48
  "homepage": "https://github.com/vtempest/server-shell-setup#readme",
40
49
  "files": [
41
- "about-system.js",
50
+ "src/about-system.js",
42
51
  "README.md",
43
52
  "package.json"
44
53
  ],
@@ -51,5 +60,8 @@
51
60
  "preferGlobal": true,
52
61
  "directories": {
53
62
  "bin": "."
63
+ },
64
+ "dependencies": {
65
+ "ora": "^8.2.0"
54
66
  }
55
67
  }
@@ -15,9 +15,8 @@
15
15
  * Network info (ip, city, domain, isp) is fetched from ipinfo.io
16
16
  * only if needed.
17
17
  *
18
- * Author: vtempest
19
- * Updated: 2025-09-01
20
- * License: MIT
18
+ * @author: vtempest
19
+ * @license: MIT
21
20
  */
22
21
 
23
22
  const os = require('os');
@@ -106,17 +105,7 @@ const DEFAULT_SETTINGS = {
106
105
  multiline: true,
107
106
  group_similar: true,
108
107
  single_line: false,
109
- line_wrap_length: (() => {
110
- try {
111
- const { execSync } = require('child_process');
112
- const size = execSync('stty size', { encoding: 'utf8' }).trim();
113
- const cols = parseInt(size.split(' ')[1]);
114
- console.log(cols)
115
- return cols > 0 ? cols : 100; // fallback to 100 if stty fails
116
- } catch (error) {
117
- return 100; // fallback to 100 if stty is not available
118
- }
119
- })()
108
+ line_wrap_length: process?.stdout?.columns || 100, // fallback to 80 if tput fails
120
109
  },
121
110
  advanced: {
122
111
  debug: false,
@@ -449,7 +438,26 @@ const infoFunctions = {
449
438
 
450
439
  let cpuName = '';
451
440
 
452
- if (IS_LINUX) {
441
+ if (IS_WINDOWS) {
442
+ // Windows-specific CPU detection using WMIC
443
+ try {
444
+ const wmic = execCommand('wmic cpu get name /format:list');
445
+ const nameMatch = wmic.match(/Name=(.+)/);
446
+ if (nameMatch) {
447
+ cpuName = nameMatch[1].trim();
448
+ }
449
+ } catch {}
450
+
451
+ // Fallback to PowerShell if WMIC fails
452
+ if (!cpuName) {
453
+ try {
454
+ const ps = execCommand('powershell.exe -Command "Get-WmiObject -Class Win32_Processor | Select-Object -ExpandProperty Name"');
455
+ if (ps.trim()) {
456
+ cpuName = ps.trim();
457
+ }
458
+ } catch {}
459
+ }
460
+ } else if (IS_LINUX) {
453
461
  // Try lscpu first (like bash script)
454
462
  try {
455
463
  const lscpu = execCommand('lscpu');
@@ -477,7 +485,7 @@ const infoFunctions = {
477
485
  // Use Node.js os module for other platforms
478
486
  const cpus = os.cpus();
479
487
  if (cpus.length > 0) {
480
- cpuName = cpus[0].model;
488
+ cpuName = cpus[0].model.trim().replace(/[\r\n]+/g, ' ');
481
489
  }
482
490
  }
483
491
 
@@ -487,7 +495,7 @@ const infoFunctions = {
487
495
  }
488
496
 
489
497
  //remove "with ..." from cpuName
490
- cpuName = cpuName.replace(/with .*/, '');
498
+ cpuName = cpuName.trim().replace(/with .*/, '');
491
499
 
492
500
  const color = colors[settings.colors.cpu] || colors.orange;
493
501
  const emoji = settings.display.show_emojis ? '📈 ' : '';
@@ -500,7 +508,36 @@ const infoFunctions = {
500
508
  const cached = getCachedValue(this.cache, 'gpu', settings);
501
509
  if (cached) return cached;
502
510
 
503
- if (IS_LINUX) {
511
+ if (IS_WINDOWS) {
512
+ try {
513
+ // Get GPU information using WMIC
514
+ const wmic = execCommand('wmic path win32_VideoController get name /format:list');
515
+ const nameMatch = wmic.match(/Name=(.+)/);
516
+ if (nameMatch) {
517
+ const gpu = nameMatch[1].trim();
518
+ if (gpu && gpu !== '' && !gpu.includes('Microsoft Basic')) {
519
+ const color = colors[settings.colors.gpu] || colors.yellow;
520
+ const emoji = settings.display.show_emojis ? '🎮 ' : '';
521
+ const result = `${color}${emoji}${gpu}`;
522
+ setCachedValue(this.cache, 'gpu', result);
523
+ return result;
524
+ }
525
+ }
526
+ } catch {}
527
+
528
+ // Fallback using PowerShell
529
+ try {
530
+ const ps = execCommand('powershell.exe -Command "Get-WmiObject -Class Win32_VideoController | Where-Object {$_.Name -notlike \'*Microsoft Basic*\'} | Select-Object -First 1 -ExpandProperty Name"');
531
+ if (ps.trim()) {
532
+ const gpu = ps.trim();
533
+ const color = colors[settings.colors.gpu] || colors.yellow;
534
+ const emoji = settings.display.show_emojis ? '🎮 ' : '';
535
+ const result = `${color}${emoji}${gpu}`;
536
+ setCachedValue(this.cache, 'gpu', result);
537
+ return result;
538
+ }
539
+ } catch {}
540
+ } else if (IS_LINUX) {
504
541
  try {
505
542
  const lspci = execCommand('lspci');
506
543
  // Look for VGA and specific GPU brands like the bash script
@@ -536,7 +573,40 @@ const infoFunctions = {
536
573
  const cached = getCachedValue(this.cache, 'disk_used', settings);
537
574
  if (cached) return cached;
538
575
 
539
- if (IS_LINUX) {
576
+ if (IS_WINDOWS) {
577
+ try {
578
+ // Get disk usage for C: drive using PowerShell
579
+ const ps = execCommand('powershell.exe -Command "Get-WmiObject -Class Win32_LogicalDisk -Filter \'DeviceID="C:"\' | Select-Object @{Name=\'PercentFree\';Expression={[math]::Round((($_.FreeSpace / $_.Size) * 100), 0)}} | Select-Object -ExpandProperty PercentFree"');
580
+ if (ps.trim()) {
581
+ const percentFree = parseInt(ps.trim());
582
+ const percentUsed = 100 - percentFree;
583
+ const color = colors[settings.colors.disk_used] || colors.purple;
584
+ const emoji = settings.display.show_emojis ? '📁 ' : '';
585
+ const result = `${color}${emoji}${percentUsed}%`;
586
+ setCachedValue(this.cache, 'disk_used', result);
587
+ return result;
588
+ }
589
+ } catch {}
590
+
591
+ // Fallback using WMIC
592
+ try {
593
+ const wmic = execCommand('wmic logicaldisk where "DeviceID=\'C:\'" get Size,FreeSpace /format:list');
594
+ const sizeMatch = wmic.match(/Size=(\d+)/);
595
+ const freeMatch = wmic.match(/FreeSpace=(\d+)/);
596
+
597
+ if (sizeMatch && freeMatch) {
598
+ const size = parseInt(sizeMatch[1]);
599
+ const free = parseInt(freeMatch[1]);
600
+ const used = size - free;
601
+ const percentUsed = Math.round((used / size) * 100);
602
+ const color = colors[settings.colors.disk_used] || colors.purple;
603
+ const emoji = settings.display.show_emojis ? '📁 ' : '';
604
+ const result = `${color}${emoji}${percentUsed}%`;
605
+ setCachedValue(this.cache, 'disk_used', result);
606
+ return result;
607
+ }
608
+ } catch {}
609
+ } else if (IS_LINUX) {
540
610
  try {
541
611
  const df = execCommand('df -h');
542
612
  let diskUsage = '';
@@ -628,7 +698,44 @@ const infoFunctions = {
628
698
  const cached = getCachedValue(this.cache, 'top_process', settings);
629
699
  if (cached) return cached;
630
700
 
631
- if (IS_LINUX) {
701
+ if (IS_WINDOWS) {
702
+ try {
703
+ // Get top process using PowerShell performance counters
704
+ const ps = execCommand('powershell.exe -Command "Get-Counter \'\\Process(*)\\% Processor Time\' | Select-Object -ExpandProperty CounterSamples | Where-Object {$_.InstanceName -notin @(\'_Total\', \'Idle\')} | Sort-Object CookedValue -Descending | Select-Object -First 1 | Select-Object InstanceName, @{Name=\'CPU%\'; Expression={[math]::Round($_.CookedValue, 1)}}"');
705
+ const lines = ps.split('\n').filter(line => line.trim());
706
+ if (lines.length > 0) {
707
+ const parts = lines[0].trim().split(/\s+/);
708
+ if (parts.length >= 2) {
709
+ const processName = parts[0];
710
+ const cpuPercent = parts[1];
711
+ const color = colors[settings.colors.top_process] || colors.magenta;
712
+ const emoji = settings.display.show_emojis ? '🔝 ' : '';
713
+ const result = `${color}${emoji}${cpuPercent}% ${processName}`;
714
+ setCachedValue(this.cache, 'top_process', result);
715
+ return result;
716
+ }
717
+ }
718
+ } catch {}
719
+
720
+ // Fallback using tasklist
721
+ try {
722
+ const tasklist = execCommand('tasklist /fo csv | findstr /v "Image Name" | sort /r /+5');
723
+ const lines = tasklist.split('\n').filter(line => line.trim());
724
+ if (lines.length > 0) {
725
+ const line = lines[0];
726
+ const parts = line.split(',');
727
+ if (parts.length >= 5) {
728
+ const processName = parts[0].replace(/"/g, '').split('.')[0];
729
+ const memoryUsage = parts[4].replace(/"/g, '').replace(/[,\s]/g, '');
730
+ const color = colors[settings.colors.top_process] || colors.magenta;
731
+ const emoji = settings.display.show_emojis ? '🔝 ' : '';
732
+ const result = `${color}${emoji}${memoryUsage}KB ${processName}`;
733
+ setCachedValue(this.cache, 'top_process', result);
734
+ return result;
735
+ }
736
+ }
737
+ } catch {}
738
+ } else if (IS_LINUX) {
632
739
  try {
633
740
  const ps = execCommand('ps -eo pcpu,comm --sort=-%cpu --no-headers');
634
741
  const lines = ps.split('\n');
@@ -664,7 +771,36 @@ const infoFunctions = {
664
771
  const cached = getCachedValue(this.cache, 'device', settings);
665
772
  if (cached) return cached;
666
773
 
667
- if (IS_LINUX) {
774
+ if (IS_WINDOWS) {
775
+ try {
776
+ // Get computer model using WMIC
777
+ const wmic = execCommand('wmic csproduct get name /format:list');
778
+ const nameMatch = wmic.match(/Name=(.+)/);
779
+ if (nameMatch) {
780
+ const device = nameMatch[1].trim();
781
+ if (device && device !== '') {
782
+ const color = colors[settings.colors.device] || colors.blue;
783
+ const emoji = settings.display.show_emojis ? '💻 ' : '';
784
+ const result = `${color}${emoji}${device}`;
785
+ setCachedValue(this.cache, 'device', result);
786
+ return result;
787
+ }
788
+ }
789
+ } catch {}
790
+
791
+ // Fallback using PowerShell
792
+ try {
793
+ const ps = execCommand('powershell.exe -Command "Get-WmiObject -Class Win32_ComputerSystem | Select-Object -ExpandProperty Model"');
794
+ if (ps.trim()) {
795
+ const device = ps.trim();
796
+ const color = colors[settings.colors.device] || colors.blue;
797
+ const emoji = settings.display.show_emojis ? '💻 ' : '';
798
+ const result = `${color}${emoji}${device}`;
799
+ setCachedValue(this.cache, 'device', result);
800
+ return result;
801
+ }
802
+ } catch {}
803
+ } else if (IS_LINUX) {
668
804
  try {
669
805
  // Check for Android
670
806
  if (commandExists('getprop')) {
@@ -1250,17 +1386,15 @@ function handleSettingsCommand(args) {
1250
1386
  return true;
1251
1387
  }
1252
1388
 
1253
- const cacheResetIndex = args.indexOf('--cache-clear');
1389
+ const cacheResetIndex = args.indexOf('--refresh');
1254
1390
  if (cacheResetIndex !== -1) {
1255
1391
  try {
1256
1392
  if (fs.existsSync(CACHE_FILE)) {
1257
1393
  fs.unlinkSync(CACHE_FILE);
1258
1394
  }
1259
- console.log('Cache cleared');
1260
1395
  } catch (error) {
1261
1396
  console.error('Error clearing cache:', error.message);
1262
1397
  }
1263
- return true;
1264
1398
  }
1265
1399
 
1266
1400
  const setIndex = args.indexOf('--set');
@@ -1440,7 +1574,7 @@ Options:
1440
1574
  --settings-init Initialize settings file with defaults
1441
1575
  --settings-show Display current settings
1442
1576
  --settings-reset Reset settings to defaults
1443
- --cache-clear Clear the cache file
1577
+ --refresh Clear the cache file
1444
1578
  --set <key> <value> Set a configuration value (use dot notation)
1445
1579
 
1446
1580
  Examples:
@@ -0,0 +1,51 @@
1
+ import ora from 'ora';
2
+ import { spawn, execSync } from 'child_process';
3
+
4
+
5
+ /**
6
+ * Tests the download speed in MB/s using Cloudflare's speed test.
7
+ * Optionally displays a spinner message during the test.
8
+ * Their official package is @cloudflare/speedtest and it shows errors and too much output.
9
+ * This script uses a process to hide the errors and give speed in MB/s via CLI or import.
10
+ * @param {boolean} [showMessage=true] - Whether to show explanation message while testing.
11
+ * @returns {Promise<string>} The measured download speed in MB/s as a string (e.g., "12.3").
12
+ *
13
+ * @example
14
+ * import { testDownloadSpeed } from './test-speed-cloudflare.js';
15
+ * const downloadSpeed = await testDownloadSpeed(false);
16
+ * console.log(downloadSpeed); // e.g., "12.3"
17
+ */
18
+ export async function testDownloadSpeed(showMessage = true) {
19
+ var spinner;
20
+ if (showMessage)
21
+ spinner = ora('Testing download speed in MB/s using Cloudflare, runs for 1 minute').start();
22
+
23
+ // globally install @cloudflare/speedtest
24
+ await execSync('npm i -g @cloudflare/speedtest');
25
+
26
+ const result = await new Promise((resolve) => {
27
+ const child = spawn('node', [
28
+ '-e',
29
+ "import SpeedTest from '@cloudflare/speedtest'; new SpeedTest({iterations: 1}).onFinish = r => console.log((r.getDownloadBandwidth() / 8388608).toFixed(1))"
30
+ ]);
31
+
32
+ let output = '';
33
+ child.stdout.on('data', (data) => {
34
+ output += data.toString();
35
+ });
36
+ // Extract last number from output
37
+ child.on('close', () => {
38
+ resolve(output.trim().split('\n').pop().match(/(\d+(\.\d+)?)/)?.[0]);
39
+ });
40
+
41
+ });
42
+
43
+ if (showMessage) spinner.succeed(result + ' MB/s');
44
+ return result;
45
+ }
46
+
47
+ // try{
48
+ // run if file is executed directly
49
+ // if (process?.env.npm_lifecycle_event?.length > 0 || import.meta.url === `file://${process.argv[1]}` || import.meta.url === process.argv[1] || import.meta.url === `file://${process.cwd()}/${process.argv[1]}`)
50
+ testDownloadSpeed();
51
+ // } catch { }