pyre-cli 9.5.1 → 9.5.2

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.
@@ -1,3 +1,6 @@
1
+ import {
2
+ collectBlenderRenders
3
+ } from "./chunk-25I533OF.js";
1
4
  import {
2
5
  run
3
6
  } from "./chunk-FH5WDJBF.js";
@@ -110,6 +113,43 @@ function parseSuffix(s) {
110
113
  return s.toUpperCase() === "K" ? 1024 : s.toUpperCase() === "M" ? 1024 * 1024 : s.toUpperCase() === "G" ? 1024 * 1024 * 1024 : 1;
111
114
  }
112
115
 
116
+ // src/monitors/dns_cache.ts
117
+ import dns from "dns";
118
+ var cache = /* @__PURE__ */ new Map();
119
+ var pending = /* @__PURE__ */ new Set();
120
+ function resolveIp(ip) {
121
+ let cleanIp = ip;
122
+ if (cleanIp.includes("]:")) {
123
+ cleanIp = cleanIp.substring(1, cleanIp.indexOf("]"));
124
+ } else if (cleanIp.includes(":") && cleanIp.split(":").length === 2) {
125
+ cleanIp = cleanIp.split(":")[0];
126
+ } else if (cleanIp.includes(":") && !cleanIp.includes("]")) {
127
+ const lastColon = cleanIp.lastIndexOf(":");
128
+ const isPort = !cleanIp.includes(":", cleanIp.indexOf(":") + 1);
129
+ }
130
+ if (cleanIp.includes(":") && cleanIp.includes(".")) {
131
+ const lastDot = cleanIp.lastIndexOf(".");
132
+ if (lastDot > cleanIp.lastIndexOf(":")) {
133
+ cleanIp = cleanIp.substring(0, lastDot);
134
+ }
135
+ }
136
+ if (cache.has(cleanIp)) return cache.get(cleanIp);
137
+ if (pending.has(cleanIp)) return ip;
138
+ if (cleanIp.startsWith("127.") || cleanIp.startsWith("192.168.") || cleanIp.startsWith("10.") || cleanIp.startsWith("172.16.") || cleanIp.startsWith("ff02:") || cleanIp === "*:*" || cleanIp === "*" || cleanIp.startsWith("fe80:")) {
139
+ return ip;
140
+ }
141
+ pending.add(cleanIp);
142
+ dns.reverse(cleanIp, (err, hostnames) => {
143
+ if (!err && hostnames && hostnames.length > 0) {
144
+ cache.set(cleanIp, hostnames[0]);
145
+ } else {
146
+ cache.set(cleanIp, cleanIp);
147
+ }
148
+ pending.delete(cleanIp);
149
+ });
150
+ return ip;
151
+ }
152
+
113
153
  // src/monitors/collectors.ts
114
154
  var SP_TTL_MS = 1e4;
115
155
  var NETSTAT_TTL_MS = 1e3;
@@ -122,6 +162,7 @@ var spBatteryCache = null;
122
162
  var netstatIbCache = null;
123
163
  var routeCache = null;
124
164
  var sysctlCache = /* @__PURE__ */ new Map();
