about-system 0.0.40 → 0.0.45

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.
@@ -15,7 +15,7 @@ declare function battery(context: InfoContext): string;
15
15
  * Uses fuzzy matching to find similar CPU models
16
16
  * @param context - Info context with cache
17
17
  * @returns Benchmark info with score and rank, or empty string
18
- * @example "💪 37.9k #1", "💪 20.5k #68"
18
+ * @example "37.9k #1", "20.5k #68"
19
19
  */
20
20
  declare function bench(context: InfoContext): string;
21
21
 
@@ -102,9 +102,23 @@ declare function cpu_bench_info(context: InfoContext): string;
102
102
  */
103
103
  declare function device(context: InfoContext): string;
104
104
 
105
+ /**
106
+ * Gets disk size (used/total) for each real disk
107
+ * Uses `df -k` on Linux/macOS, filtering out pseudo filesystems, system/boot
108
+ * partitions (e.g. /boot, /System/Volumes/*), and anything under 10GB, since
109
+ * those aren't disks a user would care about. When exactly one real disk is
110
+ * found (the common case) the result omits the mount point; when multiple
111
+ * real disks are found (e.g. a data drive or external volume), each is
112
+ * labeled by its mount point.
113
+ * @param context - Info context with cache
114
+ * @returns Disk size as "used/total GB" or "mount(used/total GB) ..." or empty string
115
+ * @example "256/512GB", "/(100/500GB) /Volumes/Backup(900/2000GB)"
116
+ */
117
+ declare function disk_size(context: InfoContext): string;
118
+
105
119
  /**
106
120
  * Gets root filesystem disk usage percentage
107
- * Uses df command on Linux/Android
121
+ * Uses df command on Linux/Android/macOS
108
122
  * @param context - Info context with cache
109
123
  * @returns Percentage string or empty string
110
124
  * @example "45%", "78%"
@@ -134,6 +148,24 @@ export declare function getSystemInfo(options?: SystemInfoOptions): Promise<Syst
134
148
  */
135
149
  declare function gpu(context: InfoContext): string;
136
150
 
151
+ /**
152
+ * Gets GPU benchmark score and rank from Geekbench 6 data
153
+ * Uses fuzzy matching to find similar GPU models
154
+ * @param context - Info context with cache
155
+ * @returns Benchmark info with score and rank, or empty string
156
+ * @example "37.9k #1", "20.5k #68"
157
+ */
158
+ declare function gpu_bench(context: InfoContext): string;
159
+
160
+ /**
161
+ * Gets detailed GPU benchmark information from Geekbench 6 data
162
+ * Includes score, rank, and vendor detection
163
+ * @param context - Info context with cache
164
+ * @returns Detailed benchmark info with vendor, or empty string
165
+ * @example "Geekbench 6: 37.9k (Rank #1) - NVIDIA", "Geekbench 6: 20.5k (Rank #68) - AMD"
166
+ */
167
+ declare function gpu_bench_info(context: InfoContext): string;
168
+
137
169
  /**
138
170
  * Gets the system hostname
139
171
  * @returns Computer hostname/network name
@@ -167,7 +199,10 @@ export declare const infoFunctions: {
167
199
  gpu: typeof gpu;
168
200
  bench: typeof bench;
169
201
  cpu_bench_info: typeof cpu_bench_info;
202
+ gpu_bench: typeof gpu_bench;
203
+ gpu_bench_info: typeof gpu_bench_info;
170
204
  disk_used: typeof disk_used;
205
+ disk_size: typeof disk_size;
171
206
  ram_used: typeof ram_used;
172
207
  top_process: typeof top_process;
173
208
  uptime: typeof uptime;
@@ -244,7 +279,8 @@ declare function kernel(context: InfoContext): string;
244
279
 
245
280
  /**
246
281
  * Gets system load averages
247
- * Reads 1, 5, and 15 minute load averages from /proc/loadavg (Linux only)
282
+ * Reads 1, 5, and 15 minute load averages from /proc/loadavg (Linux) or
283
+ * os.loadavg() (macOS)
248
284
  * @returns Space-separated load averages (1m 5m 15m) or empty string
249
285
  * @example "0.52 0.58 0.59", "2.10 1.95 1.88"
250
286
  */
