pyre-cli 8.2.0 → 9.0.0
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/dist/{brewHealth-6NE37NAU.js → brewHealth-F2BXF5M6.js} +1 -1
- package/dist/{chunk-KBKXU2ZV.js → chunk-EQZCK2VC.js} +26 -19
- package/dist/{chunk-GLH7EKAX.js → chunk-FH5WDJBF.js} +1 -1
- package/dist/{collectors-4VYRJVRO.js → collectors-KNEN4YJD.js} +2 -2
- package/dist/{doctor-LJQAABZ4.js → doctor-L6FZYA7F.js} +1 -1
- package/dist/{extensions-QCFSVCL5.js → extensions-DVA5YLGH.js} +1 -1
- package/dist/index.js +19 -14
- package/package.json +1 -1
- package/src/live/render.ts +16 -8
- package/src/monitors/collectors.ts +22 -14
- package/src/monitors/run.ts +1 -1
- package/src/monitors/smc.ts +6 -9
- package/src/splash.ts +1 -1
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
run
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-FH5WDJBF.js";
|
|
4
4
|
|
|
5
5
|
// src/monitors/collectors.ts
|
|
6
6
|
import chalk from "chalk";
|
|
@@ -15,7 +15,8 @@ async function getSmcMetrics() {
|
|
|
15
15
|
try {
|
|
16
16
|
const pm = (await run(
|
|
17
17
|
"sudo -n powermetrics --samplers smc,cpu_power -n 1 --format text 2>/dev/null",
|
|
18
|
-
""
|
|
18
|
+
"",
|
|
19
|
+
2e3
|
|
19
20
|
)).trim();
|
|
20
21
|
if (pm) {
|
|
21
22
|
const cpuTemp = pm.match(/CPU die temperature:\s*([\d.]+)/i);
|
|
@@ -71,13 +72,9 @@ async function getSmcMetrics() {
|
|
|
71
72
|
}
|
|
72
73
|
}
|
|
73
74
|
if (result.temps["cpu_die"] === void 0) {
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
const m = top.match(/CPU usage:\s*[\d.]+\%\s*user,\s*[\d.]+\%\s*sys,\s*([\d.]+)\%\s*idle/);
|
|
78
|
-
if (m) loadUsage = Math.max(0, 100 - parseFloat(m[1]));
|
|
79
|
-
} catch {
|
|
80
|
-
}
|
|
75
|
+
const loadAvg = (await import("os")).loadavg();
|
|
76
|
+
const ncpus = (await import("os")).cpus().length || 1;
|
|
77
|
+
const loadUsage = Math.min(100, loadAvg[0] / ncpus * 100);
|
|
81
78
|
const estCpu = Math.round((38 + loadUsage * 0.42) * 10) / 10;
|
|
82
79
|
result.temps["cpu_die"] = estCpu;
|
|
83
80
|
if (result.temps["gpu_die"] === void 0) {
|
|
@@ -98,6 +95,7 @@ function parseSuffix(s) {
|
|
|
98
95
|
var SP_TTL_MS = 1e4;
|
|
99
96
|
var NETSTAT_TTL_MS = 1e3;
|
|
100
97
|
var prevCpuTimes = null;
|
|
98
|
+
var prevCpuTotal = { total: 0, idle: 0, ts: 0 };
|
|
101
99
|
var ROUTE_TTL_MS = 5e3;
|
|
102
100
|
var SYSCTL_TTL_MS = 6e4;
|
|
103
101
|
var spGpuCache = null;
|
|
@@ -239,7 +237,7 @@ async function collectGpu(detailed) {
|
|
|
239
237
|
if (spGpuCache && now - spGpuCache.ts < SP_TTL_MS) {
|
|
240
238
|
spRaw = spGpuCache.raw;
|
|
241
239
|
} else {
|
|
242
|
-
spRaw = (await run("system_profiler SPDisplaysDataType 2>/dev/null")).trim();
|
|
240
|
+
spRaw = (await run("system_profiler SPDisplaysDataType 2>/dev/null", "", 3e3)).trim();
|
|
243
241
|
spGpuCache = { raw: spRaw, ts: now };
|
|
244
242
|
}
|
|
245
243
|
let model = "Unknown";
|
|
@@ -376,12 +374,21 @@ async function collectCpu() {
|
|
|
376
374
|
}
|
|
377
375
|
let usage = 0;
|
|
378
376
|
try {
|
|
379
|
-
const
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
377
|
+
const cpus = os.cpus();
|
|
378
|
+
let totalNow = 0;
|
|
379
|
+
let idleNow = 0;
|
|
380
|
+
for (const cpu of cpus) {
|
|
381
|
+
totalNow += cpu.times.user + cpu.times.nice + cpu.times.sys + cpu.times.idle + cpu.times.irq;
|
|
382
|
+
idleNow += cpu.times.idle;
|
|
383
|
+
}
|
|
384
|
+
if (prevCpuTotal.ts > 0) {
|
|
385
|
+
const totalDelta = totalNow - prevCpuTotal.total;
|
|
386
|
+
const idleDelta = idleNow - prevCpuTotal.idle;
|
|
387
|
+
if (totalDelta > 0) {
|
|
388
|
+
usage = Math.round((totalDelta - idleDelta) / totalDelta * 100);
|
|
389
|
+
}
|
|
384
390
|
}
|
|
391
|
+
prevCpuTotal = { total: totalNow, idle: idleNow, ts: Date.now() };
|
|
385
392
|
} catch {
|
|
386
393
|
}
|
|
387
394
|
const loadAvgStr = (await run("sysctl -n vm.loadavg", "0.00 0.00 0.00")).trim();
|
|
@@ -485,7 +492,7 @@ async function getDiskIoRates() {
|
|
|
485
492
|
return { readBytesSec: cachedDiskIo.readBytesSec, writeBytesSec: cachedDiskIo.writeBytesSec };
|
|
486
493
|
}
|
|
487
494
|
try {
|
|
488
|
-
const raw = (await run("iostat -d -c 2 1 2", "")).trim();
|
|
495
|
+
const raw = (await run("iostat -d -c 2 1 2", "", 3e3)).trim();
|
|
489
496
|
const blocks = raw.split(/\n\s*\n/).filter(Boolean);
|
|
490
497
|
const targetBlock = blocks.length > 1 ? blocks[1] : blocks[0];
|
|
491
498
|
if (targetBlock) {
|
|
@@ -547,7 +554,7 @@ async function collectBattery() {
|
|
|
547
554
|
if (spBatteryCache && now - spBatteryCache.ts < SP_TTL_MS) {
|
|
548
555
|
battInfo = spBatteryCache.raw;
|
|
549
556
|
} else {
|
|
550
|
-
battInfo = (await run("system_profiler SPPowerDataType 2>/dev/null")).trim();
|
|
557
|
+
battInfo = (await run("system_profiler SPPowerDataType 2>/dev/null", "", 3e3)).trim();
|
|
551
558
|
spBatteryCache = { raw: battInfo, ts: now };
|
|
552
559
|
}
|
|
553
560
|
const cycleMatch = battInfo.match(/Cycle Count:\s+(\d+)/);
|
|
@@ -723,7 +730,7 @@ async function collectPackets() {
|
|
|
723
730
|
}
|
|
724
731
|
let connections = 0;
|
|
725
732
|
try {
|
|
726
|
-
const tcpConns = (await run("netstat -an | grep ESTABLISHED | wc -l", "0")).trim();
|
|
733
|
+
const tcpConns = (await run("netstat -an | grep ESTABLISHED | wc -l", "0", 2e3)).trim();
|
|
727
734
|
connections = parseInt(tcpConns) || 0;
|
|
728
735
|
} catch {
|
|
729
736
|
connections = 0;
|
|
@@ -731,7 +738,7 @@ async function collectPackets() {
|
|
|
731
738
|
let topProcesses = [];
|
|
732
739
|
let allProcesses = [];
|
|
733
740
|
try {
|
|
734
|
-
const lsof = (await run("lsof -i -n -P 2>/dev/null | tail -n +2 | awk '{print $1, $2}' | sort | uniq -c | sort -rn", "")).trim();
|
|
741
|
+
const lsof = (await run("lsof -i -n -P 2>/dev/null | tail -n +2 | awk '{print $1, $2}' | sort | uniq -c | sort -rn", "", 2e3)).trim();
|
|
735
742
|
const lsofLines = lsof.split("\n");
|
|
736
743
|
topProcesses = lsofLines.map((line) => {
|
|
737
744
|
const parts = line.trim().split(/\s+/);
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import { exec } from "child_process";
|
|
3
3
|
import { promisify } from "util";
|
|
4
4
|
var execAsync = promisify(exec);
|
|
5
|
-
async function run(cmd, fallback = "", timeout =
|
|
5
|
+
async function run(cmd, fallback = "", timeout = 3e3) {
|
|
6
6
|
try {
|
|
7
7
|
return (await execAsync(cmd, { encoding: "utf8", timeout })).stdout.trim();
|
|
8
8
|
} catch {
|
package/dist/index.js
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
collectAll
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-EQZCK2VC.js";
|
|
5
5
|
import {
|
|
6
6
|
CONFIG_FILE,
|
|
7
7
|
readConfig,
|
|
8
8
|
writeConfig
|
|
9
9
|
} from "./chunk-RVGKEJXT.js";
|
|
10
|
-
import "./chunk-
|
|
10
|
+
import "./chunk-FH5WDJBF.js";
|
|
11
11
|
|
|
12
12
|
// src/index.ts
|
|
13
13
|
import fs8 from "fs";
|
|
@@ -2697,8 +2697,7 @@ function graphsCacheParams() {
|
|
|
2697
2697
|
}
|
|
2698
2698
|
function processRowBudget() {
|
|
2699
2699
|
let overlayRows = 0;
|
|
2700
|
-
if (state.inputMode === "
|
|
2701
|
-
else if (state.inputMode === "signal") overlayRows = 6;
|
|
2700
|
+
if (state.inputMode === "signal") overlayRows = 6;
|
|
2702
2701
|
else if (state.inputMode === "filter" || state.inputMode === "kill" || state.inputMode === "p2p") overlayRows = 3;
|
|
2703
2702
|
if (state.activePanel === "process") {
|
|
2704
2703
|
return Math.max(10, state.termHeight - 12 - overlayRows);
|
|
@@ -2854,14 +2853,20 @@ function render() {
|
|
|
2854
2853
|
const footerHeight = 3;
|
|
2855
2854
|
const targetBodyHeight = Math.max(1, state.termHeight - footerHeight);
|
|
2856
2855
|
if (state.inputMode === "customizer") {
|
|
2857
|
-
const preOverlayCount = bodyLines.length;
|
|
2858
|
-
const availableForOverlay = targetBodyHeight - preOverlayCount;
|
|
2859
2856
|
const totalItems = state.CUSTOMIZER_OPTIONS.length;
|
|
2860
2857
|
const headerLines = 1;
|
|
2861
|
-
const blankLines =
|
|
2862
|
-
const
|
|
2858
|
+
const blankLines = 1;
|
|
2859
|
+
const idealOverlayHeight = totalItems + headerLines + blankLines;
|
|
2860
|
+
const minOverlayHeight = Math.min(10 + headerLines + blankLines, Math.floor(targetBodyHeight / 2));
|
|
2861
|
+
const overlayHeight = Math.min(idealOverlayHeight, Math.max(minOverlayHeight, Math.floor(targetBodyHeight * 0.6)));
|
|
2862
|
+
const maxBodyForTable = Math.max(3, targetBodyHeight - overlayHeight);
|
|
2863
|
+
if (bodyLines.length > maxBodyForTable) {
|
|
2864
|
+
bodyLines.length = maxBodyForTable;
|
|
2865
|
+
}
|
|
2866
|
+
const availableForOverlay = targetBodyHeight - bodyLines.length;
|
|
2867
|
+
const maxVisibleItems = Math.max(1, availableForOverlay - headerLines - blankLines);
|
|
2863
2868
|
const scrollOffset = totalItems > maxVisibleItems ? Math.max(0, Math.min(state.customizerIndex, totalItems - maxVisibleItems)) : 0;
|
|
2864
|
-
|
|
2869
|
+
bodyLines.push("");
|
|
2865
2870
|
bodyLines.push(...renderCustomizerOverlay(scrollOffset, maxVisibleItems).split("\n"));
|
|
2866
2871
|
} else if (state.inputMode === "filter") {
|
|
2867
2872
|
bodyLines.push(chalk4.cyan(` Filter processes: ${state.inputBuffer}_`));
|
|
@@ -4591,7 +4596,7 @@ async function showSplash(config3) {
|
|
|
4591
4596
|
process.stdin.setRawMode(true);
|
|
4592
4597
|
process.stdin.resume();
|
|
4593
4598
|
process.stdin.on("data", onEnter);
|
|
4594
|
-
setTimeout(onEnter,
|
|
4599
|
+
setTimeout(onEnter, 1500);
|
|
4595
4600
|
});
|
|
4596
4601
|
}
|
|
4597
4602
|
|
|
@@ -4861,12 +4866,12 @@ async function main() {
|
|
|
4861
4866
|
return;
|
|
4862
4867
|
}
|
|
4863
4868
|
if (cmd === "extensions") {
|
|
4864
|
-
const { printExtensionsReport } = await import("./extensions-
|
|
4869
|
+
const { printExtensionsReport } = await import("./extensions-DVA5YLGH.js");
|
|
4865
4870
|
await printExtensionsReport();
|
|
4866
4871
|
return;
|
|
4867
4872
|
}
|
|
4868
4873
|
if (cmd === "brew") {
|
|
4869
|
-
const { printBrewHealthReport } = await import("./brewHealth-
|
|
4874
|
+
const { printBrewHealthReport } = await import("./brewHealth-F2BXF5M6.js");
|
|
4870
4875
|
await printBrewHealthReport();
|
|
4871
4876
|
return;
|
|
4872
4877
|
}
|
|
@@ -4969,7 +4974,7 @@ async function main() {
|
|
|
4969
4974
|
return;
|
|
4970
4975
|
}
|
|
4971
4976
|
if (cmd === "doctor") {
|
|
4972
|
-
const { runDoctor, printDoctorReport } = await import("./doctor-
|
|
4977
|
+
const { runDoctor, printDoctorReport } = await import("./doctor-L6FZYA7F.js");
|
|
4973
4978
|
const checks = await runDoctor();
|
|
4974
4979
|
printDoctorReport(checks);
|
|
4975
4980
|
return;
|
|
@@ -5234,7 +5239,7 @@ async function runP2PConnect() {
|
|
|
5234
5239
|
}
|
|
5235
5240
|
async function runInfoCommand() {
|
|
5236
5241
|
const data = await collectAll({ detailed: true });
|
|
5237
|
-
const { getDisplayInfo, getTimeMachineStatus } = await import("./collectors-
|
|
5242
|
+
const { getDisplayInfo, getTimeMachineStatus } = await import("./collectors-KNEN4YJD.js");
|
|
5238
5243
|
const displays = await getDisplayInfo();
|
|
5239
5244
|
const tmStatus = await getTimeMachineStatus();
|
|
5240
5245
|
const lines = [];
|
package/package.json
CHANGED
package/src/live/render.ts
CHANGED
|
@@ -68,8 +68,7 @@ function graphsCacheParams(): string {
|
|
|
68
68
|
|
|
69
69
|
function processRowBudget(): number {
|
|
70
70
|
let overlayRows = 0;
|
|
71
|
-
if (state.inputMode === '
|
|
72
|
-
else if (state.inputMode === 'signal') overlayRows = 6;
|
|
71
|
+
if (state.inputMode === 'signal') overlayRows = 6;
|
|
73
72
|
else if (state.inputMode === 'filter' || state.inputMode === 'kill' || state.inputMode === 'p2p') overlayRows = 3;
|
|
74
73
|
|
|
75
74
|
if (state.activePanel === 'process') {
|
|
@@ -265,17 +264,26 @@ function render() {
|
|
|
265
264
|
const targetBodyHeight = Math.max(1, state.termHeight - footerHeight);
|
|
266
265
|
|
|
267
266
|
if (state.inputMode === 'customizer') {
|
|
268
|
-
const preOverlayCount = bodyLines.length;
|
|
269
|
-
const availableForOverlay = targetBodyHeight - preOverlayCount;
|
|
270
267
|
const totalItems = state.CUSTOMIZER_OPTIONS.length;
|
|
271
|
-
const headerLines = 1;
|
|
272
|
-
const blankLines =
|
|
273
|
-
|
|
268
|
+
const headerLines = 1; // the "UI CUSTOMIZER" header
|
|
269
|
+
const blankLines = 1; // blank separator line
|
|
270
|
+
// Reserve a fixed height for the customizer: show all items if they fit,
|
|
271
|
+
// otherwise guarantee at least 10 visible items (or half the screen).
|
|
272
|
+
const idealOverlayHeight = totalItems + headerLines + blankLines;
|
|
273
|
+
const minOverlayHeight = Math.min(10 + headerLines + blankLines, Math.floor(targetBodyHeight / 2));
|
|
274
|
+
const overlayHeight = Math.min(idealOverlayHeight, Math.max(minOverlayHeight, Math.floor(targetBodyHeight * 0.6)));
|
|
275
|
+
// Truncate table body to make room for the customizer overlay
|
|
276
|
+
const maxBodyForTable = Math.max(3, targetBodyHeight - overlayHeight);
|
|
277
|
+
if (bodyLines.length > maxBodyForTable) {
|
|
278
|
+
bodyLines.length = maxBodyForTable;
|
|
279
|
+
}
|
|
280
|
+
const availableForOverlay = targetBodyHeight - bodyLines.length;
|
|
281
|
+
const maxVisibleItems = Math.max(1, availableForOverlay - headerLines - blankLines);
|
|
274
282
|
const scrollOffset = totalItems > maxVisibleItems
|
|
275
283
|
? Math.max(0, Math.min(state.customizerIndex, totalItems - maxVisibleItems))
|
|
276
284
|
: 0;
|
|
277
285
|
|
|
278
|
-
|
|
286
|
+
bodyLines.push('');
|
|
279
287
|
bodyLines.push(...renderCustomizerOverlay(scrollOffset, maxVisibleItems).split('\n'));
|
|
280
288
|
} else if (state.inputMode === 'filter') {
|
|
281
289
|
bodyLines.push(chalk.cyan(` Filter processes: ${state.inputBuffer}_`));
|
|
@@ -20,6 +20,7 @@ import type { StatsData, CpuData, MemoryData, ThermalData, BatteryData, PowerDat
|
|
|
20
20
|
const SP_TTL_MS = 10_000;
|
|
21
21
|
const NETSTAT_TTL_MS = 1000;
|
|
22
22
|
let prevCpuTimes: { total: number; idle: number }[] | null = null;
|
|
23
|
+
let prevCpuTotal = { total: 0, idle: 0, ts: 0 };
|
|
23
24
|
const ROUTE_TTL_MS = 5_000;
|
|
24
25
|
const SYSCTL_TTL_MS = 60_000;
|
|
25
26
|
|
|
@@ -236,7 +237,7 @@ export async function collectPower(): Promise<PowerData | null> {
|
|
|
236
237
|
if (spGpuCache && now - spGpuCache.ts < SP_TTL_MS) {
|
|
237
238
|
spRaw = spGpuCache.raw;
|
|
238
239
|
} else {
|
|
239
|
-
spRaw = (await run('system_profiler SPDisplaysDataType 2>/dev/null')).trim();
|
|
240
|
+
spRaw = (await run('system_profiler SPDisplaysDataType 2>/dev/null', '', 3000)).trim();
|
|
240
241
|
spGpuCache = { raw: spRaw, ts: now };
|
|
241
242
|
}
|
|
242
243
|
|
|
@@ -400,18 +401,25 @@ export async function collectCpu(): Promise<CpuData> {
|
|
|
400
401
|
}
|
|
401
402
|
}
|
|
402
403
|
|
|
404
|
+
// Use os.cpus() delta instead of the very slow `top -l 1 -n 0` which
|
|
405
|
+
// blocks for ~1-2s waiting for a sampling window. os.cpus() is instant.
|
|
403
406
|
let usage = 0;
|
|
404
407
|
try {
|
|
405
|
-
const
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
408
|
+
const cpus = os.cpus();
|
|
409
|
+
let totalNow = 0;
|
|
410
|
+
let idleNow = 0;
|
|
411
|
+
for (const cpu of cpus) {
|
|
412
|
+
totalNow += cpu.times.user + cpu.times.nice + cpu.times.sys + cpu.times.idle + cpu.times.irq;
|
|
413
|
+
idleNow += cpu.times.idle;
|
|
414
|
+
}
|
|
415
|
+
if (prevCpuTotal.ts > 0) {
|
|
416
|
+
const totalDelta = totalNow - prevCpuTotal.total;
|
|
417
|
+
const idleDelta = idleNow - prevCpuTotal.idle;
|
|
418
|
+
if (totalDelta > 0) {
|
|
419
|
+
usage = Math.round(((totalDelta - idleDelta) / totalDelta) * 100);
|
|
420
|
+
}
|
|
414
421
|
}
|
|
422
|
+
prevCpuTotal = { total: totalNow, idle: idleNow, ts: Date.now() };
|
|
415
423
|
} catch {
|
|
416
424
|
// ignore
|
|
417
425
|
}
|
|
@@ -534,7 +542,7 @@ async function getDiskIoRates(): Promise<{ readBytesSec: number; writeBytesSec:
|
|
|
534
542
|
return { readBytesSec: cachedDiskIo.readBytesSec, writeBytesSec: cachedDiskIo.writeBytesSec };
|
|
535
543
|
}
|
|
536
544
|
try {
|
|
537
|
-
const raw = (await run('iostat -d -c 2 1 2', '')).trim();
|
|
545
|
+
const raw = (await run('iostat -d -c 2 1 2', '', 3000)).trim();
|
|
538
546
|
const blocks = raw.split(/\n\s*\n/).filter(Boolean);
|
|
539
547
|
const targetBlock = blocks.length > 1 ? blocks[1] : blocks[0];
|
|
540
548
|
if (targetBlock) {
|
|
@@ -606,7 +614,7 @@ export async function collectBattery(): Promise<BatteryData | null> {
|
|
|
606
614
|
if (spBatteryCache && now - spBatteryCache.ts < SP_TTL_MS) {
|
|
607
615
|
battInfo = spBatteryCache.raw;
|
|
608
616
|
} else {
|
|
609
|
-
battInfo = (await run('system_profiler SPPowerDataType 2>/dev/null')).trim();
|
|
617
|
+
battInfo = (await run('system_profiler SPPowerDataType 2>/dev/null', '', 3000)).trim();
|
|
610
618
|
spBatteryCache = { raw: battInfo, ts: now };
|
|
611
619
|
}
|
|
612
620
|
|
|
@@ -821,7 +829,7 @@ export async function collectPackets(): Promise<PacketData | null> {
|
|
|
821
829
|
|
|
822
830
|
let connections = 0;
|
|
823
831
|
try {
|
|
824
|
-
const tcpConns = (await run('netstat -an | grep ESTABLISHED | wc -l', '0')).trim();
|
|
832
|
+
const tcpConns = (await run('netstat -an | grep ESTABLISHED | wc -l', '0', 2000)).trim();
|
|
825
833
|
connections = parseInt(tcpConns) || 0;
|
|
826
834
|
} catch {
|
|
827
835
|
connections = 0;
|
|
@@ -830,7 +838,7 @@ export async function collectPackets(): Promise<PacketData | null> {
|
|
|
830
838
|
let topProcesses: { pid: number; command: string; rxBytes: number; txBytes: number }[] = [];
|
|
831
839
|
let allProcesses: { pid: number; command: string; rxBytes: number; txBytes: number; rxPackets?: number; txPackets?: number }[] = [];
|
|
832
840
|
try {
|
|
833
|
-
const lsof = (await run('lsof -i -n -P 2>/dev/null | tail -n +2 | awk \'{print $1, $2}\' | sort | uniq -c | sort -rn', '')).trim();
|
|
841
|
+
const lsof = (await run('lsof -i -n -P 2>/dev/null | tail -n +2 | awk \'{print $1, $2}\' | sort | uniq -c | sort -rn', '', 2000)).trim();
|
|
834
842
|
const lsofLines = lsof.split('\n');
|
|
835
843
|
topProcesses = lsofLines.map(line => {
|
|
836
844
|
const parts = line.trim().split(/\s+/);
|
package/src/monitors/run.ts
CHANGED
|
@@ -11,7 +11,7 @@ import { promisify } from 'node:util';
|
|
|
11
11
|
|
|
12
12
|
const execAsync = promisify(exec);
|
|
13
13
|
|
|
14
|
-
async function run(cmd: string, fallback: string = '', timeout =
|
|
14
|
+
async function run(cmd: string, fallback: string = '', timeout = 3000): Promise<string> {
|
|
15
15
|
try {
|
|
16
16
|
return (await execAsync(cmd, { encoding: 'utf8', timeout })).stdout.trim();
|
|
17
17
|
} catch {
|
package/src/monitors/smc.ts
CHANGED
|
@@ -41,7 +41,8 @@ export async function getSmcMetrics(): Promise<SmcMetrics> {
|
|
|
41
41
|
const pm = (
|
|
42
42
|
await run(
|
|
43
43
|
'sudo -n powermetrics --samplers smc,cpu_power -n 1 --format text 2>/dev/null',
|
|
44
|
-
''
|
|
44
|
+
'',
|
|
45
|
+
2000
|
|
45
46
|
)
|
|
46
47
|
).trim();
|
|
47
48
|
|
|
@@ -116,14 +117,10 @@ export async function getSmcMetrics(): Promise<SmcMetrics> {
|
|
|
116
117
|
|
|
117
118
|
// 4. Smart load-based thermal estimation if hardware sensors return nothing
|
|
118
119
|
if (result.temps['cpu_die'] === undefined) {
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
if (m) loadUsage = Math.max(0, 100 - parseFloat(m[1]));
|
|
124
|
-
} catch {
|
|
125
|
-
// ignore
|
|
126
|
-
}
|
|
120
|
+
// Use os.loadavg() (instant) instead of the slow `top -l 1` (~1-2s)
|
|
121
|
+
const loadAvg = (await import('node:os')).loadavg();
|
|
122
|
+
const ncpus = (await import('node:os')).cpus().length || 1;
|
|
123
|
+
const loadUsage = Math.min(100, (loadAvg[0] / ncpus) * 100);
|
|
127
124
|
|
|
128
125
|
const estCpu = Math.round((38 + (loadUsage * 0.42)) * 10) / 10;
|
|
129
126
|
result.temps['cpu_die'] = estCpu;
|