pyre-cli 9.0.0 → 9.2.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/{anomaliesCmd-TO52YY2B.js → anomaliesCmd-25OFKYPK.js} +1 -1
- package/dist/{chunk-EQZCK2VC.js → chunk-QOLZ7T32.js} +9 -0
- package/dist/{collectors-KNEN4YJD.js → collectors-VACLPHRP.js} +1 -1
- package/dist/index.js +421 -80
- package/package.json +1 -1
- package/src/anomaliesCmd.ts +1 -1
- package/src/formatters/render.ts +127 -38
- package/src/formatters/types.ts +6 -0
- package/src/live/input.ts +149 -5
- package/src/live/render.ts +145 -3
- package/src/live/state.ts +8 -0
- package/src/live/types.ts +1 -1
- package/src/monitors/collectors.ts +11 -0
package/dist/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
collectAll
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-QOLZ7T32.js";
|
|
5
5
|
import {
|
|
6
6
|
CONFIG_FILE,
|
|
7
7
|
readConfig,
|
|
@@ -10,9 +10,9 @@ import {
|
|
|
10
10
|
import "./chunk-FH5WDJBF.js";
|
|
11
11
|
|
|
12
12
|
// src/index.ts
|
|
13
|
-
import
|
|
13
|
+
import fs9 from "fs";
|
|
14
14
|
import os3 from "os";
|
|
15
|
-
import
|
|
15
|
+
import path6 from "path";
|
|
16
16
|
import readline2 from "readline";
|
|
17
17
|
import { Command } from "commander";
|
|
18
18
|
import chalk12 from "chalk";
|
|
@@ -575,17 +575,19 @@ function sortProcesses(processes, sortBy) {
|
|
|
575
575
|
function pctColor(v) {
|
|
576
576
|
return v > 80 ? chalk2.red : v > 50 ? chalk2.yellow : chalk2.dim;
|
|
577
577
|
}
|
|
578
|
-
function processTableLines(processes, contentWidth, borderAccent = THEMES.default.border) {
|
|
578
|
+
function processTableLines(processes, contentWidth, borderAccent = THEMES.default.border, selectedIdx = -1) {
|
|
579
579
|
const pidW = 8, ppidW = 8, userW = 12, cpuW = 8, memW = 8, stateW = 8, thrW = 6, rtW = 10;
|
|
580
580
|
const cmdW = Math.max(10, contentWidth - pidW - ppidW - userW - cpuW - memW - stateW - thrW - rtW - 8);
|
|
581
581
|
const head = chalk2.bold.hex("#f8f8f2").bgHex("#44475a")(" PID ") + chalk2.bold.hex("#f8f8f2").bgHex("#44475a")(" PPID ") + chalk2.bold.hex("#f8f8f2").bgHex("#44475a")(" USER ") + chalk2.bold.hex("#f8f8f2").bgHex("#44475a")(" CPU% ") + chalk2.bold.hex("#f8f8f2").bgHex("#44475a")(" MEM% ") + chalk2.bold.hex("#f8f8f2").bgHex("#44475a")(" STATE ") + chalk2.bold.hex("#f8f8f2").bgHex("#44475a")(" THREADS") + chalk2.bold.hex("#f8f8f2").bgHex("#44475a")(" RUNTIME ") + chalk2.bold.hex("#f8f8f2").bgHex("#44475a")(" COMMAND".padEnd(cmdW + 1));
|
|
582
|
-
const rows = processes.map((p) => {
|
|
582
|
+
const rows = processes.map((p, idx) => {
|
|
583
|
+
const isSelected = idx === selectedIdx;
|
|
583
584
|
const cpuStr = pctColor(p.cpu)(`${p.cpu.toFixed(1)}`.padEnd(cpuW));
|
|
584
585
|
const memStr = pctColor(p.mem)(`${p.mem.toFixed(1)}`.padEnd(memW));
|
|
585
586
|
const stateStr = chalk2.dim(p.state.padEnd(stateW));
|
|
586
587
|
const thrStr = String(p.threads).padEnd(thrW);
|
|
587
588
|
const rtStr = formatRuntime(p.runtime).padEnd(rtW);
|
|
588
|
-
|
|
589
|
+
const line = String(p.pid).padEnd(pidW) + String(p.ppid).padEnd(ppidW) + truncatePlain(p.user, userW - 1).padEnd(userW) + cpuStr + memStr + stateStr + thrStr + rtStr + truncatePlain(p.command, cmdW);
|
|
590
|
+
return isSelected ? chalk2.bgCyan.black(line) : line;
|
|
589
591
|
});
|
|
590
592
|
return [head, borderAccent("\u2500".repeat(contentWidth)), ...rows];
|
|
591
593
|
}
|
|
@@ -654,7 +656,7 @@ function diskTableLines(disks, contentWidth, borderAccent = THEMES.default.borde
|
|
|
654
656
|
});
|
|
655
657
|
return [head, borderAccent("\u2500".repeat(contentWidth)), ...rows];
|
|
656
658
|
}
|
|
657
|
-
function detailPanelTitle(panel2) {
|
|
659
|
+
function detailPanelTitle(panel2, trackedPid) {
|
|
658
660
|
const map = {
|
|
659
661
|
cpu: "CPU",
|
|
660
662
|
mem: "Memory",
|
|
@@ -666,7 +668,7 @@ function detailPanelTitle(panel2) {
|
|
|
666
668
|
packets: "Packets",
|
|
667
669
|
tasks: "Tasks",
|
|
668
670
|
disk: "Disk",
|
|
669
|
-
process: "Processes"
|
|
671
|
+
process: trackedPid !== void 0 && trackedPid !== null ? `Processes (Following PID ${trackedPid})` : "Processes"
|
|
670
672
|
};
|
|
671
673
|
return map[panel2] || panel2;
|
|
672
674
|
}
|
|
@@ -727,11 +729,43 @@ function activeDetailLines(data, activePanel, width, opts2 = {}) {
|
|
|
727
729
|
case "process": {
|
|
728
730
|
const filtered = opts2.filter ? data.processes.filter((p) => p.command.toLowerCase().includes(opts2.filter.toLowerCase())) : data.processes;
|
|
729
731
|
const sorted = sortProcesses(filtered, opts2.sortBy ?? "cpu");
|
|
730
|
-
|
|
732
|
+
let selectedIdx = opts2.selectedProcessIndex ?? -1;
|
|
733
|
+
const isTracking = opts2.trackedPid !== void 0 && opts2.trackedPid !== null;
|
|
734
|
+
if (isTracking) {
|
|
735
|
+
const trackedIdx = sorted.findIndex((p) => p.pid === opts2.trackedPid);
|
|
736
|
+
if (trackedIdx >= 0) {
|
|
737
|
+
selectedIdx = trackedIdx;
|
|
738
|
+
}
|
|
739
|
+
}
|
|
740
|
+
const trackingLines = [];
|
|
741
|
+
if (isTracking) {
|
|
742
|
+
const tp = sorted.find((p) => p.pid === opts2.trackedPid);
|
|
743
|
+
if (tp) {
|
|
744
|
+
const cpuColor = tp.cpu > 50 ? chalk2.red.bold : tp.cpu > 20 ? chalk2.yellow : chalk2.green;
|
|
745
|
+
const memColor = tp.mem > 50 ? chalk2.red.bold : tp.mem > 20 ? chalk2.yellow : chalk2.green;
|
|
746
|
+
trackingLines.push(chalk2.bgHex("#1a1a2e").hex("#e94560").bold(` \u25C9 FOLLOWING PID ${tp.pid} \u2014 ${truncatePlain(tp.command, Math.max(10, contentWidth - 30))} `));
|
|
747
|
+
trackingLines.push(
|
|
748
|
+
` ${chalk2.bold("CPU:")} ${cpuColor(tp.cpu.toFixed(1) + "%")} ${chalk2.bold("MEM:")} ${memColor(tp.mem.toFixed(1) + "%")} ${chalk2.bold("State:")} ${chalk2.dim(tp.state)} ${chalk2.bold("Threads:")} ${tp.threads} ${chalk2.bold("Runtime:")} ${formatRuntime(tp.runtime)} ${chalk2.bold("User:")} ${tp.user}`
|
|
749
|
+
);
|
|
750
|
+
trackingLines.push(chalk2.dim(` Full: ${tp.command}`));
|
|
751
|
+
trackingLines.push(theme.border("\u2500".repeat(contentWidth)));
|
|
752
|
+
} else {
|
|
753
|
+
trackingLines.push(chalk2.yellow(` \u25C9 PID ${opts2.trackedPid} exited \u2014 no longer in process list`));
|
|
754
|
+
trackingLines.push(theme.border("\u2500".repeat(contentWidth)));
|
|
755
|
+
}
|
|
756
|
+
}
|
|
757
|
+
const availableRows = Math.max(1, (opts2.processLimit || sorted.length) - trackingLines.length);
|
|
758
|
+
let offset = 0;
|
|
759
|
+
if (selectedIdx >= 0) {
|
|
760
|
+
if (selectedIdx >= availableRows) {
|
|
761
|
+
offset = selectedIdx - availableRows + 1;
|
|
762
|
+
}
|
|
763
|
+
}
|
|
764
|
+
const visible = sorted.slice(offset, offset + availableRows);
|
|
731
765
|
if (opts2.treeView) {
|
|
732
|
-
return buildProcessTree(
|
|
766
|
+
return [...trackingLines, ...buildProcessTree(visible)];
|
|
733
767
|
}
|
|
734
|
-
return processTableLines(
|
|
768
|
+
return [...trackingLines, ...processTableLines(visible, width - 4, theme.border, selectedIdx - offset)];
|
|
735
769
|
}
|
|
736
770
|
case "anomalies": {
|
|
737
771
|
if (!opts2.anomalyHistory || opts2.anomalyHistory.length === 0) return ["No anomalies detected yet."];
|
|
@@ -875,18 +909,50 @@ function btopProcBox(data, width, targetHeight, theme, opts2) {
|
|
|
875
909
|
const sorted = sortProcesses(filtered, opts2.sortBy ?? "cpu");
|
|
876
910
|
const headerRowOverhead = 2;
|
|
877
911
|
const tableHeaderOverhead = 2;
|
|
878
|
-
const
|
|
879
|
-
const
|
|
912
|
+
const isTracking = opts2.trackedPid !== void 0 && opts2.trackedPid !== null;
|
|
913
|
+
const trackingLines = [];
|
|
914
|
+
if (isTracking) {
|
|
915
|
+
const tp = sorted.find((p) => p.pid === opts2.trackedPid);
|
|
916
|
+
if (tp) {
|
|
917
|
+
const cpuColor = tp.cpu > 50 ? chalk2.red.bold : tp.cpu > 20 ? chalk2.yellow : chalk2.green;
|
|
918
|
+
const memColor = tp.mem > 50 ? chalk2.red.bold : tp.mem > 20 ? chalk2.yellow : chalk2.green;
|
|
919
|
+
trackingLines.push(chalk2.bgHex("#1a1a2e").hex("#e94560").bold(` \u25C9 PID ${tp.pid} ${truncatePlain(tp.command, Math.max(6, contentWidth - 20))} `));
|
|
920
|
+
trackingLines.push(
|
|
921
|
+
` ${cpuColor("CPU " + tp.cpu.toFixed(1) + "%")} ${memColor("MEM " + tp.mem.toFixed(1) + "%")} ${chalk2.dim(tp.state)} THR:${tp.threads} ${formatRuntime(tp.runtime)}`
|
|
922
|
+
);
|
|
923
|
+
trackingLines.push(theme.border("\u2500".repeat(contentWidth)));
|
|
924
|
+
} else {
|
|
925
|
+
trackingLines.push(chalk2.yellow(` \u25C9 PID ${opts2.trackedPid} exited`));
|
|
926
|
+
trackingLines.push(theme.border("\u2500".repeat(contentWidth)));
|
|
927
|
+
}
|
|
928
|
+
}
|
|
929
|
+
const availableRows = Math.max(1, targetHeight - headerRowOverhead - tableHeaderOverhead - trackingLines.length);
|
|
930
|
+
let selectedIdx = opts2.selectedProcessIndex ?? -1;
|
|
931
|
+
if (isTracking) {
|
|
932
|
+
const trackedIdx = sorted.findIndex((p) => p.pid === opts2.trackedPid);
|
|
933
|
+
if (trackedIdx >= 0) {
|
|
934
|
+
selectedIdx = trackedIdx;
|
|
935
|
+
}
|
|
936
|
+
}
|
|
937
|
+
let offset = 0;
|
|
938
|
+
if (selectedIdx >= 0) {
|
|
939
|
+
if (selectedIdx >= availableRows) {
|
|
940
|
+
offset = selectedIdx - availableRows + 1;
|
|
941
|
+
}
|
|
942
|
+
}
|
|
943
|
+
const visible = sorted.slice(offset, offset + availableRows);
|
|
880
944
|
const pidW = 6, userW = 7, thrW = 3, memW = 6, cpuW = 6;
|
|
881
945
|
const fixedW = pidW + userW + thrW + memW + cpuW + 5;
|
|
882
946
|
const cmdW = Math.max(8, contentWidth - fixedW);
|
|
883
947
|
const head = chalk2.bold("PID".padEnd(pidW)) + " " + chalk2.bold("PROGRAM".padEnd(cmdW)) + " " + chalk2.bold("USER".padEnd(userW)) + " " + chalk2.bold("THR".padStart(thrW)) + " " + chalk2.bold("MEM%".padStart(memW)) + " " + chalk2.bold("CPU%".padStart(cpuW));
|
|
884
948
|
if (opts2.treeView) {
|
|
885
|
-
const treeLines = buildProcessTree(
|
|
886
|
-
|
|
887
|
-
|
|
949
|
+
const treeLines = buildProcessTree(visible);
|
|
950
|
+
let rightTitle2 = opts2.filter ? `filter: "${opts2.filter}"` : `tree \xB7 sort: ${opts2.sortBy || "cpu"}`;
|
|
951
|
+
if (isTracking) rightTitle2 += ` \xB7 following PID ${opts2.trackedPid}`;
|
|
952
|
+
return panel("P proc", [...trackingLines, head, theme.border("\u2500".repeat(contentWidth)), ...treeLines], width, theme.process, theme.border, targetHeight - 2, rightTitle2);
|
|
888
953
|
}
|
|
889
|
-
const rows =
|
|
954
|
+
const rows = visible.map((p, idx) => {
|
|
955
|
+
const isSelected = offset + idx === selectedIdx;
|
|
890
956
|
const cpuVal = p.cpu.toFixed(1) + "%";
|
|
891
957
|
const cpuStr = p.cpu > 50 ? chalk2.red.bold(cpuVal.padStart(cpuW)) : p.cpu > 20 ? chalk2.yellow(cpuVal.padStart(cpuW)) : chalk2.green(cpuVal.padStart(cpuW));
|
|
892
958
|
const memStr = (p.mem.toFixed(1) + "%").padStart(memW);
|
|
@@ -894,13 +960,17 @@ function btopProcBox(data, width, targetHeight, theme, opts2) {
|
|
|
894
960
|
const thrStr = String(p.threads).padStart(thrW);
|
|
895
961
|
const pidStr = String(p.pid).padEnd(pidW);
|
|
896
962
|
const cmdStr = truncatePlain(p.command, cmdW).padEnd(cmdW);
|
|
897
|
-
|
|
963
|
+
const line = `${pidStr} ${cmdStr} ${userStr} ${thrStr} ${memStr} ${cpuStr}`;
|
|
964
|
+
return isSelected ? chalk2.bgCyan.black(line) : line;
|
|
898
965
|
});
|
|
899
|
-
const lines = [head, theme.border("\u2500".repeat(contentWidth)), ...rows];
|
|
966
|
+
const lines = [...trackingLines, head, theme.border("\u2500".repeat(contentWidth)), ...rows];
|
|
900
967
|
if (rows.length === 0) {
|
|
901
968
|
lines.push(chalk2.dim(`No processes match "${opts2.filter || ""}"`));
|
|
902
969
|
}
|
|
903
|
-
|
|
970
|
+
let rightTitle = opts2.filter ? `filter: "${opts2.filter}"` : `sort: ${opts2.sortBy || "cpu"}`;
|
|
971
|
+
if (isTracking) {
|
|
972
|
+
rightTitle += ` \xB7 following PID ${opts2.trackedPid}`;
|
|
973
|
+
}
|
|
904
974
|
return panel("P proc", lines, width, theme.process, theme.border, targetHeight - 2, rightTitle);
|
|
905
975
|
}
|
|
906
976
|
function formatTable(data, opts2 = {}) {
|
|
@@ -921,24 +991,24 @@ function formatTable(data, opts2 = {}) {
|
|
|
921
991
|
if (activePanel !== "grid") {
|
|
922
992
|
const lines = activeDetailLines(data, activePanel, width, opts2);
|
|
923
993
|
if (lines) {
|
|
924
|
-
out.push(...panel(detailPanelTitle(activePanel), lines, width, theme[activePanel] ?? theme.cpu, theme.border));
|
|
994
|
+
out.push(...panel(detailPanelTitle(activePanel, opts2.trackedPid), lines, width, theme[activePanel] ?? theme.cpu, theme.border));
|
|
925
995
|
}
|
|
926
|
-
return out.join("\n");
|
|
927
|
-
}
|
|
928
|
-
out.push(...btopCpuBox(data, width, theme, opts2));
|
|
929
|
-
out.push("");
|
|
930
|
-
if (width >= 85) {
|
|
931
|
-
const leftColW = Math.max(32, Math.floor(width * 0.38));
|
|
932
|
-
const rightColW = width - leftColW - 2;
|
|
933
|
-
const leftLines = btopLeftColumn(data, leftColW, theme, opts2);
|
|
934
|
-
const procLines = btopProcBox(data, rightColW, leftLines.length, theme, opts2);
|
|
935
|
-
out.push(...hstack([leftLines, procLines], 2, width));
|
|
936
996
|
} else {
|
|
937
|
-
|
|
938
|
-
out.push(...leftLines);
|
|
997
|
+
out.push(...btopCpuBox(data, width, theme, opts2));
|
|
939
998
|
out.push("");
|
|
940
|
-
|
|
941
|
-
|
|
999
|
+
if (width >= 85) {
|
|
1000
|
+
const leftColW = Math.max(32, Math.floor(width * 0.38));
|
|
1001
|
+
const rightColW = width - leftColW - 2;
|
|
1002
|
+
const leftLines = btopLeftColumn(data, leftColW, theme, opts2);
|
|
1003
|
+
const procLines = btopProcBox(data, rightColW, leftLines.length, theme, opts2);
|
|
1004
|
+
out.push(...hstack([leftLines, procLines], 2, width));
|
|
1005
|
+
} else {
|
|
1006
|
+
const leftLines = btopLeftColumn(data, width, theme, opts2);
|
|
1007
|
+
out.push(...leftLines);
|
|
1008
|
+
out.push("");
|
|
1009
|
+
const procLines = btopProcBox(data, width, 12, theme, opts2);
|
|
1010
|
+
out.push(...procLines);
|
|
1011
|
+
}
|
|
942
1012
|
}
|
|
943
1013
|
return out.join("\n");
|
|
944
1014
|
}
|
|
@@ -2311,6 +2381,7 @@ var History = class _History {
|
|
|
2311
2381
|
|
|
2312
2382
|
// src/live/state.ts
|
|
2313
2383
|
var SIGNAL_OPTIONS = ["SIGTERM", "SIGKILL", "SIGINT", "SIGHUP", "SIGSTOP", "SIGCONT"];
|
|
2384
|
+
var MENU_OPTIONS = ["Resume Dashboard", "Settings (Customizer)", "Readme", "Credits", "Quit pyre"];
|
|
2314
2385
|
var config = readConfig();
|
|
2315
2386
|
var state = {
|
|
2316
2387
|
intervalHandle: null,
|
|
@@ -2350,6 +2421,10 @@ var state = {
|
|
|
2350
2421
|
termHeight: process.stdout.rows || 24,
|
|
2351
2422
|
sortMode: config.sortMode,
|
|
2352
2423
|
processFilter: "",
|
|
2424
|
+
processSelectionIndex: 0,
|
|
2425
|
+
processScrollOffset: 0,
|
|
2426
|
+
trackedPid: null,
|
|
2427
|
+
inspectingProcess: null,
|
|
2353
2428
|
inputMode: null,
|
|
2354
2429
|
inputBuffer: "",
|
|
2355
2430
|
targetPid: "",
|
|
@@ -2415,7 +2490,9 @@ var state = {
|
|
|
2415
2490
|
anomalyHistory: [],
|
|
2416
2491
|
splashEnabled: config.splashEnabled,
|
|
2417
2492
|
splashColorScheme: config.splashColorScheme,
|
|
2418
|
-
splashAnimation: config.splashAnimation
|
|
2493
|
+
splashAnimation: config.splashAnimation,
|
|
2494
|
+
menuSelectionIndex: 0,
|
|
2495
|
+
readmeScrollOffset: 0
|
|
2419
2496
|
};
|
|
2420
2497
|
function setStatus(msg, ms = 3e3) {
|
|
2421
2498
|
state.statusMessage = msg;
|
|
@@ -2570,6 +2647,9 @@ function writeLogRow(data) {
|
|
|
2570
2647
|
|
|
2571
2648
|
// src/live/render.ts
|
|
2572
2649
|
import { execFile, exec } from "child_process";
|
|
2650
|
+
import fs3 from "fs";
|
|
2651
|
+
import path3 from "path";
|
|
2652
|
+
import { fileURLToPath } from "url";
|
|
2573
2653
|
import chalk4 from "chalk";
|
|
2574
2654
|
|
|
2575
2655
|
// src/anomalies.ts
|
|
@@ -2679,6 +2759,9 @@ function tableCacheParams() {
|
|
|
2679
2759
|
return [
|
|
2680
2760
|
state.sortMode,
|
|
2681
2761
|
state.processFilter || "",
|
|
2762
|
+
state.processSelectionIndex,
|
|
2763
|
+
state.trackedPid || "",
|
|
2764
|
+
state.inspectingProcess ? state.inspectingProcess.pid : "",
|
|
2682
2765
|
limit,
|
|
2683
2766
|
state.currentTheme,
|
|
2684
2767
|
state.activePanel,
|
|
@@ -2798,12 +2881,39 @@ function render() {
|
|
|
2798
2881
|
writeFrame(out);
|
|
2799
2882
|
return;
|
|
2800
2883
|
}
|
|
2884
|
+
if (state.inputMode === "menu") {
|
|
2885
|
+
writeFrame(renderSplashMenu(cols, rows));
|
|
2886
|
+
return;
|
|
2887
|
+
}
|
|
2888
|
+
if (state.inputMode === "readme") {
|
|
2889
|
+
writeFrame(renderReadme(cols, rows));
|
|
2890
|
+
return;
|
|
2891
|
+
}
|
|
2892
|
+
if (state.inputMode === "credits") {
|
|
2893
|
+
writeFrame(renderCredits(cols, rows));
|
|
2894
|
+
return;
|
|
2895
|
+
}
|
|
2801
2896
|
const lines = [];
|
|
2802
2897
|
const theme = THEMES[state.currentTheme] || THEMES.default;
|
|
2803
2898
|
const params = tableCacheParams();
|
|
2804
2899
|
const anomalies = detectAnomalies(state.lastData, state.history);
|
|
2900
|
+
if (anomalies.length > 0) {
|
|
2901
|
+
for (const a of anomalies) {
|
|
2902
|
+
const now = /* @__PURE__ */ new Date();
|
|
2903
|
+
const alertWithTime = { ...a, timestamp: now };
|
|
2904
|
+
const exists = state.anomalyHistory.some(
|
|
2905
|
+
(h) => h.metric === a.metric && Math.abs(h.zScore - a.zScore) < 0.1 && now.getTime() - (h.timestamp?.getTime() || 0) < 1e4
|
|
2906
|
+
);
|
|
2907
|
+
if (!exists) {
|
|
2908
|
+
state.anomalyHistory.unshift(alertWithTime);
|
|
2909
|
+
}
|
|
2910
|
+
}
|
|
2911
|
+
if (state.anomalyHistory.length > 100) {
|
|
2912
|
+
state.anomalyHistory.length = 100;
|
|
2913
|
+
}
|
|
2914
|
+
}
|
|
2805
2915
|
const anomalyCacheKey = anomalies.map((a) => `${a.metric}:${a.zScore.toFixed(2)}`).join(",");
|
|
2806
|
-
const cacheParams = params + "|" + anomalyCacheKey;
|
|
2916
|
+
const cacheParams = params + "|" + anomalyCacheKey + "|" + state.anomalyHistory.length;
|
|
2807
2917
|
const tableStr = _tableDataDirty || state.lastData !== _cachedTableData || cacheParams !== _cachedTableParams ? (() => {
|
|
2808
2918
|
const out = formatTable(state.lastData, {
|
|
2809
2919
|
width: state.termWidth,
|
|
@@ -2819,7 +2929,10 @@ function render() {
|
|
|
2819
2929
|
tempUnit: state.tempUnit,
|
|
2820
2930
|
history: state.history,
|
|
2821
2931
|
graphMode: state.graphMode,
|
|
2822
|
-
panelLayout: state.panelLayout
|
|
2932
|
+
panelLayout: state.panelLayout,
|
|
2933
|
+
selectedProcessIndex: state.processSelectionIndex,
|
|
2934
|
+
trackedPid: state.trackedPid,
|
|
2935
|
+
inspectProcess: state.inspectingProcess
|
|
2823
2936
|
});
|
|
2824
2937
|
_cachedTableData = state.lastData;
|
|
2825
2938
|
_cachedTableParams = cacheParams;
|
|
@@ -2991,11 +3104,100 @@ function checkAlerts(data) {
|
|
|
2991
3104
|
state.alerted = false;
|
|
2992
3105
|
}
|
|
2993
3106
|
}
|
|
3107
|
+
function renderSplashMenu(cols, rows) {
|
|
3108
|
+
const out = [];
|
|
3109
|
+
const contentLines = [];
|
|
3110
|
+
const logo = [
|
|
3111
|
+
chalk4.hex("#ff6004").bold("\u2588\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2557 \u2588\u2588\u2557\u2588\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557"),
|
|
3112
|
+
chalk4.hex("#ff8004").bold("\u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2557\u255A\u2588\u2588\u2557 \u2588\u2588\u2554\u255D\u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2557\u2588\u2588\u2554\u2550\u2550\u2550\u2550\u255D"),
|
|
3113
|
+
chalk4.hex("#ffa004").bold("\u2588\u2588\u2588\u2588\u2588\u2588\u2554\u255D \u255A\u2588\u2588\u2588\u2588\u2554\u255D \u2588\u2588\u2588\u2588\u2588\u2588\u2554\u255D\u2588\u2588\u2588\u2588\u2588\u2557 "),
|
|
3114
|
+
chalk4.hex("#ffc004").bold("\u2588\u2588\u2554\u2550\u2550\u2550\u255D \u255A\u2588\u2588\u2554\u255D \u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2557\u2588\u2588\u2554\u2550\u2550\u255D "),
|
|
3115
|
+
chalk4.hex("#ffe004").bold("\u2588\u2588\u2551 \u2588\u2588\u2551 \u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557"),
|
|
3116
|
+
chalk4.hex("#ffff40").bold("\u255A\u2550\u255D \u255A\u2550\u255D \u255A\u2550\u255D \u255A\u2550\u255D\u255A\u2550\u2550\u2550\u2550\u2550\u2550\u255D")
|
|
3117
|
+
];
|
|
3118
|
+
const menuTop = Math.max(0, Math.floor(rows / 2) - 8);
|
|
3119
|
+
for (let i = 0; i < menuTop; i++) out.push("");
|
|
3120
|
+
for (const line of logo) contentLines.push(line);
|
|
3121
|
+
contentLines.push("");
|
|
3122
|
+
contentLines.push(chalk4.dim("system monitor v9.0.0"));
|
|
3123
|
+
contentLines.push("");
|
|
3124
|
+
contentLines.push("");
|
|
3125
|
+
for (let i = 0; i < MENU_OPTIONS.length; i++) {
|
|
3126
|
+
const isSelected = i === state.menuSelectionIndex;
|
|
3127
|
+
const opt = MENU_OPTIONS[i];
|
|
3128
|
+
const prefix = isSelected ? chalk4.cyan.bold(" \u25B6 ") : " ";
|
|
3129
|
+
const text = isSelected ? chalk4.bgCyan.black(` ${opt} `) : chalk4.dim(` ${opt} `);
|
|
3130
|
+
contentLines.push(prefix + text);
|
|
3131
|
+
}
|
|
3132
|
+
contentLines.push("");
|
|
3133
|
+
contentLines.push("");
|
|
3134
|
+
contentLines.push(chalk4.dim("Use \u2191/\u2193 to navigate, Enter to select"));
|
|
3135
|
+
while (contentLines.length + menuTop < rows) contentLines.push("");
|
|
3136
|
+
const maxWidth = Math.max(...contentLines.map(visLen));
|
|
3137
|
+
const padding = Math.max(0, Math.floor((cols - maxWidth) / 2));
|
|
3138
|
+
const padStr = " ".repeat(padding);
|
|
3139
|
+
const fit = (l) => padStr + fitVisible(l, cols - padding);
|
|
3140
|
+
for (const line of contentLines) out.push(fit(line));
|
|
3141
|
+
return out;
|
|
3142
|
+
}
|
|
3143
|
+
var cachedReadmeLines = null;
|
|
3144
|
+
function getReadmeLines() {
|
|
3145
|
+
if (cachedReadmeLines) return cachedReadmeLines;
|
|
3146
|
+
try {
|
|
3147
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
3148
|
+
const __dirname = path3.dirname(__filename);
|
|
3149
|
+
const rootDir = path3.resolve(__dirname, "..", "..");
|
|
3150
|
+
const readmePath = path3.join(rootDir, "README.md");
|
|
3151
|
+
const content = fs3.readFileSync(readmePath, "utf8");
|
|
3152
|
+
cachedReadmeLines = content.split("\n");
|
|
3153
|
+
return cachedReadmeLines;
|
|
3154
|
+
} catch (err) {
|
|
3155
|
+
return [chalk4.red("Failed to load README.md")];
|
|
3156
|
+
}
|
|
3157
|
+
}
|
|
3158
|
+
function renderReadme(cols, rows) {
|
|
3159
|
+
const lines = getReadmeLines();
|
|
3160
|
+
const availableLines = Math.max(1, rows - 2);
|
|
3161
|
+
const startIdx = Math.min(state.readmeScrollOffset, Math.max(0, lines.length - availableLines));
|
|
3162
|
+
state.readmeScrollOffset = startIdx;
|
|
3163
|
+
const content = lines.slice(startIdx, startIdx + availableLines).map((l) => {
|
|
3164
|
+
let out2 = l;
|
|
3165
|
+
if (out2.startsWith("#")) {
|
|
3166
|
+
out2 = chalk4.cyan.bold(out2);
|
|
3167
|
+
} else if (out2.startsWith("```")) {
|
|
3168
|
+
out2 = chalk4.dim(out2);
|
|
3169
|
+
} else if (out2.startsWith("- ") || out2.startsWith("* ")) {
|
|
3170
|
+
out2 = " " + chalk4.yellow(out2.substring(0, 2)) + out2.substring(2);
|
|
3171
|
+
}
|
|
3172
|
+
return out2;
|
|
3173
|
+
});
|
|
3174
|
+
const out = [];
|
|
3175
|
+
const pct = Math.round(startIdx / Math.max(1, lines.length - availableLines) * 100);
|
|
3176
|
+
const title = lines.length > availableLines ? `README (${pct}%)` : "README";
|
|
3177
|
+
out.push(...panel(title, content, cols, chalk4.cyan, chalk4.dim, availableLines));
|
|
3178
|
+
return out;
|
|
3179
|
+
}
|
|
3180
|
+
function renderCredits(cols, rows) {
|
|
3181
|
+
const out = [];
|
|
3182
|
+
const content = [
|
|
3183
|
+
chalk4.bold.hex("#ff6004")("Pyre - The Terminal System Monitor"),
|
|
3184
|
+
"",
|
|
3185
|
+
"Created with \u2764\uFE0F using Node.js",
|
|
3186
|
+
"",
|
|
3187
|
+
chalk4.cyan("Libraries used:"),
|
|
3188
|
+
" - chalk (Terminal styling)",
|
|
3189
|
+
" - systeminformation (System metrics)",
|
|
3190
|
+
"",
|
|
3191
|
+
chalk4.dim("Press Esc or Enter to return to menu.")
|
|
3192
|
+
];
|
|
3193
|
+
out.push(...panel("CREDITS", content, cols, chalk4.magenta, chalk4.dim, rows - 2));
|
|
3194
|
+
return out;
|
|
3195
|
+
}
|
|
2994
3196
|
|
|
2995
3197
|
// src/p2p/server.ts
|
|
2996
3198
|
import net from "net";
|
|
2997
3199
|
import tls from "tls";
|
|
2998
|
-
import
|
|
3200
|
+
import fs4 from "fs";
|
|
2999
3201
|
import crypto2 from "crypto";
|
|
3000
3202
|
import chalk5 from "chalk";
|
|
3001
3203
|
|
|
@@ -3140,9 +3342,9 @@ var P2PServer = class {
|
|
|
3140
3342
|
async start() {
|
|
3141
3343
|
if (this.options.auditLog) {
|
|
3142
3344
|
try {
|
|
3143
|
-
|
|
3345
|
+
fs4.mkdirSync(this.options.auditLog, { recursive: true });
|
|
3144
3346
|
const logFile = `${this.options.auditLog}/p2p-audit.log`;
|
|
3145
|
-
this.auditStream =
|
|
3347
|
+
this.auditStream = fs4.createWriteStream(logFile, { flags: "a" });
|
|
3146
3348
|
} catch {
|
|
3147
3349
|
this.log(chalk5.yellow("Warning: could not open audit log"));
|
|
3148
3350
|
}
|
|
@@ -3151,11 +3353,11 @@ var P2PServer = class {
|
|
|
3151
3353
|
const useTLS = !!(this.options.tlsCert && this.options.tlsKey);
|
|
3152
3354
|
if (useTLS) {
|
|
3153
3355
|
const tlsOptions = {
|
|
3154
|
-
key:
|
|
3155
|
-
cert:
|
|
3356
|
+
key: fs4.readFileSync(this.options.tlsKey),
|
|
3357
|
+
cert: fs4.readFileSync(this.options.tlsCert)
|
|
3156
3358
|
};
|
|
3157
3359
|
if (this.options.tlsCA) {
|
|
3158
|
-
tlsOptions.ca =
|
|
3360
|
+
tlsOptions.ca = fs4.readFileSync(this.options.tlsCA);
|
|
3159
3361
|
}
|
|
3160
3362
|
this.server = tls.createServer(tlsOptions, (socket) => this.onConnection(socket));
|
|
3161
3363
|
} else {
|
|
@@ -3423,7 +3625,7 @@ async function startP2PServer(options) {
|
|
|
3423
3625
|
// src/p2p/client.ts
|
|
3424
3626
|
import net2 from "net";
|
|
3425
3627
|
import tls2 from "tls";
|
|
3426
|
-
import
|
|
3628
|
+
import fs5 from "fs";
|
|
3427
3629
|
import crypto3 from "crypto";
|
|
3428
3630
|
import chalk6 from "chalk";
|
|
3429
3631
|
var P2PClient = class {
|
|
@@ -3451,9 +3653,9 @@ var P2PClient = class {
|
|
|
3451
3653
|
async connect() {
|
|
3452
3654
|
if (this.options.auditLog) {
|
|
3453
3655
|
try {
|
|
3454
|
-
|
|
3656
|
+
fs5.mkdirSync(this.options.auditLog, { recursive: true });
|
|
3455
3657
|
const logFile = `${this.options.auditLog}/p2p-client-audit.log`;
|
|
3456
|
-
this.auditStream =
|
|
3658
|
+
this.auditStream = fs5.createWriteStream(logFile, { flags: "a" });
|
|
3457
3659
|
} catch {
|
|
3458
3660
|
console.log(chalk6.yellow("Warning: could not open audit log"));
|
|
3459
3661
|
}
|
|
@@ -3468,7 +3670,7 @@ var P2PClient = class {
|
|
|
3468
3670
|
rejectUnauthorized: !this.options.tlsInsecure
|
|
3469
3671
|
};
|
|
3470
3672
|
if (this.options.tlsCA) {
|
|
3471
|
-
tlsOptions.ca =
|
|
3673
|
+
tlsOptions.ca = fs5.readFileSync(this.options.tlsCA);
|
|
3472
3674
|
}
|
|
3473
3675
|
this.socket = tls2.connect(tlsOptions, () => {
|
|
3474
3676
|
this.running = true;
|
|
@@ -3751,6 +3953,68 @@ function handleInputModeKey(str, key) {
|
|
|
3751
3953
|
render();
|
|
3752
3954
|
return;
|
|
3753
3955
|
}
|
|
3956
|
+
if (state.inputMode === "menu") {
|
|
3957
|
+
if (isEscKey(key, str)) {
|
|
3958
|
+
state.inputMode = null;
|
|
3959
|
+
render();
|
|
3960
|
+
return;
|
|
3961
|
+
}
|
|
3962
|
+
if (isUpKey(key, str)) {
|
|
3963
|
+
state.menuSelectionIndex = (state.menuSelectionIndex - 1 + MENU_OPTIONS.length) % MENU_OPTIONS.length;
|
|
3964
|
+
render();
|
|
3965
|
+
return;
|
|
3966
|
+
}
|
|
3967
|
+
if (isDownKey(key, str)) {
|
|
3968
|
+
state.menuSelectionIndex = (state.menuSelectionIndex + 1) % MENU_OPTIONS.length;
|
|
3969
|
+
render();
|
|
3970
|
+
return;
|
|
3971
|
+
}
|
|
3972
|
+
if (isEnterKey(key, str) || str === " ") {
|
|
3973
|
+
const option = MENU_OPTIONS[state.menuSelectionIndex];
|
|
3974
|
+
switch (option) {
|
|
3975
|
+
case "Resume Dashboard":
|
|
3976
|
+
state.inputMode = null;
|
|
3977
|
+
break;
|
|
3978
|
+
case "Settings (Customizer)":
|
|
3979
|
+
state.inputMode = "customizer";
|
|
3980
|
+
state.customizerIndex = 0;
|
|
3981
|
+
break;
|
|
3982
|
+
case "Readme":
|
|
3983
|
+
state.inputMode = "readme";
|
|
3984
|
+
break;
|
|
3985
|
+
case "Credits":
|
|
3986
|
+
state.inputMode = "credits";
|
|
3987
|
+
break;
|
|
3988
|
+
case "Quit pyre":
|
|
3989
|
+
process.stdout.write("\x1B[2J\x1B[3J\x1B[H");
|
|
3990
|
+
process.exit(0);
|
|
3991
|
+
}
|
|
3992
|
+
render();
|
|
3993
|
+
return;
|
|
3994
|
+
}
|
|
3995
|
+
render();
|
|
3996
|
+
return;
|
|
3997
|
+
}
|
|
3998
|
+
if (state.inputMode === "readme" || state.inputMode === "credits") {
|
|
3999
|
+
if (isEscKey(key, str) || isEnterKey(key, str)) {
|
|
4000
|
+
state.inputMode = "menu";
|
|
4001
|
+
render();
|
|
4002
|
+
return;
|
|
4003
|
+
}
|
|
4004
|
+
if (state.inputMode === "readme") {
|
|
4005
|
+
if (isUpKey(key, str)) {
|
|
4006
|
+
state.readmeScrollOffset = Math.max(0, state.readmeScrollOffset - 1);
|
|
4007
|
+
render();
|
|
4008
|
+
return;
|
|
4009
|
+
}
|
|
4010
|
+
if (isDownKey(key, str)) {
|
|
4011
|
+
state.readmeScrollOffset += 1;
|
|
4012
|
+
render();
|
|
4013
|
+
return;
|
|
4014
|
+
}
|
|
4015
|
+
}
|
|
4016
|
+
return;
|
|
4017
|
+
}
|
|
3754
4018
|
if (state.inputMode === "signal") {
|
|
3755
4019
|
if (isUpKey(key, str)) {
|
|
3756
4020
|
const idx = state.SIGNAL_OPTIONS.indexOf(state.inputBuffer);
|
|
@@ -4172,11 +4436,72 @@ async function startLive(opts2, splashPromise) {
|
|
|
4172
4436
|
case "tab":
|
|
4173
4437
|
cycleTab(1);
|
|
4174
4438
|
break;
|
|
4439
|
+
case "up":
|
|
4440
|
+
if (state.lastData?.processes?.length) {
|
|
4441
|
+
state.trackedPid = null;
|
|
4442
|
+
state.processSelectionIndex = Math.max(0, state.processSelectionIndex - 1);
|
|
4443
|
+
render();
|
|
4444
|
+
}
|
|
4445
|
+
break;
|
|
4446
|
+
case "down":
|
|
4447
|
+
if (state.lastData?.processes?.length) {
|
|
4448
|
+
state.trackedPid = null;
|
|
4449
|
+
const count = state.lastData.processes.length;
|
|
4450
|
+
state.processSelectionIndex = Math.min(count - 1, state.processSelectionIndex + 1);
|
|
4451
|
+
render();
|
|
4452
|
+
}
|
|
4453
|
+
break;
|
|
4454
|
+
case "space":
|
|
4455
|
+
case " ":
|
|
4456
|
+
if (state.lastData?.processes?.length && state.processSelectionIndex >= 0) {
|
|
4457
|
+
const sorted = state.lastData.processes;
|
|
4458
|
+
const proc = sorted[state.processSelectionIndex];
|
|
4459
|
+
if (proc) {
|
|
4460
|
+
if (state.trackedPid === proc.pid) {
|
|
4461
|
+
state.trackedPid = null;
|
|
4462
|
+
setStatus(`Stopped following PID ${proc.pid}`);
|
|
4463
|
+
} else {
|
|
4464
|
+
state.trackedPid = proc.pid;
|
|
4465
|
+
setStatus(`Following PID ${proc.pid} (${proc.command})`);
|
|
4466
|
+
}
|
|
4467
|
+
render();
|
|
4468
|
+
}
|
|
4469
|
+
}
|
|
4470
|
+
break;
|
|
4471
|
+
case "return":
|
|
4472
|
+
case "enter":
|
|
4473
|
+
if (state.inspectingProcess) {
|
|
4474
|
+
state.inspectingProcess = null;
|
|
4475
|
+
render();
|
|
4476
|
+
} else if (state.lastData?.processes?.length && state.processSelectionIndex >= 0) {
|
|
4477
|
+
const sorted = state.lastData.processes;
|
|
4478
|
+
const proc = sorted[state.processSelectionIndex];
|
|
4479
|
+
if (proc) {
|
|
4480
|
+
state.inspectingProcess = proc;
|
|
4481
|
+
state.trackedPid = proc.pid;
|
|
4482
|
+
setStatus(`Inspecting & following PID ${proc.pid}`);
|
|
4483
|
+
render();
|
|
4484
|
+
}
|
|
4485
|
+
}
|
|
4486
|
+
break;
|
|
4175
4487
|
case "escape":
|
|
4176
4488
|
case "esc":
|
|
4177
|
-
state.
|
|
4178
|
-
|
|
4179
|
-
|
|
4489
|
+
if (state.inspectingProcess) {
|
|
4490
|
+
state.inspectingProcess = null;
|
|
4491
|
+
render();
|
|
4492
|
+
} else if (state.trackedPid !== null) {
|
|
4493
|
+
state.trackedPid = null;
|
|
4494
|
+
setStatus("Stopped following process");
|
|
4495
|
+
render();
|
|
4496
|
+
} else if (state.activePanel !== "grid") {
|
|
4497
|
+
state.activePanel = "grid";
|
|
4498
|
+
setStatus("Grid view");
|
|
4499
|
+
render();
|
|
4500
|
+
} else {
|
|
4501
|
+
state.inputMode = "menu";
|
|
4502
|
+
state.menuSelectionIndex = 0;
|
|
4503
|
+
render();
|
|
4504
|
+
}
|
|
4180
4505
|
break;
|
|
4181
4506
|
default:
|
|
4182
4507
|
if (str && str.length === 1) {
|
|
@@ -4193,7 +4518,7 @@ async function startLive(opts2, splashPromise) {
|
|
|
4193
4518
|
process.once("SIGINT", () => stopLive());
|
|
4194
4519
|
}
|
|
4195
4520
|
function tabKeyToId(str) {
|
|
4196
|
-
const map = { "1": "cpu", "2": "mem", "3": "gpu", "4": "power", "5": "battery", "6": "thermal", "7": "network", "8": "packets", "9": "tasks", "0": "disk", "p": "process", "r": "p2p" };
|
|
4521
|
+
const map = { "1": "cpu", "2": "mem", "3": "gpu", "4": "power", "5": "battery", "6": "thermal", "7": "network", "8": "packets", "9": "tasks", "0": "disk", "p": "process", "r": "p2p", "A": "anomalies" };
|
|
4197
4522
|
return map[str] ?? null;
|
|
4198
4523
|
}
|
|
4199
4524
|
function cycleTab(direction) {
|
|
@@ -4211,6 +4536,10 @@ function handleNormalMouse(seq) {
|
|
|
4211
4536
|
const cy = seq.charCodeAt(5) - 32;
|
|
4212
4537
|
if (cb === 0 || cb === 1) {
|
|
4213
4538
|
handleMouseClick(cy, cx);
|
|
4539
|
+
} else if (cb === 64) {
|
|
4540
|
+
scrollProcessSelection(-1);
|
|
4541
|
+
} else if (cb === 65) {
|
|
4542
|
+
scrollProcessSelection(1);
|
|
4214
4543
|
}
|
|
4215
4544
|
}
|
|
4216
4545
|
function handleSGRMouse(seq) {
|
|
@@ -4221,6 +4550,18 @@ function handleSGRMouse(seq) {
|
|
|
4221
4550
|
const cy = parseInt(match[3]) - 1;
|
|
4222
4551
|
if (button === 0 || button === 1) {
|
|
4223
4552
|
handleMouseClick(cy, cx);
|
|
4553
|
+
} else if (button === 64) {
|
|
4554
|
+
scrollProcessSelection(-1);
|
|
4555
|
+
} else if (button === 65) {
|
|
4556
|
+
scrollProcessSelection(1);
|
|
4557
|
+
}
|
|
4558
|
+
}
|
|
4559
|
+
function scrollProcessSelection(dir) {
|
|
4560
|
+
if (state.lastData?.processes?.length) {
|
|
4561
|
+
state.trackedPid = null;
|
|
4562
|
+
const count = state.lastData.processes.length;
|
|
4563
|
+
state.processSelectionIndex = Math.max(0, Math.min(count - 1, state.processSelectionIndex + dir));
|
|
4564
|
+
render();
|
|
4224
4565
|
}
|
|
4225
4566
|
}
|
|
4226
4567
|
function handleMouseClick(y, x) {
|
|
@@ -4601,8 +4942,8 @@ async function showSplash(config3) {
|
|
|
4601
4942
|
}
|
|
4602
4943
|
|
|
4603
4944
|
// src/historyCmd.ts
|
|
4604
|
-
import
|
|
4605
|
-
import
|
|
4945
|
+
import fs6 from "fs";
|
|
4946
|
+
import path4 from "path";
|
|
4606
4947
|
import chalk8 from "chalk";
|
|
4607
4948
|
function runHistoryCommand(opts2 = {}) {
|
|
4608
4949
|
const days = opts2.days || 7;
|
|
@@ -4610,11 +4951,11 @@ function runHistoryCommand(opts2 = {}) {
|
|
|
4610
4951
|
console.log(chalk8.bold(`
|
|
4611
4952
|
pyre history \u2014 Past ${days} Days Trend
|
|
4612
4953
|
`));
|
|
4613
|
-
if (!
|
|
4954
|
+
if (!fs6.existsSync(dir)) {
|
|
4614
4955
|
console.log(chalk8.yellow(` No logs directory found at ${dir}`));
|
|
4615
4956
|
return;
|
|
4616
4957
|
}
|
|
4617
|
-
const files =
|
|
4958
|
+
const files = fs6.readdirSync(dir).filter((f) => f.startsWith("pyre-log-") && f.endsWith(".csv"));
|
|
4618
4959
|
if (files.length === 0) {
|
|
4619
4960
|
console.log(chalk8.yellow(` No CSV logs found in ${dir}`));
|
|
4620
4961
|
return;
|
|
@@ -4624,9 +4965,9 @@ function runHistoryCommand(opts2 = {}) {
|
|
|
4624
4965
|
const memPoints = [];
|
|
4625
4966
|
const tempPoints = [];
|
|
4626
4967
|
for (const file of files.sort()) {
|
|
4627
|
-
const fullPath =
|
|
4968
|
+
const fullPath = path4.join(dir, file);
|
|
4628
4969
|
try {
|
|
4629
|
-
const content =
|
|
4970
|
+
const content = fs6.readFileSync(fullPath, "utf-8");
|
|
4630
4971
|
const lines = content.split("\n").slice(1);
|
|
4631
4972
|
for (const line of lines) {
|
|
4632
4973
|
if (!line.trim()) continue;
|
|
@@ -4661,7 +5002,7 @@ function runHistoryCommand(opts2 = {}) {
|
|
|
4661
5002
|
}
|
|
4662
5003
|
|
|
4663
5004
|
// src/diffCmd.ts
|
|
4664
|
-
import
|
|
5005
|
+
import fs7 from "fs";
|
|
4665
5006
|
import chalk9 from "chalk";
|
|
4666
5007
|
function runDiffCommand(file1, file2) {
|
|
4667
5008
|
console.log(chalk9.bold(`
|
|
@@ -4671,8 +5012,8 @@ function runDiffCommand(file1, file2) {
|
|
|
4671
5012
|
console.log(chalk9.dim(` Snapshot B: ${file2}
|
|
4672
5013
|
`));
|
|
4673
5014
|
try {
|
|
4674
|
-
const dataA = JSON.parse(
|
|
4675
|
-
const dataB = JSON.parse(
|
|
5015
|
+
const dataA = JSON.parse(fs7.readFileSync(file1, "utf-8"));
|
|
5016
|
+
const dataB = JSON.parse(fs7.readFileSync(file2, "utf-8"));
|
|
4676
5017
|
const diffNum = (label, valA, valB, unit = "") => {
|
|
4677
5018
|
const delta = valB - valA;
|
|
4678
5019
|
const sign = delta > 0 ? "+" : "";
|
|
@@ -4696,8 +5037,8 @@ function runDiffCommand(file1, file2) {
|
|
|
4696
5037
|
}
|
|
4697
5038
|
|
|
4698
5039
|
// src/xbar.ts
|
|
4699
|
-
import
|
|
4700
|
-
import
|
|
5040
|
+
import fs8 from "fs";
|
|
5041
|
+
import path5 from "path";
|
|
4701
5042
|
import os2 from "os";
|
|
4702
5043
|
import chalk10 from "chalk";
|
|
4703
5044
|
function generateXbarPlugin() {
|
|
@@ -4734,11 +5075,11 @@ echo "\u{1F525} C:\${CPU}% M:\${MEM}% T:\${TEMP}\xB0C | font=Menlo"
|
|
|
4734
5075
|
echo "---"
|
|
4735
5076
|
echo "Open Dashboard | bash='${nodePath}' param1='${pyrePath}' param2='live' terminal=true"
|
|
4736
5077
|
`;
|
|
4737
|
-
const pluginDir =
|
|
5078
|
+
const pluginDir = path5.join(os2.homedir(), "Library", "Application Support", "xbar", "plugins");
|
|
4738
5079
|
const filename = "pyre-monitor.2s.sh";
|
|
4739
|
-
const outPath =
|
|
4740
|
-
|
|
4741
|
-
|
|
5080
|
+
const outPath = path5.join(process.cwd(), filename);
|
|
5081
|
+
fs8.writeFileSync(outPath, script);
|
|
5082
|
+
fs8.chmodSync(outPath, "755");
|
|
4742
5083
|
console.log(chalk10.green(`Generated xbar plugin script at ${outPath}`));
|
|
4743
5084
|
console.log(`To install, move it to your xbar plugins directory:`);
|
|
4744
5085
|
console.log(chalk10.cyan(` mv ${filename} "${pluginDir}/"`));
|
|
@@ -4774,7 +5115,7 @@ function runFleetCommand(hosts) {
|
|
|
4774
5115
|
|
|
4775
5116
|
// src/index.ts
|
|
4776
5117
|
var config2 = readConfig();
|
|
4777
|
-
var pkg = JSON.parse(
|
|
5118
|
+
var pkg = JSON.parse(fs9.readFileSync(new URL("../package.json", import.meta.url), "utf-8"));
|
|
4778
5119
|
var program = new Command();
|
|
4779
5120
|
program.name("pyre").version(pkg.version).description("Mac system monitoring CLI: interactive live dashboard, stats, graphs, export, packet monitor, battery predictor").option("-j, --json", "Output as JSON").option("--html", "Output as HTML").option("--md", "Output as Markdown").option("-c, --csv", "Output as CSV").option("-t, --tsv", "Output as TSV").option("--detailed", "Include detailed system info and sensor readings").option("--theme <name>", "Default theme for live mode (default, dracula, cyberpunk, monochrome, nord, gruvbox)", config2.theme).option("--interval <seconds>", "Refresh interval for live mode", String(config2.interval)).option("--once", "Show a single static snapshot instead of live feed").option("--out <file>", "Also write the snapshot output to a file (--once/--json/--csv/--tsv modes)").option("--export-dir <dir>", "Directory used for live-mode snapshot exports and logs", config2.exportDir).option("--log", "Start continuous CSV logging immediately when live mode starts").option("--tree", "Show process tree view instead of flat list").option("--sort <key>", "Sort processes by: cpu, mem, pid, user, command, state, threads, runtime", config2.sortMode).option("--packets", "Include packet monitor panel in output").option("--limit <n>", "Max number of processes to include in --once/--json/--csv/--tsv snapshots (0 = all)", "10").option("--alert-cpu <pct>", "CPU usage alert threshold (default: 90)", String(config2.cpuAlertPct)).option("--alert-temp <c>", "CPU temperature alert threshold in Celsius (default: 95)", String(config2.tempAlertC)).option("--temp-unit <unit>", "Temperature display unit: c or f (default: c)", "c").option("--p2p-host <host>", "P2P host address (server: bind address, client: server address)").option("--p2p-port <port>", "P2P port number", "9876").option("--p2p-password <password>", "Password for P2P authentication").option("--p2p-tls", "Enable TLS encryption for P2P connections").option("--p2p-cert <file>", "TLS certificate file (PEM) for P2P server").option("--p2p-key <file>", "TLS private key file (PEM) for P2P server").option("--p2p-ca <file>", "TLS CA certificate file (PEM) for P2P client").option("--p2p-insecure", "Skip TLS certificate verification (client only)").option("--p2p-rate-limit <n>", "Max auth attempts per IP per minute (default: 5)", "5").option("--p2p-allow <ips>", "Comma-separated list of allowed IPs (empty = all)").option("--p2p-deny <ips>", "Comma-separated list of denied IPs").option("--p2p-audit-log <dir>", "Directory for P2P audit logs").option("--p2p-hmac-key <key>", "HMAC key for message signing (default: derived from password)").option("--since <range>", "Time range for anomalies digest (e.g. 1d, 7d, yesterday)").option("--plain", "Output in plain accessible text without ANSI colors or line-drawing characters").option("--a11y", "Alias for --plain").option("--webhook-url <url>", "URL to POST to on alert").option("--alert-cmd <cmd>", "Command to execute on alert").option("--port <port>", "Port number for web server mode", "3000");
|
|
4780
5121
|
program.addHelpText("after", `
|
|
@@ -4861,7 +5202,7 @@ async function runServerCommand() {
|
|
|
4861
5202
|
async function main() {
|
|
4862
5203
|
const cmd = program.args[0];
|
|
4863
5204
|
if (cmd === "anomalies") {
|
|
4864
|
-
const { runAnomaliesDigest } = await import("./anomaliesCmd-
|
|
5205
|
+
const { runAnomaliesDigest } = await import("./anomaliesCmd-25OFKYPK.js");
|
|
4865
5206
|
runAnomaliesDigest({ since: opts.since || "7d", dir: opts.exportDir });
|
|
4866
5207
|
return;
|
|
4867
5208
|
}
|
|
@@ -4958,7 +5299,7 @@ async function main() {
|
|
|
4958
5299
|
const cfg = readConfig();
|
|
4959
5300
|
console.log(JSON.stringify(cfg, null, 2));
|
|
4960
5301
|
} else if (sub === "reset") {
|
|
4961
|
-
|
|
5302
|
+
fs9.rmSync(CONFIG_FILE, { force: true });
|
|
4962
5303
|
console.log(chalk12.green("Config reset to defaults"));
|
|
4963
5304
|
} else {
|
|
4964
5305
|
console.log("Usage: pyre config <show|reset>");
|
|
@@ -5055,7 +5396,7 @@ async function main() {
|
|
|
5055
5396
|
else output = formatTable(data, { width: process.stdout.columns || 80, sortBy: opts.sort, treeView: opts.tree ?? config2.treeView, visible: { packets: opts.packets ? true : void 0 } });
|
|
5056
5397
|
console.log(output);
|
|
5057
5398
|
if (opts.out) {
|
|
5058
|
-
|
|
5399
|
+
fs9.writeFileSync(opts.out, stripAnsi(output));
|
|
5059
5400
|
console.log(chalk12.dim(`
|
|
5060
5401
|
Saved to ${opts.out}`));
|
|
5061
5402
|
}
|
|
@@ -5239,7 +5580,7 @@ async function runP2PConnect() {
|
|
|
5239
5580
|
}
|
|
5240
5581
|
async function runInfoCommand() {
|
|
5241
5582
|
const data = await collectAll({ detailed: true });
|
|
5242
|
-
const { getDisplayInfo, getTimeMachineStatus } = await import("./collectors-
|
|
5583
|
+
const { getDisplayInfo, getTimeMachineStatus } = await import("./collectors-VACLPHRP.js");
|
|
5243
5584
|
const displays = await getDisplayInfo();
|
|
5244
5585
|
const tmStatus = await getTimeMachineStatus();
|
|
5245
5586
|
const lines = [];
|
|
@@ -5345,9 +5686,9 @@ async function runWebCommand() {
|
|
|
5345
5686
|
res.end(getDashboardHtml());
|
|
5346
5687
|
} else if (url === "/setup") {
|
|
5347
5688
|
res.writeHead(200, { "Content-Type": "text/html" });
|
|
5348
|
-
const indexPath =
|
|
5349
|
-
if (
|
|
5350
|
-
res.end(
|
|
5689
|
+
const indexPath = path6.join(process.cwd(), "index.html");
|
|
5690
|
+
if (fs9.existsSync(indexPath)) {
|
|
5691
|
+
res.end(fs9.readFileSync(indexPath, "utf-8"));
|
|
5351
5692
|
} else {
|
|
5352
5693
|
res.end(getDashboardHtml());
|
|
5353
5694
|
}
|
|
@@ -5496,8 +5837,8 @@ let delegate = AppDelegate()
|
|
|
5496
5837
|
app.delegate = delegate
|
|
5497
5838
|
app.run()
|
|
5498
5839
|
`;
|
|
5499
|
-
const scriptPath =
|
|
5500
|
-
|
|
5840
|
+
const scriptPath = path6.join(os3.tmpdir(), "pyre-ui.swift");
|
|
5841
|
+
fs9.writeFileSync(scriptPath, swiftScript);
|
|
5501
5842
|
const { spawn } = await import("child_process");
|
|
5502
5843
|
console.log(chalk12.cyan(`
|
|
5503
5844
|
Launching native UI window...`));
|
|
@@ -5514,9 +5855,9 @@ app.run()
|
|
|
5514
5855
|
async function runBenchCommand(benchCmd) {
|
|
5515
5856
|
const { spawn } = await import("child_process");
|
|
5516
5857
|
const logDir = opts.exportDir || "./pyre-exports";
|
|
5517
|
-
const file =
|
|
5518
|
-
if (!
|
|
5519
|
-
const stream =
|
|
5858
|
+
const file = path6.join(logDir, `pyre-bench-${(/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-")}.csv`);
|
|
5859
|
+
if (!fs9.existsSync(logDir)) fs9.mkdirSync(logDir, { recursive: true });
|
|
5860
|
+
const stream = fs9.createWriteStream(file, { flags: "a" });
|
|
5520
5861
|
stream.write("timestamp,cpu_usage,mem_usage_percent,temp_c,net_rx_bytes,net_tx_bytes,net_rx_packets,net_tx_packets,connections,thermal_state,power_watts\n");
|
|
5521
5862
|
console.log(chalk12.bold(`
|
|
5522
5863
|
pyre bench`));
|