@@ -257,7 +293,8 @@ export declare function loadCache(): Cache_2;
257
293
 
258
294
  /**
259
295
  * Gets available memory in gigabytes
260
- * Reads MemAvailable from /proc/meminfo (Linux only)
296
+ * Reads MemAvailable from /proc/meminfo (Linux) or derives it from
297
+ * vm_stat's free+inactive pages (macOS)
261
298
  * @returns Available memory with "GB available" suffix or empty string
262
299
  * @example "12GB available", "4GB available"
263
300
  */
@@ -265,20 +302,23 @@ declare function memory_available(): string;
265
302
 
266
303
  /**
267
304
  * Gets mounted filesystem information
268
- * Lists non-system mount points with usage from df (Linux only)
269
- * Excludes /, /dev, /proc, and /sys mounts
305
+ * Lists non-system mount points with usage from df (Linux/macOS)
306
+ * On Linux, excludes /, /dev, /proc, /sys and internal /System/Volumes mounts.
307
+ * On macOS, APFS internal volumes (Data, VM, Preboot, Update, ...) all live
308
+ * under /System/Volumes and are not user-relevant, so only /Volumes (external
309
+ * disks, network shares, disk images) are reported.
270
310
  * @param context - Info context with cache
271
311
  * @returns Space-separated mount points with usage or empty string
272
- * @example "/home(45%) /mnt/data(78%)", "/media/usb(12%)"
312
+ * @example "/home(45%) /mnt/data(78%)", "/Volumes/Backup(78%)"
273
313
  */
274
314
  declare function mount_points(context: InfoContext): string;
275
315
 
276
316
  /**
277
317
  * Gets active network interface names
278
- * Lists non-loopback interfaces with IPv4 addresses (Linux only)
318
+ * Lists non-loopback interfaces with IPv4 addresses (Linux/macOS only)
279
319
  * @param context - Info context with cache
280
320
  * @returns Space-separated interface names or empty string
281
- * @example "eth0 wlan0", "enp0s3"
321
+ * @example "eth0 wlan0", "en0 en1"
282
322
  */
283
323
  declare function network_interfaces(context: InfoContext): string;
284
324
 
@@ -302,7 +342,7 @@ declare function packages(context: InfoContext): string;
302
342
 
303
343
  /**
304
344
  * Gets open TCP ports with service names
305
- * Uses lsof to find listening TCP ports (Linux only)
345
+ * Uses lsof to find listening TCP ports (Linux/macOS only)
306
346
  * @param context - Info context with cache
307
347
  * @returns Space-separated port+process pairs or empty string
308
348
  * @example "80http 443http 22ssh", "3000node 5432post"
@@ -324,8 +364,8 @@ declare function ram_used(context: InfoContext): string;
324
364
  export declare function saveCache(cache: Cache_2): void;
325
365
 
326
366
  /**
327
- * Gets screen resolution from X11 display
328
- * Uses xrandr command (Linux with X11/Xorg only)
367
+ * Gets screen resolution
368
+ * Uses xrandr on Linux (X11/Xorg only) or system_profiler on macOS
329
369
  * @returns Resolution in WIDTHxHEIGHT format or empty string
330
370
  * @example "1920x1080", "2560x1440", "3840x2160"
331
371
  */
@@ -342,7 +382,8 @@ declare function services_running(context: InfoContext): string;
342
382
 
343
383
  /**
344
384
  * Gets the current shell name
345
- * Uses ps command to find parent process shell (Linux/Unix only)
385
+ * Uses the user's login shell (macOS/Linux), falls back to ps for the
386
+ * parent process shell
346
387
  * @returns Shell name or empty string on Windows
347
388
  * @example "bash", "zsh", "fish", "nu"
348
389
  */
