about-system 0.0.41 → 0.0.46

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.
@@ -50,7 +50,12 @@ export function os_info(context: InfoContext): string {
50
50
  osName = `Windows ${release}`;
51
51
  }
52
52
  } else if (IS_MAC) {
53
- osName = `macOS ${release}`;
53
+ const productName = execCommand("sw_vers -productName");
54
+ const productVersion = execCommand("sw_vers -productVersion");
55
+ osName =
56
+ productName && productVersion
57
+ ? `${productName} ${productVersion}`
58
+ : `macOS ${release}`;
54
59
  } else if (IS_LINUX) {
55
60
  try {
56
61
  const osRelease = fs.readFileSync("/etc/os-release", "utf8");
@@ -119,6 +124,14 @@ export function device(context: InfoContext): string {
119
124
  return device;
120
125
  }
121
126
  } catch {}
127
+ } else if (IS_MAC) {
128
+ const profile = execCommand("system_profiler SPHardwareDataType");
129
+ const nameMatch = profile.match(/Model Name:\s*(.+)/);
130
+ if (nameMatch) {
131
+ const device = nameMatch[1].trim();
132
+ setCachedValue(context.cache, "device", device);
133
+ return device;
134
+ }
122
135
  } else if (IS_LINUX) {
123
136
  try {
124
137
  if (commandExists("getprop")) {
@@ -5,13 +5,13 @@
5
5
 
6
6
  import os from "os";
7
7
  import type { InfoContext } from "../types/internal-types";
8
- import { IS_LINUX } from "../utils/platform";
8
+ import { IS_LINUX, IS_MAC } from "../utils/platform";
9
9
  import { execCommand } from "../utils/command";
10
10
  import { getCachedValue, setCachedValue } from "../cache/cache";
11
11
 
12
12
  /**
13
13
  * Gets the highest CPU-consuming process
14
- * Uses ps command to find top process by CPU usage (Linux only)
14
+ * Uses ps command to find top process by CPU usage (Linux/macOS only)
15
15
  * @param context - Info context with cache
16
16
  * @returns Process info as "percentage processname" or empty string
17
17
  * @example "8% firefox", "15% chrome", "3% systemd"
@@ -33,6 +33,22 @@ export function top_process(context: InfoContext): string {
33
33
  return result;
34
34
  }
35
35
  } catch {}
36
+ } else if (IS_MAC) {
37
+ try {
38
+ // -c gives the short command name, -r sorts by %CPU descending
39
+ const ps = execCommand("ps -Aceo pcpu,comm -r");
40
+ const lines = ps.split("\n").filter((line) => line.trim());
41
+ if (lines.length > 1) {
42
+ const topProcess = lines[1].trim().split(/\s+/);
43
+ const cpuValue = Math.round(parseFloat(topProcess[0]));
44
+ const process = topProcess.slice(1).join(" ");
45
+ if (!isNaN(cpuValue) && process) {
46
+ const result = `${cpuValue}% ${process}`;
47
+ setCachedValue(context.cache, "top_process", result);
48
+ return result;
49
+ }
50
+ }
51
+ } catch {}
36
52
  }
37
53
 
38
54
  setCachedValue(context.cache, "top_process", "");
@@ -54,12 +70,12 @@ export function uptime(): string {
54
70
 
55
71
  /**
56
72
  * Gets number of logged in users
57
- * Uses who command to count active user sessions (Linux only)
73
+ * Uses who command to count active user sessions (Linux/macOS only)
58
74
  * @returns User count with "users" suffix or empty string
59
75
  * @example "3 users", "1 users"
60
76
  */
61
77
  export function users_logged_in(): string {
62
- if (!IS_LINUX) return "";
78
+ if (!IS_LINUX && !IS_MAC) return "";
63
79
 
64
80
  try {
65
81
  const who = execCommand("who");
@@ -37,6 +37,7 @@ export const DEFAULT_SETTINGS = {
37
37
  ["user", "hostname", "os", "device", "kernel", "cpu", "gpu", "bench"],
38
38
  [
39
39
  "disk_used",
40
+ "disk_size",
40
41
  "ram_used",
41
42
  "top_process",
42
43
  "uptime",
@@ -44,13 +45,14 @@ export const DEFAULT_SETTINGS = {
44
45
  "battery",
45
46
  "load_average",
46
47
  ],
47
- ["ip", "iplocal", "city", "domain", "isp"],
48
+ ["ip", "iplocal", "city"],
48
49
  ["shell", "services_running", "pacman", "containers"],
49
50
  ],
50
51
  colors: {
51
52
  user: "red",
52
53
  hostname: "orange",
53
54
  disk_used: "purple",
55
+ disk_size: "purple",
54
56
  ram_used: "yellow",
55
57
  top_process: "magenta",
56
58
  uptime: "cyan",
@@ -97,6 +99,7 @@ export const DEFAULT_SETTINGS = {
97
99
  shell: "🐚 ",
98
100
  pacman: "🚀 ",
99
101
  disk_used: "📁 ",
102
+ disk_size: "💽 ",
100
103
  ram_used: "💾 ",
101
104
  top_process: "🔝 ",
102
105
  uptime: "⏱️ ",
@@ -131,6 +134,7 @@ export const DEFAULT_SETTINGS = {
131
134
  shell: "Shell",
132
135
  pacman: "Packages",
133
136
  disk_used: "Disk",
137
+ disk_size: "Disk Size",
134
138
  ram_used: "RAM",
135
139
  top_process: "Top",
136
140
  uptime: "Uptime",
@@ -150,7 +154,7 @@ export const DEFAULT_SETTINGS = {
150
154
  },
151
155
  display: {
152
156
  show_emojis: true,
153
- single_line: false,
157
+ single_line: true,
154
158
  line_wrap_length: process?.stdout?.columns || 100,
155
159
  },
156
160
  network: {
@@ -168,6 +172,7 @@ export interface Settings {
168
172
  labels: Record<string, string>;
169
173
  display: {
170
174
  show_emojis: boolean;
175
+ /** true: print one continuous line and let the terminal soft-wrap it; false: hard-wrap at line_wrap_length */
171
176
  single_line: boolean;
172
177
  line_wrap_length: number;
173
178
  };
@@ -3,15 +3,17 @@
3
3
  * @module info/software
4
4
  */
5
5
 
6
+ import os from "os";
6
7
  import process from "process";
7
8
  import type { InfoContext } from "../types/internal-types";
8
- import { IS_LINUX } from "../utils/platform";
9
+ import { IS_WINDOWS } from "../utils/platform";
9
10
  import { execCommand, commandExists } from "../utils/command";
10
11
  import { getCachedValue, setCachedValue } from "../cache/cache";
11
12
 
12
13
  /**
13
14
  * Gets the current shell name
14
- * Uses ps command to find parent process shell (Linux/Unix only)
15
+ * Uses the user's login shell (macOS/Linux), falls back to ps for the
16
+ * parent process shell
15
17
  * @returns Shell name or empty string on Windows
16
18
  * @example "bash", "zsh", "fish", "nu"
17
19
  */
@@ -19,7 +21,16 @@ export function shell(context: InfoContext): string {
19
21
  const cached = getCachedValue(context.cache, "shell");
20
22
  if (cached !== null) return cached;
21
23
 
22
- if (IS_LINUX) {
24
+ if (!IS_WINDOWS) {
25
+ try {
26
+ const loginShell = os.userInfo().shell;
27
+ if (loginShell) {
28
+ const shellName = loginShell.split("/").pop() as string;
29
+ setCachedValue(context.cache, "shell", shellName);
30
+ return shellName;
31
+ }
32
+ } catch {}
33
+
23
34
  try {
24
35
  const ppid = process.ppid;
25
36
  const shellName = execCommand(`ps -p ${ppid} -o comm=`).split("/").pop();
@@ -47,6 +58,7 @@ export function packages(context: InfoContext): string {
47
58
 
48
59
  const commands = [
49
60
  "apt",
61
+ "brew",
50
62
  "npm",
51
63
  "uv",
52
64
  "docker",
@@ -6,17 +6,25 @@
6
6
  import fs from "fs";
7
7
  import os from "os";
8
8
  import type { InfoContext } from "../types/internal-types";
9
- import { IS_LINUX } from "../utils/platform";
9
+ import { IS_LINUX, IS_MAC } from "../utils/platform";
10
10
  import { execCommand, commandExists } from "../utils/command";
11
11
  import { getCachedValue, setCachedValue } from "../cache/cache";
12
12
 
13
13
  /**
14
14
  * Gets system load averages
15
- * Reads 1, 5, and 15 minute load averages from /proc/loadavg (Linux only)
15
+ * Reads 1, 5, and 15 minute load averages from /proc/loadavg (Linux) or
16
+ * os.loadavg() (macOS)
16
17
  * @returns Space-separated load averages (1m 5m 15m) or empty string
17
18
  * @example "0.52 0.58 0.59", "2.10 1.95 1.88"
18
19
  */
19
20
  export function load_average(context: InfoContext): string {
21
+ if (IS_MAC) {
22
+ return os
23
+ .loadavg()
24
+ .map((n) => n.toFixed(2))
25
+ .join(" ");
26
+ }
27
+
20
28
  if (!IS_LINUX) return "";
21
29
 
22
30
  try {
@@ -38,6 +46,22 @@ export function battery(context: InfoContext): string {
38
46
  const cached = getCachedValue(context.cache, "battery");
39
47
  if (cached !== null) return cached;
40
48
 
49
+ if (IS_MAC) {
50
+ try {
51
+ const batt = execCommand("pmset -g batt");
52
+ const percentMatch = batt.match(/(\d+)%/);
53
+ if (percentMatch) {
54
+ const isCharging = /;\s*(charging|charged);/i.test(batt);
55
+ const result = `${percentMatch[1]}%${isCharging ? "+" : ""}`;
56
+ setCachedValue(context.cache, "battery", result);
57
+ return result;
58
+ }
59
+ } catch {}
60
+
61
+ setCachedValue(context.cache, "battery", "");
62
+ return "";
63
+ }
64
+
41
65
  if (!IS_LINUX) {
42
66
  setCachedValue(context.cache, "battery", "");
43
67
  return "";
@@ -68,7 +92,9 @@ export function battery(context: InfoContext): string {
68
92
 
69
93
  /**
70
94
  * Gets system temperature in Celsius
71
- * Reads from thermal zone or hwmon sensors (Linux only)
95
+ * Reads from thermal zone or hwmon sensors (Linux), or from the
96
+ * `osx-cpu-temp` CLI (macOS, if installed via `brew install osx-cpu-temp`) -
97
+ * macOS has no unprivileged API for this, so nothing is reported without it
72
98
  * @param context - Info context with cache
73
99
  * @returns Temperature with °C suffix or empty string
74
100
  * @example "45°C", "62°C"
@@ -77,6 +103,26 @@ export function temperature(context: InfoContext): string {
77
103
  const cached = getCachedValue(context.cache, "temperature");
78
104
  if (cached !== null) return cached;
79
105
 
106
+ if (IS_MAC) {
107
+ if (commandExists("osx-cpu-temp")) {
108
+ try {
109
+ const output = execCommand("osx-cpu-temp");
110
+ const match = output.match(/([\d.]+)\s*°?C/);
111
+ if (match) {
112
+ const tempC = Math.round(parseFloat(match[1]));
113
+ if (tempC > 0 && tempC < 150) {
114
+ const result = `${tempC}°C`;
115
+ setCachedValue(context.cache, "temperature", result);
116
+ return result;
117
+ }
118
+ }
119
+ } catch {}
120
+ }
121
+
122
+ setCachedValue(context.cache, "temperature", "");
123
+ return "";
124
+ }
125
+
80
126
  if (!IS_LINUX) {
81
127
  setCachedValue(context.cache, "temperature", "");
82
128
  return "";
@@ -118,6 +164,24 @@ export function services_running(context: InfoContext): string {
118
164
  const cached = getCachedValue(context.cache, "services_running");
119
165
  if (cached !== null) return cached;
120
166
 
167
+ if (IS_MAC) {
168
+ try {
169
+ const services = execCommand("launchctl list");
170
+ const serviceCount = services
171
+ .split("\n")
172
+ .filter((line) => line.trim() && !line.startsWith("PID")).length;
173
+
174
+ if (serviceCount > 0) {
175
+ const result = `${serviceCount} services`;
176
+ setCachedValue(context.cache, "services_running", result);
177
+ return result;
178
+ }
179
+ } catch {}
180
+
181
+ setCachedValue(context.cache, "services_running", "");
182
+ return "";
183
+ }
184
+
121
185
  if (!IS_LINUX) {
122
186
  setCachedValue(context.cache, "services_running", "");
123
187
  return "";
@@ -21,6 +21,7 @@ import { user, hostname, os_info, kernel, device } from "./info/platform";
21
21
  import { cpu, gpu, screen_resolution, bench, cpu_bench_info, gpu_bench, gpu_bench_info } from "./info/hardware";
22
22
  import {
23
23
  disk_used,
24
+ disk_size,
24
25
  ram_used,
25
26
  memory_available,
26
27
  swap_used,
@@ -64,6 +65,7 @@ const CACHE_DURATION = {
64
65
  containers: 5 * 60 * 1000,
65
66
  top_process: 5 * 1000,
66
67
  disk_used: 60 * 1000,
68
+ disk_size: 60 * 1000,
67
69
  ram_used: 10 * 1000,
68
70
  services_running: 5 * 60 * 1000,
69
71
  temperature: 30 * 1000,
@@ -200,6 +202,7 @@ export const infoFunctions = {
200
202
  gpu_bench,
201
203
  gpu_bench_info,
202
204
  disk_used,
205
+ disk_size,
203
206
  ram_used,
204
207
  top_process,
205
208
  uptime,
@@ -129,8 +129,8 @@ export interface SystemInfo {
129
129
  * Empty string if CPU not found or benchmark data unavailable
130
130
  *
131
131
  * @example
132
- * - "💪 37.9k #1" (top performing CPU)
133
- * - "💪 20.5k #68" (mid-range CPU)
132
+ * - "37.9k #1" (top performing CPU)
133
+ * - "20.5k #68" (mid-range CPU)
134
134
  * - "" (CPU not in benchmark database)
135
135
  */
136
136
  bench: string;
@@ -156,8 +156,8 @@ export interface SystemInfo {
156
156
  * Empty string if GPU not found or benchmark data unavailable
157
157
  *
158
158
  * @example
159
- * - "💪 37.9k #1" (top performing GPU)
160
- * - "💪 20.5k #68" (mid-range GPU)
159
+ * - "37.9k #1" (top performing GPU)
160
+ * - "20.5k #68" (mid-range GPU)
161
161
  * - "" (GPU not in benchmark database)
162
162
  */
163
163
  gpu_bench: string;
@@ -203,6 +203,18 @@ export interface SystemInfo {
203
203
  */
204
204
  disk_used: string;
205
205
 
206
+ /**
207
+ * Disk size (used/total) for each real disk
208
+ * Format: "used/total GB" when a single real disk is found, or
209
+ * "mount(used/total GB) ..." per disk when multiple are found
210
+ * Pseudo filesystems and small system/boot partitions (under 10GB) are
211
+ * excluded
212
+ * Empty string if unable to determine
213
+ *
214
+ * @example "256/512GB", "/(100/500GB) /Volumes/Backup(900/2000GB)"
215
+ */
216
+ disk_size: string;
217
+
206
218
  /**
207
219
  * Memory usage in gigabytes
208
220
  * Format: "used/total GB" showing current RAM consumption