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/index.js CHANGED
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  collectAll
4
- } from "./chunk-EQZCK2VC.js";
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 fs8 from "fs";
13
+ import fs9 from "fs";
14
14
  import os3 from "os";
15
- import path5 from "path";
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
- return 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);
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
- const limited = opts2.processLimit ? sorted.slice(0, opts2.processLimit) : sorted;
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(limited);
766
+ return [...trackingLines, ...buildProcessTree(visible)];
733
767
  }
734
- return processTableLines(limited, width - 4, theme.border);
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 availableRows = Math.max(1, targetHeight - headerRowOverhead - tableHeaderOverhead);
879
- const limited = sorted.slice(0, availableRows);
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(limited);
886
- const rightTitle2 = opts2.filter ? `filter: "${opts2.filter}"` : `tree \xB7 sort: ${opts2.sortBy || "cpu"}`;
887
- return panel("P proc", [head, theme.border("\u2500".repeat(contentWidth)), ...treeLines], width, theme.process, theme.border, targetHeight - 2, rightTitle2);
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 = limited.map((p) => {
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
- return `${pidStr} ${cmdStr} ${userStr} ${thrStr} ${memStr} ${cpuStr}`;
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
- const rightTitle = opts2.filter ? `filter: "${opts2.filter}"` : `sort: ${opts2.sortBy || "cpu"}`;
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
- const leftLines = btopLeftColumn(data, width, theme, opts2);
938
- out.push(...leftLines);
997
+ out.push(...btopCpuBox(data, width, theme, opts2));
939
998
  out.push("");
940
- const procLines = btopProcBox(data, width, 12, theme, opts2);
941
- out.push(...procLines);
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 fs3 from "fs";
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
- fs3.mkdirSync(this.options.auditLog, { recursive: true });
3342
+ fs4.mkdirSync(this.options.auditLog, { recursive: true });
3144
3343
  const logFile = `${this.options.auditLog}/p2p-audit.log`;
3145
- this.auditStream = fs3.createWriteStream(logFile, { flags: "a" });
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: fs3.readFileSync(this.options.tlsKey),
3155
- cert: fs3.readFileSync(this.options.tlsCert)
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 = fs3.readFileSync(this.options.tlsCA);
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 fs4 from "fs";
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
- fs4.mkdirSync(this.options.auditLog, { recursive: true });
3653
+ fs5.mkdirSync(this.options.auditLog, { recursive: true });
3455
3654
  const logFile = `${this.options.auditLog}/p2p-client-audit.log`;
3456
- this.auditStream = fs4.createWriteStream(logFile, { flags: "a" });
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 = fs4.readFileSync(this.options.tlsCA);
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.activePanel = "grid";
4178
- setStatus("Grid view");
4179
- render();
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 fs5 from "fs";
4605
- import path3 from "path";
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 (!fs5.existsSync(dir)) {
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 = fs5.readdirSync(dir).filter((f) => f.startsWith("pyre-log-") && f.endsWith(".csv"));
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 = path3.join(dir, file);
4965
+ const fullPath = path4.join(dir, file);
4628
4966
  try {
4629
- const content = fs5.readFileSync(fullPath, "utf-8");
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 fs6 from "fs";
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(fs6.readFileSync(file1, "utf-8"));
4675
- const dataB = JSON.parse(fs6.readFileSync(file2, "utf-8"));
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 fs7 from "fs";
4700
- import path4 from "path";
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 = path4.join(os2.homedir(), "Library", "Application Support", "xbar", "plugins");
5075
+ const pluginDir = path5.join(os2.homedir(), "Library", "Application Support", "xbar", "plugins");
4738
5076
  const filename = "pyre-monitor.2s.sh";
4739
- const outPath = path4.join(process.cwd(), filename);
4740
- fs7.writeFileSync(outPath, script);
4741
- fs7.chmodSync(outPath, "755");
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(fs8.readFileSync(new URL("../package.json", import.meta.url), "utf-8"));
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-TO52YY2B.js");
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
- fs8.rmSync(CONFIG_FILE, { force: true });
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
- fs8.writeFileSync(opts.out, stripAnsi(output));
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-KNEN4YJD.js");
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 = path5.join(process.cwd(), "index.html");
5349
- if (fs8.existsSync(indexPath)) {
5350
- res.end(fs8.readFileSync(indexPath, "utf-8"));
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 = path5.join(os3.tmpdir(), "pyre-ui.swift");
5500
- fs8.writeFileSync(scriptPath, swiftScript);
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 = path5.join(logDir, `pyre-bench-${(/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-")}.csv`);
5518
- if (!fs8.existsSync(logDir)) fs8.mkdirSync(logDir, { recursive: true });
5519
- const stream = fs8.createWriteStream(file, { flags: "a" });
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`));