165
+ var prevNetSample = null;
125
166
  async function cachedSysctl(key, fallback) {
126
167
  const now = Date.now();
127
168
  const hit = sysctlCache.get(key);
@@ -185,7 +226,7 @@ function estimateBatteryLife(level, state) {
185
226
  return { estimatedTimeToEmpty, dischargeRatePerHour: Math.round(dischargeRate * 10) / 10, powerWatts };
186
227
  }
187
228
  async function collectAll(opts = {}) {
188
- const [cpu, gpu, memory, disk, battery, thermal, network, processes, system, power, packets, tasks] = await Promise.all([
229
+ const [cpu, gpu, memory, disk, battery, thermal, network, processes, system, power, packets, tasks, containers, blenderRenders] = await Promise.all([
189
230
  collectCpu(),
190
231
  collectGpu(opts.detailed),
191
232
  collectMemory(),
@@ -197,7 +238,9 @@ async function collectAll(opts = {}) {
197
238
  collectSystem(),
198
239
  collectPower(),
199
240
  collectPackets(),
200
- collectTasks()
241
+ collectTasks(),
242
+ collectContainers(),
243
+ collectBlenderRenders()
201
244
  ]);
202
245
  return {
203
246
  header: {
@@ -217,9 +260,32 @@ async function collectAll(opts = {}) {
217
260
  power,
218
261
  timestamp: (/* @__PURE__ */ new Date()).toISOString(),
219
262
  packets,
220
- tasks
263
+ tasks,
264
+ containers,
265
+ blenderRenders
221
266
  };
222
267
  }
268
+ async function collectContainers() {
269
+ try {
270
+ const raw = (await run('docker stats --no-stream --format "{{.ID}}|{{.Name}}|{{.CPUPerc}}|{{.MemUsage}}|{{.MemPerc}}|{{.NetIO}}|{{.BlockIO}}|{{.PIDs}}" 2>/dev/null', "")).trim();
271
+ if (!raw) return [];
272
+ return raw.split("\n").map((line) => {
273
+ const parts = line.split("|");
274
+ return {
275
+ id: parts[0],
276
+ name: parts[1],
277
+ cpuPercent: parseFloat(parts[2].replace("%", "")) || 0,
278
+ memUsage: parts[3],
279
+ memPercent: parseFloat(parts[4].replace("%", "")) || 0,
280
+ netIO: parts[5],
281
+ blockIO: parts[6],
282
+ pids: parseInt(parts[7], 10) || 0
283
+ };
284
+ });
285
+ } catch {
286
+ return [];
287
+ }
288
+ }
223
289
  async function collectPower() {
224
290
  try {
225
291
  const { power } = await getSmcMetrics();
@@ -749,9 +815,148 @@ async function collectNetwork() {
749
815
  }
750
816
  }
751
817
  }
752
- return { interface: iface, ip, rxBytes, txBytes, rxPackets, txPackets };
818
+ const now = Date.now();
819
+ let rxRate = 0;
820
+ let txRate = 0;
821
+ if (prevNetSample && prevNetSample.ts > 0) {
822
+ const dt = Math.max((now - prevNetSample.ts) / 1e3, 1e-3);
823
+ rxRate = Math.max(0, (rxBytes - prevNetSample.rxBytes) / dt);
824
+ txRate = Math.max(0, (txBytes - prevNetSample.txBytes) / dt);
825
+ }
826
+ prevNetSample = { rxBytes, txBytes, rxPackets, txPackets, ts: now };
827
+ const protocolStats = await getProtocolStats();
828
+ const connectionStates = await getConnectionStates();
829
+ const listeningPorts = await getListeningPorts();
830
+ const establishedConnections = connectionStates.established;
831
+ const topRemoteHosts = await getTopRemoteHosts();
832
+ return {
833
+ interface: iface,
834
+ ip,
835
+ rxBytes,
836
+ txBytes,
837
+ rxPackets,
838
+ txPackets,
839
+ rxRate,
840
+ txRate,
841
+ connections: establishedConnections,
842
+ protocols: protocolStats,
843
+ connectionStates,
844
+ listeningPorts,
845
+ establishedConnections,
846
+ topRemoteHosts
847
+ };
848
+ } catch {
849
+ return {
850
+ interface: "unknown",
851
+ ip: "0.0.0.0",
852
+ rxBytes: 0,
853
+ txBytes: 0,
854
+ rxPackets: 0,
855
+ txPackets: 0,
856
+ rxRate: 0,
857
+ txRate: 0,
858
+ connections: 0,
859
+ protocols: { tcp: { connections: 0, rxBytes: 0, txBytes: 0 }, udp: { connections: 0, rxBytes: 0, txBytes: 0 } },
860
+ connectionStates: { established: 0, listening: 0, timeWait: 0, closeWait: 0, other: 0 },
861
+ listeningPorts: [],
862
+ establishedConnections: 0,
863
+ topRemoteHosts: []
864
+ };
865
+ }
866
+ }
867
+ async function getProtocolStats() {
868
+ try {
869
+ const raw = await run("netstat -n -p tcp 2>/dev/null | tail -n +3 | awk '{print $1}' | sort | uniq -c", "");
870
+ const tcpConnections = (await run("netstat -n -p tcp 2>/dev/null | tail -n +3 | wc -l", "0")).trim();
871
+ const udpConnections = (await run("netstat -n -p udp 2>/dev/null | tail -n +3 | wc -l", "0")).trim();
872
+ let tcpRxBytes = 0;
873
+ let tcpTxBytes = 0;
874
+ let udpRxBytes = 0;
875
+ let udpTxBytes = 0;
876
+ try {
877
+ const netstat = await cachedNetstatIb();
878
+ for (const line of netstat.split("\n")) {
879
+ const parts = line.split(/\s+/);
880
+ if (parts.length >= 9 && parts[0] && !parts[0].startsWith("Name")) {
881
+ const iface = parts[0];
882
+ if (iface.includes("lo")) continue;
883
+ const rx = parseInt(parts[5]) || 0;
884
+ const tx = parseInt(parts[7]) || 0;
885
+ tcpRxBytes += rx;
886
+ tcpTxBytes += tx;
887
+ }
888
+ }
889
+ } catch {
890
+ }
891
+ return {
892
+ tcp: {
893
+ connections: parseInt(tcpConnections) || 0,
894
+ rxBytes: tcpRxBytes,
895
+ txBytes: tcpTxBytes
896
+ },
897
+ udp: {
898
+ connections: parseInt(udpConnections) || 0,
899
+ rxBytes: udpRxBytes,
900
+ txBytes: udpTxBytes
901
+ }
902
+ };
903
+ } catch {
904
+ return { tcp: { connections: 0, rxBytes: 0, txBytes: 0 }, udp: { connections: 0, rxBytes: 0, txBytes: 0 } };
905
+ }
906
+ }
907
+ async function getConnectionStates() {
908
+ try {
909
+ const raw = await run("netstat -n -p tcp 2>/dev/null | tail -n +3 | awk '{print $6}' | sort | uniq -c", "");
910
+ const lines = raw.split("\n").filter(Boolean);
911
+ const stats = { established: 0, listening: 0, timeWait: 0, closeWait: 0, other: 0 };
912
+ for (const line of lines) {
913
+ const match = line.match(/(\d+)\s+(\S+)/);
914
+ if (!match) continue;
915
+ const count = parseInt(match[1]);
916
+ const state = match[2].toUpperCase();
917
+ if (state.includes("ESTABLISHED")) stats.established += count;
918
+ else if (state.includes("LISTEN")) stats.listening += count;
919
+ else if (state.includes("TIME_WAIT")) stats.timeWait += count;
920
+ else if (state.includes("CLOSE_WAIT")) stats.closeWait += count;
921
+ else stats.other += count;
922
+ }
923
+ return stats;
924
+ } catch {
925
+ return { established: 0, listening: 0, timeWait: 0, closeWait: 0, other: 0 };
926
+ }
927
+ }
928
+ async function getListeningPorts() {
929
+ try {
930
+ const raw = await run("netstat -n -p tcp 2>/dev/null | grep LISTEN | awk '{print $4}' | rev | cut -d. -f1 | rev", "");
931
+ const ports = raw.split("\n").map((p) => parseInt(p, 10)).filter((p) => !isNaN(p) && p > 0);
932
+ return [...new Set(ports)].sort((a, b) => a - b);
753
933
  } catch {
754
- return { interface: "unknown", ip: "0.0.0.0", rxBytes: 0, txBytes: 0, rxPackets: 0, txPackets: 0 };
934
+ return [];
935
+ }
936
+ }
937
+ async function getTopRemoteHosts() {
938
+ try {
939
+ const raw = await run("netstat -n -p tcp 2>/dev/null | tail -n +3 | grep ESTABLISHED | awk '{print $5}' | rev | cut -d. -f1 | rev", "");
940
+ const ports = raw.split("\n").filter(Boolean);
941
+ const hostMap = /* @__PURE__ */ new Map();
942
+ for (const port of ports) {
943
+ const host = port.split(":")[0];
944
+ if (!host || host === "127.0.0.1" || host === "::1") continue;
945
+ const existing = hostMap.get(host) || { count: 0, bytes: 0 };
946
+ hostMap.set(host, { count: existing.count + 1, bytes: existing.bytes });
947
+ }
948
+ const result = [];
949
+ for (const [host, info] of hostMap.entries()) {
950
+ result.push({
951
+ host,
952
+ ip: host,
953
+ bytesTransferred: info.bytes,
954
+ connectionCount: info.count
955
+ });
956
+ }
957
+ return result.sort((a, b) => b.connectionCount - a.connectionCount).slice(0, 10);
958
+ } catch {
959
+ return [];
755
960
  }
756
961
  }
757
962
  async function collectProcesses(limit) {
@@ -800,29 +1005,67 @@ async function collectPackets() {
800
1005
  }
801
1006
  }
802
1007
  let connections = 0;
803
- try {
804
- const tcpConns = (await run("netstat -an | grep ESTABLISHED | wc -l", "0", 2e3)).trim();
805
- connections = parseInt(tcpConns) || 0;
806
- } catch {
807
- connections = 0;
808
- }
809
- let topProcesses = [];
810
1008
  let allProcesses = [];
811
1009
  try {
812
- const lsof = (await run("lsof -i -n -P 2>/dev/null | tail -n +2 | awk '{print $1, $2}' | sort | uniq -c | sort -rn", "", 2e3)).trim();
813
- const lsofLines = lsof.split("\n");
814
- topProcesses = lsofLines.map((line) => {
815
- const parts = line.trim().split(/\s+/);
816
- if (parts.length >= 3) {
817
- return { pid: parseInt(parts[2]) || 0, command: parts[1], rxBytes: 0, txBytes: parseInt(parts[0]) || 0 };
1010
+ const nettop = (await run("nettop -L 1 -J bytes_in,bytes_out,state 2>/dev/null", "", 2e3)).trim();
1011
+ const rows = nettop.split("\n");
1012
+ let currentProc = null;
1013
+ for (const row of rows) {
1014
+ if (!row || row.startsWith(",state,")) continue;
1015
+ const cols = row.split(",");
1016
+ const nameCol = cols[0];
1017
+ if (!nameCol.includes("<->")) {
1018
+ if (currentProc) {
1019
+ if (currentProc.connections && currentProc.connections.length > 0) {
1020
+ allProcesses.push(currentProc);
1021
+ }
1022
+ }
1023
+ const lastDot = nameCol.lastIndexOf(".");
1024
+ let pid = 0;
1025
+ let command = nameCol;
1026
+ if (lastDot > 0) {
1027
+ const possiblePid = parseInt(nameCol.substring(lastDot + 1));
1028
+ if (!isNaN(possiblePid)) {
1029
+ pid = possiblePid;
1030
+ command = nameCol.substring(0, lastDot);
1031
+ }
1032
+ }
1033
+ const rx = parseInt(cols[2]) || 0;
1034
+ const tx = parseInt(cols[3]) || 0;
1035
+ currentProc = { pid, command, rxBytes: rx, txBytes: tx, connections: [] };
1036
+ } else {
1037
+ if (currentProc) {
1038
+ const state = cols[1];
1039
+ const rx = parseInt(cols[2]) || 0;
1040
+ const tx = parseInt(cols[3]) || 0;
1041
+ if (state === "Established") connections++;
1042
+ const spaceIdx = nameCol.indexOf(" ");
1043
+ const protocol = spaceIdx > 0 ? nameCol.substring(0, spaceIdx) : "";
1044
+ const endpoints = spaceIdx > 0 ? nameCol.substring(spaceIdx + 1) : nameCol;
1045
+ const arrowIdx = endpoints.indexOf("<->");
1046
+ let local = "";
1047
+ let remote = "";
1048
+ if (arrowIdx > 0) {
1049
+ local = endpoints.substring(0, arrowIdx);
1050
+ remote = endpoints.substring(arrowIdx + 3);
1051
+ remote = resolveIp(remote);
1052
+ } else {
1053
+ local = endpoints;
1054
+ }
1055
+ currentProc.connections.push({ protocol, local, remote, state, rxBytes: rx, txBytes: tx });
1056
+ }
818
1057
  }
819
- return { pid: 0, command: "", rxBytes: 0, txBytes: 0 };
820
- }).filter((p) => p.pid > 0);
821
- allProcesses = topProcesses;
1058
+ }
1059
+ if (currentProc && currentProc.connections && currentProc.connections.length > 0) {
1060
+ allProcesses.push(currentProc);
1061
+ }
822
1062
  } catch {
823
- topProcesses = [];
824
1063
  allProcesses = [];
825
1064
  }
1065
+ const topProcesses = [...allProcesses].sort((a, b) => b.rxBytes + b.txBytes - (a.rxBytes + a.txBytes));
1066
+ const protocolStats = await getProtocolStats();
1067
+ const connectionStates = await getConnectionStates();
1068
+ const listeningPorts = await getListeningPorts();
826
1069
  return {
827
1070
  totalPackets: totalRxPackets + totalTxPackets,
828
1071
  rxPackets: totalRxPackets,
@@ -832,7 +1075,10 @@ async function collectPackets() {
832
1075
  connections,
833
1076
  topProcesses,
834
1077
  interfaces: ifaceStats,
835
- allProcesses
1078
+ allProcesses,
1079
+ protocolStats,
1080
+ connectionStates,
1081
+ listeningPorts
836
1082
  };
837
1083
  } catch {
838
1084
  return null;
@@ -921,6 +1167,7 @@ async function getTimeMachineStatus() {
921
1167
 
922
1168
  export {
923
1169
  collectAll,
1170
+ collectContainers,
924
1171
  collectPower,
925
1172
  collectGpu,
926
1173
  collectCpu,
@@ -1,6 +1,7 @@
1
1
  import {
2
2
  collectAll,
3
3
  collectBattery,
4
+ collectContainers,
4
5
  collectCpu,
5
6
  collectDisk,
6
7
  collectGpu,
@@ -13,11 +14,13 @@ import {
13
14
  collectThermal,
14
15
  getDisplayInfo,
15
16
  getTimeMachineStatus
16
- } from "./chunk-HGRBBPYX.js";
17
+ } from "./chunk-N4WJVF5M.js";
18
+ import "./chunk-25I533OF.js";
17
19
  import "./chunk-FH5WDJBF.js";
18
20
  export {
19
21
  collectAll,
20
22
  collectBattery,
23
+ collectContainers,
21
24
  collectCpu,
22
25
  collectDisk,
23
26
  collectGpu,
@@ -8,7 +8,7 @@ import {
8
8
  readConfig,
9
9
  saveProfile,
10
10
  writeConfig
11
- } from "./chunk-RVGKEJXT.js";
11
+ } from "./chunk-CXL4GYGQ.js";
12
12
  export {
13
13
  CONFIG_FILE,
14
14
  DEFAULT_CONFIG,
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  CONFIG_FILE,
3
3
  readConfig
4
- } from "./chunk-RVGKEJXT.js";
4
+ } from "./chunk-CXL4GYGQ.js";
5
5
  import {
6
6
  run
7
7
  } from "./chunk-FH5WDJBF.js";