@@ -350,7 +391,8 @@ declare function shell(context: InfoContext): string;
350
391
 
351
392
  /**
352
393
  * Gets swap memory usage
353
- * Calculates swap usage from /proc/meminfo (Linux only)
394
+ * Calculates swap usage from /proc/meminfo (Linux) or `sysctl vm.swapusage`
395
+ * (macOS)
354
396
  * @returns Swap usage as "percentage (size MB) swap" or empty string
355
397
  * @example "15% (512MB) swap", "0% (0MB) swap"
356
398
  */
@@ -358,7 +400,9 @@ declare function swap_used(): string;
358
400
 
359
401
  /**
360
402
  * Gets system temperature in Celsius
361
- * Reads from thermal zone or hwmon sensors (Linux only)
403
+ * Reads from thermal zone or hwmon sensors (Linux), or from the
404
+ * `osx-cpu-temp` CLI (macOS, if installed via `brew install osx-cpu-temp`) -
405
+ * macOS has no unprivileged API for this, so nothing is reported without it
362
406
  * @param context - Info context with cache
363
407
  * @returns Temperature with °C suffix or empty string
364
408
  * @example "45°C", "62°C"
@@ -367,7 +411,7 @@ declare function temperature(context: InfoContext): string;
367
411
 
368
412
  /**
369
413
  * Gets the highest CPU-consuming process
370
- * Uses ps command to find top process by CPU usage (Linux only)
414
+ * Uses ps command to find top process by CPU usage (Linux/macOS only)
371
415
  * @param context - Info context with cache
372
416
  * @returns Process info as "percentage processname" or empty string
373
417
  * @example "8% firefox", "15% chrome", "3% systemd"
@@ -389,7 +433,7 @@ declare function user(): string;
389
433
 
390
434
  /**
391
435
  * Gets number of logged in users
392
- * Uses who command to count active user sessions (Linux only)
436
+ * Uses who command to count active user sessions (Linux/macOS only)
393
437
  * @returns User count with "users" suffix or empty string
394
438
  * @example "3 users", "1 users"
395
439
  */
@@ -2,7 +2,7 @@ import "os";
2
2
  import "fs";
3
3
  import "https";
4
4
  import "path";
