pyre-cli 9.0.0 → 9.1.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 +418 -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 +7 -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,8 @@ var state = {
|
|
|
2415
2490
|
anomalyHistory: [],
|
|
2416
2491
|
splashEnabled: config.splashEnabled,
|
|
2417
2492
|
splashColorScheme: config.splashColorScheme,
|
|
2418
|
-
splashAnimation: config.splashAnimation
|
|
2493
|
+
splashAnimation: config.splashAnimation,
|
|
2494
|
+
readmeScrollOffset: 0
|
|
2419
2495
|
};
|
|
2420
2496
|
function setStatus(msg, ms = 3e3) {
|
|
2421
2497
|
state.statusMessage = msg;
|
|
@@ -2570,6 +2646,9 @@ function writeLogRow(data) {
|
|
|
2570
2646
|
|
|
2571
2647
|
// src/live/render.ts
|
|
2572
2648
|
import { execFile, exec } from "child_process";
|
|
2649
|
+
import fs3 from "fs";
|
|
2650
|
+
import path3 from "path";
|
|
2651
|
+
import { fileURLToPath } from "url";
|
|
2573
2652
|
import chalk4 from "chalk";
|
|
2574
2653
|
|
|
2575
2654
|
// src/anomalies.ts
|
|
@@ -2679,6 +2758,9 @@ function tableCacheParams() {
|
|
|
2679
2758
|
return [
|
|
2680
2759
|
state.sortMode,
|
|
2681
2760
|
state.processFilter || "",
|
|
2761
|
+
state.processSelectionIndex,
|
|
2762
|
+
state.trackedPid || "",
|
|
2763
|
+
state.inspectingProcess ? state.inspectingProcess.pid : "",
|
|
2682
2764
|
limit,
|
|
2683
2765
|
state.currentTheme,
|
|
2684
2766
|
state.activePanel,
|
|
@@ -2798,12 +2880,39 @@ function render() {
|
|
|
2798
2880
|
writeFrame(out);
|
|
2799
2881
|
return;
|
|
2800
2882
|
}
|
|
2883
|
+
if (state.inputMode === "menu") {
|
|
2884
|
+
writeFrame(renderSplashMenu(cols, rows));
|
|
2885
|
+
return;
|
|
2886
|
+
}
|
|
2887
|
+
if (state.inputMode === "readme") {
|
|
2888
|
+
writeFrame(renderReadme(cols, rows));
|
|
2889
|
+
return;
|
|
2890
|
+
}
|
|
2891
|
+
if (state.inputMode === "credits") {
|
|
2892
|
+
writeFrame(renderCredits(cols, rows));
|
|
2893
|
+
return;
|
|
2894
|
+
}
|
|
2801
2895
|
const lines = [];
|
|
2802
2896
|
const theme = THEMES[state.currentTheme] || THEMES.default;
|
|
2803
2897
|
const params = tableCacheParams();
|
|
2804
2898
|
const anomalies = detectAnomalies(state.lastData, state.history);
|
|
2899
|
+
if (anomalies.length > 0) {
|
|
2900
|
+
for (const a of anomalies) {
|
|
2901
|
+
const now = /* @__PURE__ */ new Date();
|
|
2902
|
+
const alertWithTime = { ...a, timestamp: now };
|
|
2903
|
+
const exists = state.anomalyHistory.some(
|
|
2904
|
+
(h) => h.metric === a.metric && Math.abs(h.zScore - a.zScore) < 0.1 && now.getTime() - (h.timestamp?.getTime() || 0) < 1e4
|
|
2905
|
+
);
|
|
2906
|
+
if (!exists) {
|
|
2907
|
+
state.anomalyHistory.unshift(alertWithTime);
|
|
2908
|
+
}
|
|
2909
|
+
}
|
|
2910
|
+
if (state.anomalyHistory.length > 100) {
|
|
2911
|
+
state.anomalyHistory.length = 100;
|
|
2912
|
+
}
|
|
2913
|
+
}
|
|
2805
2914
|
const anomalyCacheKey = anomalies.map((a) => `${a.metric}:${a.zScore.toFixed(2)}`).join(",");
|
|
2806
|
-
const cacheParams = params + "|" + anomalyCacheKey;
|
|
2915
|
+
const cacheParams = params + "|" + anomalyCacheKey + "|" + state.anomalyHistory.length;
|
|
2807
2916
|
const tableStr = _tableDataDirty || state.lastData !== _cachedTableData || cacheParams !== _cachedTableParams ? (() => {
|
|
2808
2917
|
const out = formatTable(state.lastData, {
|
|
2809
2918
|
width: state.termWidth,
|
|
@@ -2819,7 +2928,10 @@ function render() {
|
|
|
2819
2928
|
tempUnit: state.tempUnit,
|
|
2820
2929
|
history: state.history,
|
|
2821
2930
|
graphMode: state.graphMode,
|
|
2822
|
-
panelLayout: state.panelLayout
|
|
2931
|
+
panelLayout: state.panelLayout,
|
|
2932
|
+
selectedProcessIndex: state.processSelectionIndex,
|
|
2933
|
+
trackedPid: state.trackedPid,
|
|
2934
|
+
inspectProcess: state.inspectingProcess
|
|
2823
2935
|
});
|
|
2824
2936
|
_cachedTableData = state.lastData;
|
|
2825
2937
|
_cachedTableParams = cacheParams;
|
|
@@ -2991,11 +3103,98 @@ function checkAlerts(data) {
|
|
|
2991
3103
|
state.alerted = false;
|
|
2992
3104
|
}
|
|
2993
3105
|
}
|
|
3106
|
+
function renderSplashMenu(cols, rows) {
|
|
3107
|
+
const out = [];
|
|
3108
|
+
const logo = [
|
|
3109
|
+
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"),
|
|
3110
|
+
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"),
|
|
3111
|
+
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 "),
|
|
3112
|
+
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 "),
|
|
3113
|
+
chalk4.hex("#ffe004").bold(" \u2588\u2588\u2551 \u2588\u2588\u2551 \u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557"),
|
|
3114
|
+
chalk4.hex("#ffff40").bold(" \u255A\u2550\u255D \u255A\u2550\u255D \u255A\u2550\u255D \u255A\u2550\u255D\u255A\u2550\u2550\u2550\u2550\u2550\u2550\u255D")
|
|
3115
|
+
];
|
|
3116
|
+
const menuTop = Math.max(0, Math.floor(rows / 2) - 8);
|
|
3117
|
+
for (let i = 0; i < menuTop; i++) out.push("");
|
|
3118
|
+
const padding = Math.max(0, Math.floor((cols - 50) / 2));
|
|
3119
|
+
const padStr = " ".repeat(padding);
|
|
3120
|
+
for (const line of logo) {
|
|
3121
|
+
out.push(padStr + line);
|
|
3122
|
+
}
|
|
3123
|
+
out.push("");
|
|
3124
|
+
out.push(padStr + chalk4.dim(" system monitor v9.0.0"));
|
|
3125
|
+
out.push("");
|
|
3126
|
+
out.push("");
|
|
3127
|
+
for (let i = 0; i < MENU_OPTIONS.length; i++) {
|
|
3128
|
+
const isSelected = i === state.menuSelectionIndex;
|
|
3129
|
+
const opt = MENU_OPTIONS[i];
|
|
3130
|
+
const prefix = isSelected ? chalk4.cyan.bold(" \u25B6 ") : " ";
|
|
3131
|
+
const text = isSelected ? chalk4.bgCyan.black(` ${opt} `) : chalk4.dim(` ${opt} `);
|
|
3132
|
+
out.push(padStr + " " + prefix + text);
|
|
3133
|
+
}
|
|
3134
|
+
out.push("");
|
|
3135
|
+
out.push("");
|
|
3136
|
+
out.push(padStr + chalk4.dim(" Use \u2191/\u2193 to navigate, Enter to select"));
|
|
3137
|
+
while (out.length < rows) out.push("");
|
|
3138
|
+
return out.map((l) => fitVisible(l, cols));
|
|
3139
|
+
}
|
|
3140
|
+
var cachedReadmeLines = null;
|
|
3141
|
+
function getReadmeLines() {
|
|
3142
|
+
if (cachedReadmeLines) return cachedReadmeLines;
|
|
3143
|
+
try {
|
|
3144
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
3145
|
+
const __dirname = path3.dirname(__filename);
|
|
3146
|
+
const rootDir = path3.resolve(__dirname, "..", "..");
|
|
3147
|
+
const readmePath = path3.join(rootDir, "README.md");
|
|
3148
|
+
const content = fs3.readFileSync(readmePath, "utf8");
|
|
3149
|
+
cachedReadmeLines = content.split("\n");
|
|
3150
|
+
return cachedReadmeLines;
|
|
3151
|
+
} catch (err) {
|
|
3152
|
+
return [chalk4.red("Failed to load README.md")];
|
|
3153
|
+
}
|
|
3154
|
+
}
|
|
3155
|
+
function renderReadme(cols, rows) {
|
|
3156
|
+
const lines = getReadmeLines();
|
|
3157
|
+
const availableLines = Math.max(1, rows - 2);
|
|
3158
|
+
const startIdx = Math.min(state.readmeScrollOffset, Math.max(0, lines.length - availableLines));
|
|
3159
|
+
state.readmeScrollOffset = startIdx;
|
|
3160
|
+
const content = lines.slice(startIdx, startIdx + availableLines).map((l) => {
|
|
3161
|
+
let out2 = l;
|
|
3162
|
+
if (out2.startsWith("#")) {
|
|
3163
|
+
out2 = chalk4.cyan.bold(out2);
|
|
3164
|
+
} else if (out2.startsWith("```")) {
|
|
3165
|
+
out2 = chalk4.dim(out2);
|
|
3166
|
+
} else if (out2.startsWith("- ") || out2.startsWith("* ")) {
|
|
3167
|
+
out2 = " " + chalk4.yellow(out2.substring(0, 2)) + out2.substring(2);
|
|
3168
|
+
}
|
|
3169
|
+
return out2;
|
|
3170
|
+
});
|
|
3171
|
+
const out = [];
|
|
3172
|
+
const pct = Math.round(startIdx / Math.max(1, lines.length - availableLines) * 100);
|
|
3173
|
+
const title = lines.length > availableLines ? `README (${pct}%)` : "README";
|
|
3174
|
+
out.push(...panel(title, content, cols, chalk4.cyan, chalk4.dim, availableLines));
|
|
3175
|
+
return out;
|
|
3176
|
+
}
|
|
3177
|
+
function renderCredits(cols, rows) {
|
|
3178
|
+
const out = [];
|
|
3179
|
+
const content = [
|
|
3180
|
+
chalk4.bold.hex("#ff6004")("Pyre - The Terminal System Monitor"),
|
|
3181
|
+
"",
|
|
3182
|
+
"Created with \u2764\uFE0F using Node.js",
|
|
3183
|
+
"",
|
|
3184
|
+
chalk4.cyan("Libraries used:"),
|
|
3185
|
+
" - chalk (Terminal styling)",
|
|
3186
|
+
" - systeminformation (System metrics)",
|
|
3187
|
+
"",
|
|
3188
|
+
chalk4.dim("Press Esc or Enter to return to menu.")
|
|
3189
|
+
];
|
|
3190
|
+
out.push(...panel("CREDITS", content, cols, chalk4.magenta, chalk4.dim, rows - 2));
|
|
3191
|
+
return out;
|
|
3192
|
+
}
|
|
2994
3193
|
|
|
2995
3194
|
// src/p2p/server.ts
|
|
2996
3195
|
import net from "net";
|
|
2997
3196
|
import tls from "tls";
|
|
2998
|
-
import
|
|
3197
|
+
import fs4 from "fs";
|
|
2999
3198
|
import crypto2 from "crypto";
|
|
3000
3199
|
import chalk5 from "chalk";
|
|
3001
3200
|
|
|
@@ -3140,9 +3339,9 @@ var P2PServer = class {
|
|
|
3140
3339
|
async start() {
|
|
3141
3340
|
if (this.options.auditLog) {
|
|
3142
3341
|
try {
|
|
3143
|
-
|
|
3342
|
+
fs4.mkdirSync(this.options.auditLog, { recursive: true });
|
|
3144
3343
|
const logFile = `${this.options.auditLog}/p2p-audit.log`;
|
|
3145
|
-
this.auditStream =
|
|
3344
|
+
this.auditStream = fs4.createWriteStream(logFile, { flags: "a" });
|
|
3146
3345
|
} catch {
|
|
3147
3346
|
this.log(chalk5.yellow("Warning: could not open audit log"));
|
|
3148
3347
|
}
|
|
@@ -3151,11 +3350,11 @@ var P2PServer = class {
|
|
|
3151
3350
|
const useTLS = !!(this.options.tlsCert && this.options.tlsKey);
|
|
3152
3351
|
if (useTLS) {
|
|
3153
3352
|
const tlsOptions = {
|
|
3154
|
-
key:
|
|
3155
|
-
cert:
|
|
3353
|
+
key: fs4.readFileSync(this.options.tlsKey),
|
|
3354
|
+
cert: fs4.readFileSync(this.options.tlsCert)
|
|
3156
3355
|
};
|
|
3157
3356
|
if (this.options.tlsCA) {
|
|
3158
|
-
tlsOptions.ca =
|
|
3357
|
+
tlsOptions.ca = fs4.readFileSync(this.options.tlsCA);
|
|
3159
3358
|
}
|
|
3160
3359
|
this.server = tls.createServer(tlsOptions, (socket) => this.onConnection(socket));
|
|
3161
3360
|
} else {
|
|
@@ -3423,7 +3622,7 @@ async function startP2PServer(options) {
|
|
|
3423
3622
|
// src/p2p/client.ts
|
|
3424
3623
|
import net2 from "net";
|
|
3425
3624
|
import tls2 from "tls";
|
|
3426
|
-
import
|
|
3625
|
+
import fs5 from "fs";
|
|
3427
3626
|
import crypto3 from "crypto";
|
|
3428
3627
|
import chalk6 from "chalk";
|
|
3429
3628
|
var P2PClient = class {
|
|
@@ -3451,9 +3650,9 @@ var P2PClient = class {
|
|
|
3451
3650
|
async connect() {
|
|
3452
3651
|
if (this.options.auditLog) {
|
|
3453
3652
|
try {
|
|
3454
|
-
|
|
3653
|
+
fs5.mkdirSync(this.options.auditLog, { recursive: true });
|
|
3455
3654
|
const logFile = `${this.options.auditLog}/p2p-client-audit.log`;
|
|
3456
|
-
this.auditStream =
|
|
3655
|
+
this.auditStream = fs5.createWriteStream(logFile, { flags: "a" });
|
|
3457
3656
|
} catch {
|
|
3458
3657
|
console.log(chalk6.yellow("Warning: could not open audit log"));
|
|
3459
3658
|
}
|
|
@@ -3468,7 +3667,7 @@ var P2PClient = class {
|
|
|
3468
3667
|
rejectUnauthorized: !this.options.tlsInsecure
|
|
3469
3668
|
};
|
|
3470
3669
|
if (this.options.tlsCA) {
|
|
3471
|
-
tlsOptions.ca =
|
|
3670
|
+
tlsOptions.ca = fs5.readFileSync(this.options.tlsCA);
|
|
3472
3671
|
}
|
|
3473
3672
|
this.socket = tls2.connect(tlsOptions, () => {
|
|
3474
3673
|
this.running = true;
|
|
@@ -3751,6 +3950,68 @@ function handleInputModeKey(str, key) {
|
|
|
3751
3950
|
render();
|
|
3752
3951
|
return;
|
|
3753
3952
|
}
|
|
3953
|
+
if (state.inputMode === "menu") {
|
|
3954
|
+
if (isEscKey(key, str)) {
|
|
3955
|
+
state.inputMode = null;
|
|
3956
|
+
render();
|
|
3957
|
+
return;
|
|
3958
|
+
}
|
|
3959
|
+
if (isUpKey(key, str)) {
|
|
3960
|
+
state.menuSelectionIndex = (state.menuSelectionIndex - 1 + MENU_OPTIONS.length) % MENU_OPTIONS.length;
|
|
3961
|
+
render();
|
|
3962
|
+
return;
|
|
3963
|
+
}
|
|
3964
|
+
if (isDownKey(key, str)) {
|
|
3965
|
+
state.menuSelectionIndex = (state.menuSelectionIndex + 1) % MENU_OPTIONS.length;
|
|
3966
|
+
render();
|
|
3967
|
+
return;
|
|
3968
|
+
}
|
|
3969
|
+
if (isEnterKey(key, str) || str === " ") {
|
|
3970
|
+
const option = MENU_OPTIONS[state.menuSelectionIndex];
|
|
3971
|
+
switch (option) {
|
|
3972
|
+
case "Resume Dashboard":
|
|
3973
|
+
state.inputMode = null;
|
|
3974
|
+
break;
|
|
3975
|
+
case "Settings (Customizer)":
|
|
3976
|
+
state.inputMode = "customizer";
|
|
3977
|
+
state.customizerIndex = 0;
|
|
3978
|
+
break;
|
|
3979
|
+
case "Readme":
|
|
3980
|
+
state.inputMode = "readme";
|
|
3981
|
+
break;
|
|
3982
|
+
case "Credits":
|
|
3983
|
+
state.inputMode = "credits";
|
|
3984
|
+
break;
|
|
3985
|
+
case "Quit pyre":
|
|
3986
|
+
process.stdout.write("\x1B[2J\x1B[3J\x1B[H");
|
|
3987
|
+
process.exit(0);
|
|
3988
|
+
}
|
|
3989
|
+
render();
|
|
3990
|
+
return;
|
|
3991
|
+
}
|
|
3992
|
+
render();
|
|
3993
|
+
return;
|
|
3994
|
+
}
|
|
3995
|
+
if (state.inputMode === "readme" || state.inputMode === "credits") {
|
|
3996
|
+
if (isEscKey(key, str) || isEnterKey(key, str)) {
|
|
3997
|
+
state.inputMode = "menu";
|
|
3998
|
+
render();
|
|
3999
|
+
return;
|
|
4000
|
+
}
|
|
4001
|
+
if (state.inputMode === "readme") {
|
|
4002
|
+
if (isUpKey(key, str)) {
|
|
4003
|
+
state.readmeScrollOffset = Math.max(0, state.readmeScrollOffset - 1);
|
|
4004
|
+
render();
|
|
4005
|
+
return;
|
|
4006
|
+
}
|
|
4007
|
+
if (isDownKey(key, str)) {
|
|
4008
|
+
state.readmeScrollOffset += 1;
|
|
4009
|
+
render();
|
|
4010
|
+
return;
|
|
4011
|
+
}
|
|
4012
|
+
}
|
|
4013
|
+
return;
|
|
4014
|
+
}
|
|
3754
4015
|
if (state.inputMode === "signal") {
|
|
3755
4016
|
if (isUpKey(key, str)) {
|
|
3756
4017
|
const idx = state.SIGNAL_OPTIONS.indexOf(state.inputBuffer);
|
|
@@ -4172,11 +4433,72 @@ async function startLive(opts2, splashPromise) {
|
|
|
4172
4433
|
case "tab":
|
|
4173
4434
|
cycleTab(1);
|
|
4174
4435
|
break;
|
|
4436
|
+
case "up":
|
|
4437
|
+
if (state.lastData?.processes?.length) {
|
|
4438
|
+
state.trackedPid = null;
|
|
4439
|
+
state.processSelectionIndex = Math.max(0, state.processSelectionIndex - 1);
|
|
4440
|
+
render();
|
|
4441
|
+
}
|
|
4442
|
+
break;
|
|
4443
|
+
case "down":
|
|
4444
|
+
if (state.lastData?.processes?.length) {
|
|
4445
|
+
state.trackedPid = null;
|
|
4446
|
+
const count = state.lastData.processes.length;
|
|
4447
|
+
state.processSelectionIndex = Math.min(count - 1, state.processSelectionIndex + 1);
|
|
4448
|
+
render();
|
|
4449
|
+
}
|
|
4450
|
+
break;
|
|
4451
|
+
case "space":
|
|
4452
|
+
case " ":
|
|
4453
|
+
if (state.lastData?.processes?.length && state.processSelectionIndex >= 0) {
|
|
4454
|
+
const sorted = state.lastData.processes;
|
|
4455
|
+
const proc = sorted[state.processSelectionIndex];
|
|
4456
|
+
if (proc) {
|
|
4457
|
+
if (state.trackedPid === proc.pid) {
|
|
4458
|
+
state.trackedPid = null;
|
|
4459
|
+
setStatus(`Stopped following PID ${proc.pid}`);
|
|
4460
|
+
} else {
|
|
4461
|
+
state.trackedPid = proc.pid;
|
|
4462
|
+
setStatus(`Following PID ${proc.pid} (${proc.command})`);
|
|
4463
|
+
}
|
|
4464
|
+
render();
|
|
4465
|
+
}
|
|
4466
|
+
}
|
|
4467
|
+
break;
|
|
4468
|
+
case "return":
|
|
4469
|
+
case "enter":
|
|
4470
|
+
if (state.inspectingProcess) {
|
|
4471
|
+
state.inspectingProcess = null;
|
|
4472
|
+
render();
|
|
4473
|
+
} else if (state.lastData?.processes?.length && state.processSelectionIndex >= 0) {
|
|
4474
|
+
const sorted = state.lastData.processes;
|
|
4475
|
+
const proc = sorted[state.processSelectionIndex];
|
|
4476
|
+
if (proc) {
|
|
4477
|
+
state.inspectingProcess = proc;
|
|
4478
|
+
state.trackedPid = proc.pid;
|
|
4479
|
+
setStatus(`Inspecting & following PID ${proc.pid}`);
|
|
4480
|
+
render();
|
|
4481
|
+
}
|
|
4482
|
+
}
|
|
4483
|
+
break;
|
|
4175
4484
|
case "escape":
|
|
4176
4485
|
case "esc":
|
|
4177
|
-
state.
|
|
4178
|
-
|
|
4179
|
-
|
|
4486
|
+
if (state.inspectingProcess) {
|
|
4487
|
+
state.inspectingProcess = null;
|
|
4488
|
+
render();
|
|
4489
|
+
} else if (state.trackedPid !== null) {
|
|
4490
|
+
state.trackedPid = null;
|
|
4491
|
+
setStatus("Stopped following process");
|
|
4492
|
+
render();
|
|
4493
|
+
} else if (state.activePanel !== "grid") {
|
|
4494
|
+
state.activePanel = "grid";
|
|
4495
|
+
setStatus("Grid view");
|
|
4496
|
+
render();
|
|
4497
|
+
} else {
|
|
4498
|
+
state.inputMode = "menu";
|
|
4499
|
+
state.menuSelectionIndex = 0;
|
|
4500
|
+
render();
|
|
4501
|
+
}
|
|
4180
4502
|
break;
|
|
4181
4503
|
default:
|
|
4182
4504
|
if (str && str.length === 1) {
|
|
@@ -4193,7 +4515,7 @@ async function startLive(opts2, splashPromise) {
|
|
|
4193
4515
|
process.once("SIGINT", () => stopLive());
|
|
4194
4516
|
}
|
|
4195
4517
|
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" };
|
|
4518
|
+
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
4519
|
return map[str] ?? null;
|
|
4198
4520
|
}
|
|
4199
4521
|
function cycleTab(direction) {
|
|
@@ -4211,6 +4533,10 @@ function handleNormalMouse(seq) {
|
|
|
4211
4533
|
const cy = seq.charCodeAt(5) - 32;
|
|
4212
4534
|
if (cb === 0 || cb === 1) {
|
|
4213
4535
|
handleMouseClick(cy, cx);
|
|
4536
|
+
} else if (cb === 64) {
|
|
4537
|
+
scrollProcessSelection(-1);
|
|
4538
|
+
} else if (cb === 65) {
|
|
4539
|
+
scrollProcessSelection(1);
|
|
4214
4540
|
}
|
|
4215
4541
|
}
|
|
4216
4542
|
function handleSGRMouse(seq) {
|
|
@@ -4221,6 +4547,18 @@ function handleSGRMouse(seq) {
|
|
|
4221
4547
|
const cy = parseInt(match[3]) - 1;
|
|
4222
4548
|
if (button === 0 || button === 1) {
|
|
4223
4549
|
handleMouseClick(cy, cx);
|
|
4550
|
+
} else if (button === 64) {
|
|
4551
|
+
scrollProcessSelection(-1);
|
|
4552
|
+
} else if (button === 65) {
|
|
4553
|
+
scrollProcessSelection(1);
|
|
4554
|
+
}
|
|
4555
|
+
}
|
|
4556
|
+
function scrollProcessSelection(dir) {
|
|
4557
|
+
if (state.lastData?.processes?.length) {
|
|
4558
|
+
state.trackedPid = null;
|
|
4559
|
+
const count = state.lastData.processes.length;
|
|
4560
|
+
state.processSelectionIndex = Math.max(0, Math.min(count - 1, state.processSelectionIndex + dir));
|
|
4561
|
+
render();
|
|
4224
4562
|
}
|
|
4225
4563
|
}
|
|
4226
4564
|
function handleMouseClick(y, x) {
|
|
@@ -4601,8 +4939,8 @@ async function showSplash(config3) {
|
|
|
4601
4939
|
}
|
|
4602
4940
|
|
|
4603
4941
|
// src/historyCmd.ts
|
|
4604
|
-
import
|
|
4605
|
-
import
|
|
4942
|
+
import fs6 from "fs";
|
|
4943
|
+
import path4 from "path";
|
|
4606
4944
|
import chalk8 from "chalk";
|
|
4607
4945
|
function runHistoryCommand(opts2 = {}) {
|
|
4608
4946
|
const days = opts2.days || 7;
|
|
@@ -4610,11 +4948,11 @@ function runHistoryCommand(opts2 = {}) {
|
|
|
4610
4948
|
console.log(chalk8.bold(`
|
|
4611
4949
|
pyre history \u2014 Past ${days} Days Trend
|
|
4612
4950
|
`));
|
|
4613
|
-
if (!
|
|
4951
|
+
if (!fs6.existsSync(dir)) {
|
|
4614
4952
|
console.log(chalk8.yellow(` No logs directory found at ${dir}`));
|
|
4615
4953
|
return;
|
|
4616
4954
|
}
|
|
4617
|
-
const files =
|
|
4955
|
+
const files = fs6.readdirSync(dir).filter((f) => f.startsWith("pyre-log-") && f.endsWith(".csv"));
|
|
4618
4956
|
if (files.length === 0) {
|
|
4619
4957
|
console.log(chalk8.yellow(` No CSV logs found in ${dir}`));
|
|
4620
4958
|
return;
|
|
@@ -4624,9 +4962,9 @@ function runHistoryCommand(opts2 = {}) {
|
|
|
4624
4962
|
const memPoints = [];
|
|
4625
4963
|
const tempPoints = [];
|
|
4626
4964
|
for (const file of files.sort()) {
|
|
4627
|
-
const fullPath =
|
|
4965
|
+
const fullPath = path4.join(dir, file);
|
|
4628
4966
|
try {
|
|
4629
|
-
const content =
|
|
4967
|
+
const content = fs6.readFileSync(fullPath, "utf-8");
|
|
4630
4968
|
const lines = content.split("\n").slice(1);
|
|
4631
4969
|
for (const line of lines) {
|
|
4632
4970
|
if (!line.trim()) continue;
|
|
@@ -4661,7 +4999,7 @@ function runHistoryCommand(opts2 = {}) {
|
|
|
4661
4999
|
}
|
|
4662
5000
|
|
|
4663
5001
|
// src/diffCmd.ts
|
|
4664
|
-
import
|
|
5002
|
+
import fs7 from "fs";
|
|
4665
5003
|
import chalk9 from "chalk";
|
|
4666
5004
|
function runDiffCommand(file1, file2) {
|
|
4667
5005
|
console.log(chalk9.bold(`
|
|
@@ -4671,8 +5009,8 @@ function runDiffCommand(file1, file2) {
|
|
|
4671
5009
|
console.log(chalk9.dim(` Snapshot B: ${file2}
|
|
4672
5010
|
`));
|
|
4673
5011
|
try {
|
|
4674
|
-
const dataA = JSON.parse(
|
|
4675
|
-
const dataB = JSON.parse(
|
|
5012
|
+
const dataA = JSON.parse(fs7.readFileSync(file1, "utf-8"));
|
|
5013
|
+
const dataB = JSON.parse(fs7.readFileSync(file2, "utf-8"));
|
|
4676
5014
|
const diffNum = (label, valA, valB, unit = "") => {
|
|
4677
5015
|
const delta = valB - valA;
|
|
4678
5016
|
const sign = delta > 0 ? "+" : "";
|
|
@@ -4696,8 +5034,8 @@ function runDiffCommand(file1, file2) {
|
|
|
4696
5034
|
}
|
|
4697
5035
|
|
|
4698
5036
|
// src/xbar.ts
|
|
4699
|
-
import
|
|
4700
|
-
import
|
|
5037
|
+
import fs8 from "fs";
|
|
5038
|
+
import path5 from "path";
|
|
4701
5039
|
import os2 from "os";
|
|
4702
5040
|
import chalk10 from "chalk";
|
|
4703
5041
|
function generateXbarPlugin() {
|
|
@@ -4734,11 +5072,11 @@ echo "\u{1F525} C:\${CPU}% M:\${MEM}% T:\${TEMP}\xB0C | font=Menlo"
|
|
|
4734
5072
|
echo "---"
|
|
4735
5073
|
echo "Open Dashboard | bash='${nodePath}' param1='${pyrePath}' param2='live' terminal=true"
|
|
4736
5074
|
`;
|
|
4737
|
-
const pluginDir =
|
|
5075
|
+
const pluginDir = path5.join(os2.homedir(), "Library", "Application Support", "xbar", "plugins");
|
|
4738
5076
|
const filename = "pyre-monitor.2s.sh";
|
|
4739
|
-
const outPath =
|
|
4740
|
-
|
|
4741
|
-
|
|
5077
|
+
const outPath = path5.join(process.cwd(), filename);
|
|
5078
|
+
fs8.writeFileSync(outPath, script);
|
|
5079
|
+
fs8.chmodSync(outPath, "755");
|
|
4742
5080
|
console.log(chalk10.green(`Generated xbar plugin script at ${outPath}`));
|
|
4743
5081
|
console.log(`To install, move it to your xbar plugins directory:`);
|
|
4744
5082
|
console.log(chalk10.cyan(` mv ${filename} "${pluginDir}/"`));
|
|
@@ -4774,7 +5112,7 @@ function runFleetCommand(hosts) {
|
|
|
4774
5112
|
|
|
4775
5113
|
// src/index.ts
|
|
4776
5114
|
var config2 = readConfig();
|
|
4777
|
-
var pkg = JSON.parse(
|
|
5115
|
+
var pkg = JSON.parse(fs9.readFileSync(new URL("../package.json", import.meta.url), "utf-8"));
|
|
4778
5116
|
var program = new Command();
|
|
4779
5117
|
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
5118
|
program.addHelpText("after", `
|
|
@@ -4861,7 +5199,7 @@ async function runServerCommand() {
|
|
|
4861
5199
|
async function main() {
|
|
4862
5200
|
const cmd = program.args[0];
|
|
4863
5201
|
if (cmd === "anomalies") {
|
|
4864
|
-
const { runAnomaliesDigest } = await import("./anomaliesCmd-
|
|
5202
|
+
const { runAnomaliesDigest } = await import("./anomaliesCmd-25OFKYPK.js");
|
|
4865
5203
|
runAnomaliesDigest({ since: opts.since || "7d", dir: opts.exportDir });
|
|
4866
5204
|
return;
|
|
4867
5205
|
}
|
|
@@ -4958,7 +5296,7 @@ async function main() {
|
|
|
4958
5296
|
const cfg = readConfig();
|
|
4959
5297
|
console.log(JSON.stringify(cfg, null, 2));
|
|
4960
5298
|
} else if (sub === "reset") {
|
|
4961
|
-
|
|
5299
|
+
fs9.rmSync(CONFIG_FILE, { force: true });
|
|
4962
5300
|
console.log(chalk12.green("Config reset to defaults"));
|
|
4963
5301
|
} else {
|
|
4964
5302
|
console.log("Usage: pyre config <show|reset>");
|
|
@@ -5055,7 +5393,7 @@ async function main() {
|
|
|
5055
5393
|
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
5394
|
console.log(output);
|
|
5057
5395
|
if (opts.out) {
|
|
5058
|
-
|
|
5396
|
+
fs9.writeFileSync(opts.out, stripAnsi(output));
|
|
5059
5397
|
console.log(chalk12.dim(`
|
|
5060
5398
|
Saved to ${opts.out}`));
|
|
5061
5399
|
}
|
|
@@ -5239,7 +5577,7 @@ async function runP2PConnect() {
|
|
|
5239
5577
|
}
|
|
5240
5578
|
async function runInfoCommand() {
|
|
5241
5579
|
const data = await collectAll({ detailed: true });
|
|
5242
|
-
const { getDisplayInfo, getTimeMachineStatus } = await import("./collectors-
|
|
5580
|
+
const { getDisplayInfo, getTimeMachineStatus } = await import("./collectors-VACLPHRP.js");
|
|
5243
5581
|
const displays = await getDisplayInfo();
|
|
5244
5582
|
const tmStatus = await getTimeMachineStatus();
|
|
5245
5583
|
const lines = [];
|
|
@@ -5345,9 +5683,9 @@ async function runWebCommand() {
|
|
|
5345
5683
|
res.end(getDashboardHtml());
|
|
5346
5684
|
} else if (url === "/setup") {
|
|
5347
5685
|
res.writeHead(200, { "Content-Type": "text/html" });
|
|
5348
|
-
const indexPath =
|
|
5349
|
-
if (
|
|
5350
|
-
res.end(
|
|
5686
|
+
const indexPath = path6.join(process.cwd(), "index.html");
|
|
5687
|
+
if (fs9.existsSync(indexPath)) {
|
|
5688
|
+
res.end(fs9.readFileSync(indexPath, "utf-8"));
|
|
5351
5689
|
} else {
|
|
5352
5690
|
res.end(getDashboardHtml());
|
|
5353
5691
|
}
|
|
@@ -5496,8 +5834,8 @@ let delegate = AppDelegate()
|
|
|
5496
5834
|
app.delegate = delegate
|
|
5497
5835
|
app.run()
|
|
5498
5836
|
`;
|
|
5499
|
-
const scriptPath =
|
|
5500
|
-
|
|
5837
|
+
const scriptPath = path6.join(os3.tmpdir(), "pyre-ui.swift");
|
|
5838
|
+
fs9.writeFileSync(scriptPath, swiftScript);
|
|
5501
5839
|
const { spawn } = await import("child_process");
|
|
5502
5840
|
console.log(chalk12.cyan(`
|
|
5503
5841
|
Launching native UI window...`));
|
|
@@ -5514,9 +5852,9 @@ app.run()
|
|
|
5514
5852
|
async function runBenchCommand(benchCmd) {
|
|
5515
5853
|
const { spawn } = await import("child_process");
|
|
5516
5854
|
const logDir = opts.exportDir || "./pyre-exports";
|
|
5517
|
-
const file =
|
|
5518
|
-
if (!
|
|
5519
|
-
const stream =
|
|
5855
|
+
const file = path6.join(logDir, `pyre-bench-${(/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-")}.csv`);
|
|
5856
|
+
if (!fs9.existsSync(logDir)) fs9.mkdirSync(logDir, { recursive: true });
|
|
5857
|
+
const stream = fs9.createWriteStream(file, { flags: "a" });
|
|
5520
5858
|
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
5859
|
console.log(chalk12.bold(`
|
|
5522
5860
|
pyre bench`));
|