5
- import { g as m, i as r, l as p, s as n } from "./system-info-api-J8OqC6YU.js";
5
+ import { g as m, i as r, l as p, s as n } from "./system-info-api-CChFyamn.js";
6
6
  export {
7
7
  m as getSystemInfo,
8
8
  r as infoFunctions,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "about-system",
3
- "version": "0.0.40",
3
+ "version": "0.0.45",
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
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -56,9 +56,9 @@
56
56
  "license": "rights.institute/prosper",
57
57
  "repository": {
58
58
  "type": "git",
59
- "url": "https://github.com/OpenSourceAGI/starter-app-dev-tools/tree/master/packages/about-system-info"
59
+ "url": "https://github.com/OpenSourceAGI/dev-tools-starter-agent/tree/master/packages/about-system-info"
60
60
  },
61
- "homepage": "https://github.com/OpenSourceAGI/starter-app-dev-tools/tree/master/packages/about-system-info",
61
+ "homepage": "https://github.com/OpenSourceAGI/dev-tools-starter-agent/tree/master/packages/about-system-info",
62
62
  "files": [
63
63
  "dist/**/*",
64
64
  "src/**/*.ts",
@@ -6,7 +6,7 @@
6
6
  import os from "os";
7
7
  import fs from "fs";
8
8
  import type { InfoContext } from "../types/internal-types";
9
- import { IS_WINDOWS, IS_LINUX } from "../utils/platform";
9
+ import { IS_WINDOWS, IS_MAC, IS_LINUX } from "../utils/platform";
10
10
  import { execCommand } from "../utils/command";
11
11
  import { getCachedValue, setCachedValue } from "../cache/cache";
12
12
  import Fuse from "fuse.js";
@@ -97,54 +97,87 @@ export function gpu(context: InfoContext): string {
97
97
  if (cached !== null) return cached;
98
98
 
99
99
  if (IS_WINDOWS) {
100
+ const gpus: string[] = [];
101
+
100
102
  try {
101
103
  const wmic = execCommand(
102
104
  "wmic path win32_VideoController get name /format:list"
103
105
  );
104
- const nameMatch = wmic.match(/Name=(.+)/);
105
- if (nameMatch) {
106
- const gpu = nameMatch[1].trim();
107
- if (gpu && gpu !== "" && !gpu.includes("Microsoft Basic")) {
108
- setCachedValue(context.cache, "gpu", gpu);
109
- return gpu;
106
+ const nameMatches = wmic.matchAll(/Name=(.+)/g);
107
+ for (const match of nameMatches) {
108
+ const name = match[1].trim();
109
+ if (name && !name.includes("Microsoft Basic")) {
110
+ gpus.push(name);
110
111
  }
111
112
  }
112
113
  } catch {}
113
114
 
115
+ if (gpus.length === 0) {
116
+ try {
117
+ const ps = execCommand(
118
+ "powershell.exe -Command \"Get-WmiObject -Class Win32_VideoController | Where-Object {$_.Name -notlike '*Microsoft Basic*'} | Select-Object -ExpandProperty Name\""
119
+ );
120
+ if (ps.trim()) {
121
+ for (const line of ps.trim().split(/\r?\n/)) {
122
+ const name = line.trim();
123
+ if (name && !name.includes("Microsoft Basic")) {
124
+ gpus.push(name);
125
+ }
126
+ }
127
+ }
128
+ } catch {}
129
+ }
130
+
131
+ if (gpus.length > 0) {
132
+ const result = gpus.join(", ");
133
+ setCachedValue(context.cache, "gpu", result);
134
+ return result;
135
+ }
136
+ } else if (IS_MAC) {
114
137
  try {
115
- const ps = execCommand(
116
- "powershell.exe -Command \"Get-WmiObject -Class Win32_VideoController | Where-Object {$_.Name -notlike '*Microsoft Basic*'} | Select-Object -First 1 -ExpandProperty Name\""
138
+ const profile = execCommand("system_profiler SPDisplaysDataType");
139
+ const gpus = Array.from(profile.matchAll(/Chipset Model:\s*(.+)/g)).map(
140
+ (match) => match[1].trim()
117
141
  );
118
- if (ps.trim()) {
119
- const gpu = ps.trim();
120
- setCachedValue(context.cache, "gpu", gpu);
121
- return gpu;
142
+
143
+ if (gpus.length > 0) {
144
+ const result = gpus.join(", ");
145
+ setCachedValue(context.cache, "gpu", result);
146
+ return result;
122
147
  }
123
148
  } catch {}
124
149
  } else if (IS_LINUX) {
125
150
  try {
126
151
  const lspci = execCommand("lspci");
127
- const gpuMatch = lspci.match(
128
- /VGA.*?(RTX|GeForce|AMD|Intel|NVIDIA)[^\n]*/i
129
- );
130
- if (gpuMatch) {
131
- let gpu = gpuMatch[0];
132
-
133
- const bracketMatch = gpu.match(/\[([^\]]+)\]/);
134
- if (bracketMatch) {
135
- gpu = bracketMatch[1];
152
+ const gpus: string[] = [];
153
+ const classPattern = /(?:VGA compatible controller|3D controller|Display controller)/i;
154
+ const gpuPattern = /(?:NVIDIA|GeForce|RTX|GTX|Quadro|Tesla|AMD|ATI|Radeon|Navi|Vega|RX|Intel.*(?:Arc|UHD|Iris|HD Graphics))/i;
155
+
156
+ for (const line of lspci.split("\n")) {
157
+ if (!classPattern.test(line) || !gpuPattern.test(line)) continue;
158
+
159
+ let name: string;
160
+ const allBrackets = line.match(/\[([^\]]+)\]/g);
161
+ if (allBrackets && allBrackets.length > 0) {
162
+ const last = allBrackets[allBrackets.length - 1];
163
+ name = last.replace(/^\[|\]$/g, "");
136
164
  } else {
137
- gpu = gpu
138
- .replace(/^.*VGA[^:]*:\s*/, "")
139
- .replace(/\s*\(.*\)$/, "")
165
+ name = line
166
+ .replace(/^.*(?:VGA compatible controller|3D controller|Display controller):\s*/i, "")
167
+ .replace(/\s*\(rev [a-f0-9]+\)\s*$/i, "")
140
168
  .trim();
141
169
  }
142
170
 
143
- if (gpu) {
144
- setCachedValue(context.cache, "gpu", gpu);
145
- return gpu;
171
+ if (name && !gpus.includes(name)) {
172
+ gpus.push(name);
146
173
  }
147
174
  }
175
+
176
+ if (gpus.length > 0) {
177
+ const result = gpus.join(", ");
178
+ setCachedValue(context.cache, "gpu", result);
179
+ return result;
180
+ }
148
181
  } catch {}
149
182
  }
150
183
 
@@ -153,12 +186,23 @@ export function gpu(context: InfoContext): string {
153
186
  }
154
187
 
155
188
  /**
156
- * Gets screen resolution from X11 display
157
- * Uses xrandr command (Linux with X11/Xorg only)
189
+ * Gets screen resolution
190
+ * Uses xrandr on Linux (X11/Xorg only) or system_profiler on macOS
158
191
  * @returns Resolution in WIDTHxHEIGHT format or empty string
159
192
  * @example "1920x1080", "2560x1440", "3840x2160"
160
193
  */
161
194
  export function screen_resolution(): string {
195
+ if (IS_MAC) {
196
+ try {
197
+ const profile = execCommand("system_profiler SPDisplaysDataType");
198
+ const resolutionMatch = profile.match(/Resolution:\s*(\d+) x (\d+)/);
199
+ if (resolutionMatch) {
200
+ return `${resolutionMatch[1]}x${resolutionMatch[2]}`;
201
+ }
202
+ } catch {}
203
+ return "";
204
+ }
205
+
162
206
  if (!IS_LINUX) return "";
163
207
 
164
208
  try {
@@ -178,7 +222,7 @@ export function screen_resolution(): string {
178
222
  * Uses fuzzy matching to find similar CPU models
179
223
  * @param context - Info context with cache
180
224
  * @returns Benchmark info with score and rank, or empty string
181
- * @example "💪 37.9k #1", "💪 20.5k #68"
225
+ * @example "37.9k #1", "20.5k #68"
182
226
  */
183
227
  export function bench(context: InfoContext): string {
184
228
  const cached = getCachedValue(context.cache, "bench");
@@ -192,7 +236,7 @@ export function bench(context: InfoContext): string {
192
236
 
193
237
  try {
194
238
  let benchmarkPath: string;
195
- const benchmarkFile = "cpu-geekbench-1k.json";
239
+ const benchmarkFile = "cpu-geekbench.json";
196
240
 
197
241
  // Try multiple resolution strategies
198
242
  if (fs.existsSync(benchmarkFile)) {
@@ -232,7 +276,7 @@ export function bench(context: InfoContext): string {
232
276
  const match = results[0].item;
233
277
  const score = Math.round(match.score / 100) / 10;
234
278
  const rank = match.rank;
235
- const result = `💪 ${score}k #${rank}`;
279
+ const result = `${score}k #${rank}`;
236
280
  setCachedValue(context.cache, "bench", result);
237
281
  return result;
238
282
  }
@@ -263,7 +307,7 @@ export function cpu_bench_info(context: InfoContext): string {
263
307
 
264
308
  try {
265
309
  let benchmarkPath: string;
266
- const benchmarkFile = "cpu-geekbench-1k.json";
310
+ const benchmarkFile = "cpu-geekbench.json";
267
311
 
268
312
  // Try multiple resolution strategies
269
313
  if (fs.existsSync(benchmarkFile)) {
@@ -331,3 +375,171 @@ export function cpu_bench_info(context: InfoContext): string {
331
375
  setCachedValue(context.cache, "cpu_bench_info", "");
332
376
  return "";
333
377
  }
378
+
379
+ /**
380
+ * Gets GPU benchmark score and rank from Geekbench 6 data
381
+ * Uses fuzzy matching to find similar GPU models
382
+ * @param context - Info context with cache
383
+ * @returns Benchmark info with score and rank, or empty string
384
+ * @example "37.9k #1", "20.5k #68"
385
+ */
386
+ export function gpu_bench(context: InfoContext): string {
387
+ const cached = getCachedValue(context.cache, "gpu_bench");
388
+ if (cached) return cached;
389
+
390
+ const gpuName = gpu(context);
391
+ if (!gpuName) {
392
+ setCachedValue(context.cache, "gpu_bench", "");
393
+ return "";
394
+ }
395
+
396
+ try {
397
+ let benchmarkPath: string;
398
+ const benchmarkFile = "gpu-geekbench.json";
399
+
400
+ // Try multiple resolution strategies
401
+ if (fs.existsSync(benchmarkFile)) {
402
+ benchmarkPath = benchmarkFile;
403
+ } else if (fs.existsSync(`src/bench/${benchmarkFile}`)) {
404
+ benchmarkPath = `src/bench/${benchmarkFile}`;
405
+ } else if (fs.existsSync(`./bench/${benchmarkFile}`)) {
406
+ benchmarkPath = `./bench/${benchmarkFile}`;
407
+ } else {
408
+ // Last resort: construct path from import.meta.url
409
+ try {
410
+ const url = new URL(`./${benchmarkFile}`, import.meta.url);
411
+ benchmarkPath = url.pathname;
412
+ if (!fs.existsSync(benchmarkPath)) {
413
+ const distPath = url.pathname.substring(0, url.pathname.lastIndexOf('/'));
414
+ benchmarkPath = distPath + `/${benchmarkFile}`;
415
+ }
416
+ } catch {
417
+ benchmarkPath = benchmarkFile;
418
+ }
419
+ }
420
+
421
+ const benchmarkData = fs.readFileSync(benchmarkPath, "utf8");
422
+ const parsed = JSON.parse(benchmarkData);
423
+ const scores = parsed.scores as [string, number, number][];
424
+
425
+ const gpuList = scores.map((item) => ({ name: item[0], score: item[1], rank: item[2] }));
426
+
427
+ const fuse = new Fuse(gpuList, {
428
+ keys: ["name"],
429
+ threshold: 0.6,
430
+ minMatchCharLength: 3,
431
+ });
432
+
433
+ const results = fuse.search(gpuName);
434
+ if (results.length > 0) {
435
+ const match = results[0].item;
436
+ const score = Math.round(match.score / 100) / 10;
437
+ const rank = match.rank;
438
+ const result = `${score}k #${rank}`;
439
+ setCachedValue(context.cache, "gpu_bench", result);
440
+ return result;
441
+ }
442
+ } catch (e) {
443
+ // Silently fail
444
+ }
445
+
446
+ setCachedValue(context.cache, "gpu_bench", "");
447
+ return "";
448
+ }
449
+
450
+ /**
451
+ * Gets detailed GPU benchmark information from Geekbench 6 data
452
+ * Includes score, rank, and vendor detection
453
+ * @param context - Info context with cache
454
+ * @returns Detailed benchmark info with vendor, or empty string
455
+ * @example "Geekbench 6: 37.9k (Rank #1) - NVIDIA", "Geekbench 6: 20.5k (Rank #68) - AMD"
456
+ */
457
+ export function gpu_bench_info(context: InfoContext): string {
458
+ const cached = getCachedValue(context.cache, "gpu_bench_info");
459
+ if (cached) return cached;
460
+
461
+ const gpuName = gpu(context);
462
+ if (!gpuName) {
463
+ setCachedValue(context.cache, "gpu_bench_info", "");
464
+ return "";
465
+ }
466
+
467
+ try {
468
+ let benchmarkPath: string;
469
+ const benchmarkFile = "gpu-geekbench.json";
470
+
471
+ // Try multiple resolution strategies
472
+ if (fs.existsSync(benchmarkFile)) {
473
+ benchmarkPath = benchmarkFile;
474
+ } else if (fs.existsSync(`src/bench/${benchmarkFile}`)) {
475
+ benchmarkPath = `src/bench/${benchmarkFile}`;
476
+ } else if (fs.existsSync(`./bench/${benchmarkFile}`)) {
477
+ benchmarkPath = `./bench/${benchmarkFile}`;
478
+ } else {
479
+ // Last resort: construct path from import.meta.url
480
+ try {
481
+ const url = new URL(`./${benchmarkFile}`, import.meta.url);
482
+ benchmarkPath = url.pathname;
483
+ if (!fs.existsSync(benchmarkPath)) {
484
+ const distPath = url.pathname.substring(0, url.pathname.lastIndexOf('/'));
485
+ benchmarkPath = distPath + `/${benchmarkFile}`;
486
+ }
487
+ } catch {
488
+ benchmarkPath = benchmarkFile;
489
+ }
490
+ }
491
+
492
+ const benchmarkData = fs.readFileSync(benchmarkPath, "utf8");
493
+ const parsed = JSON.parse(benchmarkData);
494
+ const scores = parsed.scores as [string, number, number][];
495
+
496
+ const gpuList = scores.map((item) => ({
497
+ name: item[0],
498
+ score: item[1],
499
+ rank: item[2],
500
+ }));
501
+
502
+ const fuse = new Fuse(gpuList, {
503
+ keys: ["name"],
504
+ threshold: 0.6,
505
+ minMatchCharLength: 3,
506
+ });
507
+
508
+ const results = fuse.search(gpuName);
509
+ if (results.length > 0) {
510
+ const match = results[0].item;
511
+ const score = Math.round(match.score / 100) / 10;
512
+ const rank = match.rank;
513
+
514
+ // Detect vendor from GPU name
515
+ let vendor = "Unknown";
516
+ const upperName = match.name.toUpperCase();
517
+ if (upperName.includes("NVIDIA") || upperName.includes("GEFORCE") ||
518
+ upperName.includes("RTX") || upperName.includes("GTX") ||
519
+ upperName.includes("QUADRO") || upperName.includes("TESL") ||
520
+ upperName.includes("B200") || upperName.includes("H100") ||
521
+ upperName.includes("A100") || upperName.includes("A40") ||
522
+ upperName.includes("L40") || upperName.includes("L20")) {
523
+ vendor = "NVIDIA";
524
+ } else if (upperName.includes("AMD") || upperName.includes("RADEON") ||
525
+ upperName.includes("RX ") || upperName.includes("HD") ||
526
+ upperName.includes("EPYC") || upperName.includes("INSTINCT") ||
527
+ upperName.includes("NAVI") || upperName.includes("VEGA")) {
528
+ vendor = "AMD";
529
+ } else if (upperName.includes("INTEL") || upperName.includes("ARC") ||
530
+ upperName.includes("UHD") || upperName.includes("IRIS") ||
531
+ upperName.includes("HD GRAPHICS")) {
532
+ vendor = "Intel";
533
+ }
534
+
535
+ const result = `Geekbench 6: ${score}k (Rank #${rank}) - ${vendor}`;
536
+ setCachedValue(context.cache, "gpu_bench_info", result);
537
+ return result;
538
+ }
539
+ } catch (e) {
540
+ // Silently fail
541
+ }
542
+
543
+ setCachedValue(context.cache, "gpu_bench_info", "");
544
+ return "";
545
+ }