pyre-cli 9.5.1 → 10.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +84 -14
- package/dist/alertChannels-TPSQIJ7S.js +8 -0
- package/dist/blender-FGH3ASEQ.js +7 -0
- package/dist/brewHealth-P2GW5Y5C.js +176 -0
- package/dist/buildCmd-CDPZ2ZFA.js +38 -0
- package/dist/{checkCmd-EWFNLBWE.js → checkCmd-RKW6QGDR.js} +10 -11
- package/dist/{chunk-RVGKEJXT.js → chunk-53O2RGSL.js} +47 -17
- package/dist/{chunk-MOAEGMFP.js → chunk-6UHZP4QP.js} +204 -46
- package/dist/chunk-GHRDW646.js +2506 -0
- package/dist/{prometheus-LFYHF6VO.js → chunk-HT4VQ4OH.js} +1 -0
- package/dist/chunk-M73HCQD2.js +95 -0
- package/dist/chunk-MZO5QKUR.js +32 -0
- package/dist/chunk-VIACN2RU.js +133 -0
- package/dist/chunk-Z2YV5HKV.js +87 -0
- package/dist/chunk-ZLVIVFSO.js +110 -0
- package/dist/{collectors-WD6VKH6M.js → collectors-H43PN4PS.js} +8 -2
- package/dist/{completions-VQMHQCXE.js → completions-JKYEJNGR.js} +34 -1
- package/dist/{config-4ZLF4HTS.js → config-GYGJXU2Q.js} +9 -1
- package/dist/doctor-GYHFTNZQ.js +387 -0
- package/dist/explainCmd-MF6PIMLW.js +222 -0
- package/dist/extensions-XJGHG7X3.js +134 -0
- package/dist/index.js +841 -206
- package/dist/ioreport.py +72 -0
- package/dist/netUsageCmd-WKBTW2YG.js +90 -0
- package/dist/{pipeCmd-7THXEGDH.js → pipeCmd-7REDBLBU.js} +5 -3
- package/dist/profileProcCmd-N4H6MCBT.js +107 -0
- package/dist/prometheus-5BL5PVLC.js +6 -0
- package/dist/prometheusCmd-PL64BLN5.js +93 -0
- package/dist/replayCmd-Z3PYXY7V.js +164 -0
- package/dist/run-HOGQDDTA.js +8 -0
- package/dist/serveCmd-2H5VLF3P.js +153 -0
- package/dist/service-Q74BBILO.js +181 -0
- package/dist/smartCmd-ODWKSFNG.js +166 -0
- package/dist/syncCmd-A2W3QB3S.js +126 -0
- package/dist/topoCmd-DU2HHZNH.js +148 -0
- package/dist/watchdogCmd-UF53JPZB.js +161 -0
- package/dist/{wizard-GVIAHIVV.js → wizard-TD7BGX6O.js} +1 -1
- package/install.ps1 +29 -0
- package/install.sh +10 -9
- package/package.json +7 -3
- package/src/ai/models.ts +138 -0
- package/src/alertChannels.ts +119 -0
- package/src/anomalies.ts +114 -60
- package/src/brewHealth.ts +157 -40
- package/src/buildCmd.ts +48 -0
- package/src/checkCmd.ts +5 -5
- package/src/completions.ts +35 -0
- package/src/doctor.ts +235 -7
- package/src/easy_features.test.ts +40 -0
- package/src/explainCmd.ts +261 -0
- package/src/extensions.ts +71 -7
- package/src/formatters/index.ts +1 -1
- package/src/formatters/output.ts +100 -13
- package/src/formatters/render.ts +274 -38
- package/src/formatters/themes.ts +8 -0
- package/src/formatters/types.ts +6 -1
- package/src/index.ts +298 -56
- package/src/live/input.ts +122 -4
- package/src/live/render.ts +98 -0
- package/src/live/state.ts +70 -52
- package/src/live/types.ts +2 -2
- package/src/monitors/batteryPredictor.ts +143 -0
- package/src/monitors/blender.ts +144 -0
- package/src/monitors/buildTracker.ts +121 -0
- package/src/monitors/collectors.ts +558 -147
- package/src/monitors/dns_cache.ts +48 -0
- package/src/monitors/index.ts +3 -2
- package/src/monitors/ioreport.py +72 -0
- package/src/monitors/platform/linux.ts +756 -0
- package/src/monitors/platform/windows.ts +519 -0
- package/src/monitors/run.ts +27 -3
- package/src/monitors/smc.ts +21 -1
- package/src/monitors/types.ts +112 -14
- package/src/netUsageCmd.ts +121 -0
- package/src/platform.test.ts +99 -0
- package/src/plugins/index.ts +143 -0
- package/src/profileProcCmd.ts +133 -0
- package/src/prometheusCmd.ts +107 -0
- package/src/replayCmd.ts +186 -0
- package/src/serveCmd.ts +180 -0
- package/src/service.ts +125 -7
- package/src/smartCmd.ts +205 -0
- package/src/state/config.ts +64 -17
- package/src/syncCmd.ts +166 -0
- package/src/topoCmd.ts +176 -0
- package/src/watchdogCmd.ts +198 -0
- package/src/xbar.ts +22 -11
- package/dist/brewHealth-F2BXF5M6.js +0 -74
- package/dist/chunk-FH5WDJBF.js +0 -15
- package/dist/chunk-HGRBBPYX.js +0 -937
- package/dist/doctor-L6FZYA7F.js +0 -184
- package/dist/extensions-DVA5YLGH.js +0 -74
- package/dist/service-WTS3NBQU.js +0 -73
- /package/dist/{chunk-SG26Y3WF.js → chunk-IM3IQMMT.js} +0 -0
package/src/anomalies.ts
CHANGED
|
@@ -18,84 +18,138 @@ export interface AnomalyAlert {
|
|
|
18
18
|
|
|
19
19
|
const ZSCORE_THRESHOLD = 2.5;
|
|
20
20
|
const CRITICAL_ZSCORE = 3.5;
|
|
21
|
-
const MIN_SAMPLES =
|
|
21
|
+
const MIN_SAMPLES = 10;
|
|
22
|
+
|
|
23
|
+
// Minimum absolute deviation from the mean required to trigger an anomaly
|
|
24
|
+
const MIN_DEV_CPU = 10; // 10%
|
|
25
|
+
const MIN_DEV_MEM = 5; // 5%
|
|
26
|
+
const MIN_DEV_TEMP = 5; // 5 degrees
|
|
27
|
+
const MIN_DEV_NET = 500_000; // 500 KB
|
|
28
|
+
const MIN_DEV_POWER = 5; // 5 Watts
|
|
29
|
+
const MIN_DEV_GPU = 10; // 10%
|
|
22
30
|
|
|
23
31
|
export function detectAnomalies(data: StatsData, history: History): AnomalyAlert[] {
|
|
24
32
|
const alerts: AnomalyAlert[] = [];
|
|
25
33
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
+
if (history.cpuUsage.length >= MIN_SAMPLES) {
|
|
35
|
+
const cpuMean = History.mean(history.cpuUsage);
|
|
36
|
+
if (Math.abs(data.cpu.usage - cpuMean) > MIN_DEV_CPU) {
|
|
37
|
+
const cpuZ = History.zScore(data.cpu.usage, history.cpuUsage);
|
|
38
|
+
if (Math.abs(cpuZ) > ZSCORE_THRESHOLD) {
|
|
39
|
+
alerts.push({
|
|
40
|
+
metric: 'CPU',
|
|
41
|
+
value: data.cpu.usage,
|
|
42
|
+
zScore: cpuZ,
|
|
43
|
+
severity: Math.abs(cpuZ) > CRITICAL_ZSCORE ? 'critical' : 'warning',
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
if (history.memUsage.length >= MIN_SAMPLES) {
|
|
50
|
+
const memMean = History.mean(history.memUsage);
|
|
51
|
+
if (Math.abs(data.memory.usagePercent - memMean) > MIN_DEV_MEM) {
|
|
52
|
+
const memZ = History.zScore(data.memory.usagePercent, history.memUsage);
|
|
53
|
+
if (Math.abs(memZ) > ZSCORE_THRESHOLD) {
|
|
54
|
+
alerts.push({
|
|
55
|
+
metric: 'Memory',
|
|
56
|
+
value: data.memory.usagePercent,
|
|
57
|
+
zScore: memZ,
|
|
58
|
+
severity: Math.abs(memZ) > CRITICAL_ZSCORE ? 'critical' : 'warning',
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
}
|
|
34
62
|
}
|
|
35
63
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
64
|
+
if (data.cpu.temperature !== undefined && history.temp.length >= MIN_SAMPLES) {
|
|
65
|
+
const tempMean = History.mean(history.temp);
|
|
66
|
+
if (Math.abs(data.cpu.temperature - tempMean) > MIN_DEV_TEMP) {
|
|
67
|
+
const tempZ = History.zScore(data.cpu.temperature, history.temp);
|
|
68
|
+
if (Math.abs(tempZ) > ZSCORE_THRESHOLD) {
|
|
69
|
+
alerts.push({
|
|
70
|
+
metric: 'Temp',
|
|
71
|
+
value: data.cpu.temperature,
|
|
72
|
+
zScore: tempZ,
|
|
73
|
+
severity: Math.abs(tempZ) > CRITICAL_ZSCORE ? 'critical' : 'warning',
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
}
|
|
44
77
|
}
|
|
45
78
|
|
|
46
|
-
if (
|
|
47
|
-
const
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
79
|
+
if (history.netRxRate.length >= MIN_SAMPLES) {
|
|
80
|
+
const currentRxRate = history.netRxRate[history.netRxRate.length - 1];
|
|
81
|
+
const netRxMean = History.mean(history.netRxRate);
|
|
82
|
+
if (Math.abs(currentRxRate - netRxMean) > MIN_DEV_NET) {
|
|
83
|
+
const netRxZ = History.zScore(currentRxRate, history.netRxRate);
|
|
84
|
+
if (Math.abs(netRxZ) > ZSCORE_THRESHOLD) {
|
|
85
|
+
alerts.push({
|
|
86
|
+
metric: 'Net RX',
|
|
87
|
+
value: currentRxRate,
|
|
88
|
+
zScore: netRxZ,
|
|
89
|
+
severity: Math.abs(netRxZ) > CRITICAL_ZSCORE ? 'critical' : 'warning',
|
|
90
|
+
});
|
|
91
|
+
}
|
|
55
92
|
}
|
|
56
93
|
}
|
|
57
94
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
95
|
+
if (history.netTxRate.length >= MIN_SAMPLES) {
|
|
96
|
+
const currentTxRate = history.netTxRate[history.netTxRate.length - 1];
|
|
97
|
+
const netTxMean = History.mean(history.netTxRate);
|
|
98
|
+
if (Math.abs(currentTxRate - netTxMean) > MIN_DEV_NET) {
|
|
99
|
+
const netTxZ = History.zScore(currentTxRate, history.netTxRate);
|
|
100
|
+
if (Math.abs(netTxZ) > ZSCORE_THRESHOLD) {
|
|
101
|
+
alerts.push({
|
|
102
|
+
metric: 'Net TX',
|
|
103
|
+
value: currentTxRate,
|
|
104
|
+
zScore: netTxZ,
|
|
105
|
+
severity: Math.abs(netTxZ) > CRITICAL_ZSCORE ? 'critical' : 'warning',
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
}
|
|
66
109
|
}
|
|
67
110
|
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
111
|
+
if (data.power?.combinedWatts !== undefined && history.powerWatts.length >= MIN_SAMPLES) {
|
|
112
|
+
const powerMean = History.mean(history.powerWatts);
|
|
113
|
+
if (Math.abs(data.power.combinedWatts - powerMean) > MIN_DEV_POWER) {
|
|
114
|
+
const powerZ = History.zScore(data.power.combinedWatts, history.powerWatts);
|
|
115
|
+
if (Math.abs(powerZ) > ZSCORE_THRESHOLD) {
|
|
116
|
+
alerts.push({
|
|
117
|
+
metric: 'Power',
|
|
118
|
+
value: data.power.combinedWatts,
|
|
119
|
+
zScore: powerZ,
|
|
120
|
+
severity: Math.abs(powerZ) > CRITICAL_ZSCORE ? 'critical' : 'warning',
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
}
|
|
76
124
|
}
|
|
77
125
|
|
|
78
|
-
if (
|
|
79
|
-
const
|
|
80
|
-
if (Math.abs(
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
126
|
+
if (history.connections.length >= MIN_SAMPLES) {
|
|
127
|
+
const connMean = History.mean(history.connections);
|
|
128
|
+
if (Math.abs((data.packets?.connections || data.network.connections || 0) - connMean) > 5) {
|
|
129
|
+
const connZ = History.zScore(data.packets?.connections || data.network.connections || 0, history.connections);
|
|
130
|
+
if (Math.abs(connZ) > ZSCORE_THRESHOLD) {
|
|
131
|
+
alerts.push({
|
|
132
|
+
metric: 'Connections',
|
|
133
|
+
value: data.packets?.connections || data.network.connections || 0,
|
|
134
|
+
zScore: connZ,
|
|
135
|
+
severity: Math.abs(connZ) > CRITICAL_ZSCORE ? 'critical' : 'warning',
|
|
136
|
+
});
|
|
137
|
+
}
|
|
87
138
|
}
|
|
88
139
|
}
|
|
89
140
|
|
|
90
|
-
if (data.gpu) {
|
|
91
|
-
const
|
|
92
|
-
if (Math.abs(
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
141
|
+
if (data.gpu && history.gpuUtil.length >= MIN_SAMPLES) {
|
|
142
|
+
const gpuMean = History.mean(history.gpuUtil);
|
|
143
|
+
if (Math.abs(data.gpu.utilization - gpuMean) > MIN_DEV_GPU) {
|
|
144
|
+
const gpuZ = History.zScore(data.gpu.utilization, history.gpuUtil);
|
|
145
|
+
if (Math.abs(gpuZ) > ZSCORE_THRESHOLD) {
|
|
146
|
+
alerts.push({
|
|
147
|
+
metric: 'GPU',
|
|
148
|
+
value: data.gpu.utilization,
|
|
149
|
+
zScore: gpuZ,
|
|
150
|
+
severity: Math.abs(gpuZ) > CRITICAL_ZSCORE ? 'critical' : 'warning',
|
|
151
|
+
});
|
|
152
|
+
}
|
|
99
153
|
}
|
|
100
154
|
}
|
|
101
155
|
|
package/src/brewHealth.ts
CHANGED
|
@@ -7,76 +7,193 @@ export interface BrewHealthInfo {
|
|
|
7
7
|
cellarSize: string;
|
|
8
8
|
doctorWarnings: string[];
|
|
9
9
|
brewAvailable: boolean;
|
|
10
|
+
managerName: string;
|
|
10
11
|
}
|
|
11
12
|
|
|
12
13
|
export async function getBrewHealth(): Promise<BrewHealthInfo> {
|
|
14
|
+
const isWindows = process.platform === 'win32';
|
|
15
|
+
|
|
16
|
+
// 1. Try Homebrew (macOS or Linuxbrew)
|
|
13
17
|
try {
|
|
14
|
-
const brewPath = await run('which brew 2>&1', '');
|
|
15
|
-
if (
|
|
16
|
-
|
|
18
|
+
const brewPath = await run(isWindows ? 'where brew 2>nul' : 'which brew 2>&1', '');
|
|
19
|
+
if (brewPath.trim() && !brewPath.includes('not found') && !brewPath.includes('Could not find')) {
|
|
20
|
+
const outdatedRaw = await run('brew outdated --quiet 2>&1', '');
|
|
21
|
+
const outdatedLines = outdatedRaw.trim().split('\n').filter(l => l.length > 0 && !l.startsWith('Homebrew') && !l.startsWith('==>'));
|
|
22
|
+
|
|
23
|
+
const listRaw = await run('brew list --formula -1 2>&1', '');
|
|
24
|
+
const listLines = listRaw.trim().split('\n').filter(l => l.length > 0);
|
|
25
|
+
|
|
26
|
+
let cellarSize = 'N/A';
|
|
27
|
+
try {
|
|
28
|
+
const cellarPath = await run('brew --cellar 2>&1', '');
|
|
29
|
+
if (cellarPath.trim()) {
|
|
30
|
+
const duRaw = await run(`du -sh "${cellarPath.trim()}" 2>&1`, '');
|
|
31
|
+
const duMatch = duRaw.match(/^([0-9.,]+[KMGTP]?i?B?)/i);
|
|
32
|
+
if (duMatch) cellarSize = duMatch[1];
|
|
33
|
+
}
|
|
34
|
+
} catch {
|
|
35
|
+
cellarSize = 'N/A';
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
const doctorRaw = await run('brew doctor 2>&1', '');
|
|
39
|
+
const doctorWarnings: string[] = [];
|
|
40
|
+
const docLines = doctorRaw.split('\n');
|
|
41
|
+
for (const line of docLines) {
|
|
42
|
+
if (line.startsWith('Warning:')) {
|
|
43
|
+
doctorWarnings.push(line.replace(/^Warning:\s*/, '').trim());
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
return {
|
|
48
|
+
installedCount: listLines.length,
|
|
49
|
+
outdatedCount: outdatedLines.length,
|
|
50
|
+
cellarSize,
|
|
51
|
+
doctorWarnings,
|
|
52
|
+
brewAvailable: true,
|
|
53
|
+
managerName: 'Homebrew',
|
|
54
|
+
};
|
|
17
55
|
}
|
|
56
|
+
} catch {
|
|
57
|
+
// continue to alternative managers
|
|
58
|
+
}
|
|
18
59
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
60
|
+
// 2. Linux Package Managers (APT, DNF, Pacman)
|
|
61
|
+
if (process.platform === 'linux') {
|
|
62
|
+
// Try APT
|
|
63
|
+
try {
|
|
64
|
+
const whichApt = (await run('which apt-get 2>/dev/null', '')).trim();
|
|
65
|
+
if (whichApt) {
|
|
66
|
+
const listRaw = (await run('dpkg-query -l 2>/dev/null', '')).trim();
|
|
67
|
+
const installed = listRaw ? listRaw.split('\n').filter(l => l.startsWith('ii')).length : 0;
|
|
68
|
+
const upgradeRaw = (await run('apt list --upgradable 2>/dev/null', '')).trim();
|
|
69
|
+
const outdated = upgradeRaw ? upgradeRaw.split('\n').filter(l => l.includes('/') && !l.startsWith('Listing')).length : 0;
|
|
70
|
+
return {
|
|
71
|
+
installedCount: installed,
|
|
72
|
+
outdatedCount: outdated,
|
|
73
|
+
cellarSize: '/var/cache/apt',
|
|
74
|
+
doctorWarnings: [],
|
|
75
|
+
brewAvailable: true,
|
|
76
|
+
managerName: 'APT (Debian/Ubuntu)',
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
} catch {
|
|
80
|
+
// ignore
|
|
81
|
+
}
|
|
22
82
|
|
|
23
|
-
//
|
|
24
|
-
|
|
25
|
-
|
|
83
|
+
// Try Pacman
|
|
84
|
+
try {
|
|
85
|
+
const whichPacman = (await run('which pacman 2>/dev/null', '')).trim();
|
|
86
|
+
if (whichPacman) {
|
|
87
|
+
const listRaw = (await run('pacman -Q 2>/dev/null', '')).trim();
|
|
88
|
+
const installed = listRaw ? listRaw.split('\n').filter(Boolean).length : 0;
|
|
89
|
+
const upgradeRaw = (await run('checkupdates 2>/dev/null || pacman -Qu 2>/dev/null', '')).trim();
|
|
90
|
+
const outdated = upgradeRaw ? upgradeRaw.split('\n').filter(Boolean).length : 0;
|
|
91
|
+
return {
|
|
92
|
+
installedCount: installed,
|
|
93
|
+
outdatedCount: outdated,
|
|
94
|
+
cellarSize: '/var/cache/pacman',
|
|
95
|
+
doctorWarnings: [],
|
|
96
|
+
brewAvailable: true,
|
|
97
|
+
managerName: 'Pacman (Arch)',
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
} catch {
|
|
101
|
+
// ignore
|
|
102
|
+
}
|
|
26
103
|
|
|
27
|
-
//
|
|
28
|
-
let cellarSize = 'N/A';
|
|
104
|
+
// Try DNF
|
|
29
105
|
try {
|
|
30
|
-
const
|
|
31
|
-
if (
|
|
32
|
-
const
|
|
33
|
-
const
|
|
34
|
-
|
|
106
|
+
const whichDnf = (await run('which dnf 2>/dev/null', '')).trim();
|
|
107
|
+
if (whichDnf) {
|
|
108
|
+
const listRaw = (await run('dnf list installed 2>/dev/null', '')).trim();
|
|
109
|
+
const installed = listRaw ? listRaw.split('\n').filter(Boolean).length - 1 : 0;
|
|
110
|
+
return {
|
|
111
|
+
installedCount: Math.max(0, installed),
|
|
112
|
+
outdatedCount: 0,
|
|
113
|
+
cellarSize: '/var/cache/dnf',
|
|
114
|
+
doctorWarnings: [],
|
|
115
|
+
brewAvailable: true,
|
|
116
|
+
managerName: 'DNF (Fedora/RHEL)',
|
|
117
|
+
};
|
|
35
118
|
}
|
|
36
119
|
} catch {
|
|
37
|
-
|
|
120
|
+
// ignore
|
|
38
121
|
}
|
|
122
|
+
}
|
|
39
123
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
if (
|
|
46
|
-
|
|
124
|
+
// 3. Windows Package Managers (winget, choco, scoop)
|
|
125
|
+
if (isWindows) {
|
|
126
|
+
// Try winget
|
|
127
|
+
try {
|
|
128
|
+
const whichWinget = (await run('where winget 2>nul', '')).trim();
|
|
129
|
+
if (whichWinget) {
|
|
130
|
+
const listRaw = (await run('winget list 2>nul', '', 4000)).trim();
|
|
131
|
+
const installed = listRaw ? listRaw.split('\n').filter(Boolean).length - 2 : 0;
|
|
132
|
+
return {
|
|
133
|
+
installedCount: Math.max(0, installed),
|
|
134
|
+
outdatedCount: 0,
|
|
135
|
+
cellarSize: 'N/A',
|
|
136
|
+
doctorWarnings: [],
|
|
137
|
+
brewAvailable: true,
|
|
138
|
+
managerName: 'Windows Package Manager (winget)',
|
|
139
|
+
};
|
|
47
140
|
}
|
|
141
|
+
} catch {
|
|
142
|
+
// ignore
|
|
48
143
|
}
|
|
49
144
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
145
|
+
// Try scoop
|
|
146
|
+
try {
|
|
147
|
+
const whichScoop = (await run('where scoop 2>nul', '')).trim();
|
|
148
|
+
if (whichScoop) {
|
|
149
|
+
const listRaw = (await run('scoop list 2>nul', '')).trim();
|
|
150
|
+
const installed = listRaw ? listRaw.split('\n').filter(Boolean).length - 4 : 0;
|
|
151
|
+
return {
|
|
152
|
+
installedCount: Math.max(0, installed),
|
|
153
|
+
outdatedCount: 0,
|
|
154
|
+
cellarSize: 'N/A',
|
|
155
|
+
doctorWarnings: [],
|
|
156
|
+
brewAvailable: true,
|
|
157
|
+
managerName: 'Scoop',
|
|
158
|
+
};
|
|
159
|
+
}
|
|
160
|
+
} catch {
|
|
161
|
+
// ignore
|
|
162
|
+
}
|
|
59
163
|
}
|
|
164
|
+
|
|
165
|
+
return {
|
|
166
|
+
installedCount: 0,
|
|
167
|
+
outdatedCount: 0,
|
|
168
|
+
cellarSize: 'N/A',
|
|
169
|
+
doctorWarnings: [],
|
|
170
|
+
brewAvailable: false,
|
|
171
|
+
managerName: 'None',
|
|
172
|
+
};
|
|
60
173
|
}
|
|
61
174
|
|
|
62
175
|
export async function printBrewHealthReport(): Promise<void> {
|
|
63
|
-
console.log(chalk.bold('\n pyre brew — Homebrew Health Summary\n'));
|
|
64
176
|
const health = await getBrewHealth();
|
|
177
|
+
const label = health.brewAvailable ? health.managerName : 'Package Manager';
|
|
178
|
+
console.log(chalk.bold(`\n pyre brew — ${label} Health Summary\n`));
|
|
65
179
|
|
|
66
180
|
if (!health.brewAvailable) {
|
|
67
|
-
console.log(chalk.yellow(' ⚠
|
|
181
|
+
console.log(chalk.yellow(' ⚠ No supported package manager detected on PATH.\n'));
|
|
68
182
|
return;
|
|
69
183
|
}
|
|
70
184
|
|
|
71
|
-
console.log(` 📦
|
|
72
|
-
console.log(`
|
|
73
|
-
console.log(`
|
|
185
|
+
console.log(` 📦 Package Manager: ${chalk.cyan.bold(health.managerName)}`);
|
|
186
|
+
console.log(` 📦 Installed Packages: ${chalk.bold(health.installedCount)}`);
|
|
187
|
+
console.log(` ⏳ Outdated Packages: ${health.outdatedCount > 0 ? chalk.yellow.bold(health.outdatedCount) : chalk.green('0 (Up to date)')}`);
|
|
188
|
+
if (health.cellarSize !== 'N/A') {
|
|
189
|
+
console.log(` 💾 Cache / Cellar: ${chalk.bold(health.cellarSize)}`);
|
|
190
|
+
}
|
|
74
191
|
|
|
75
192
|
console.log();
|
|
76
193
|
if (health.doctorWarnings.length === 0) {
|
|
77
|
-
console.log(chalk.green(
|
|
194
|
+
console.log(chalk.green(` ✔ ${health.managerName}: Ready and healthy.`));
|
|
78
195
|
} else {
|
|
79
|
-
console.log(chalk.yellow(` ⚠
|
|
196
|
+
console.log(chalk.yellow(` ⚠ Diagnostics warnings (${health.doctorWarnings.length}):`));
|
|
80
197
|
for (const warn of health.doctorWarnings.slice(0, 5)) {
|
|
81
198
|
console.log(chalk.dim(` • ${warn}`));
|
|
82
199
|
}
|
package/src/buildCmd.ts
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* pyre build — Active Build System Tracker.
|
|
3
|
+
*
|
|
4
|
+
* Discovers running compilation and build tools (xcodebuild, cargo, swift,
|
|
5
|
+
* make, ninja, bazel, go), displaying real-time compiler workers, parallelism,
|
|
6
|
+
* and CPU/RAM footprints.
|
|
7
|
+
*/
|
|
8
|
+
import chalk from 'chalk';
|
|
9
|
+
import { collectBuilds } from './monitors/buildTracker.js';
|
|
10
|
+
|
|
11
|
+
export interface BuildOptions {
|
|
12
|
+
watch?: boolean;
|
|
13
|
+
json?: boolean;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export async function runBuildCommand(opts: BuildOptions = {}): Promise<void> {
|
|
17
|
+
const builds = await collectBuilds();
|
|
18
|
+
|
|
19
|
+
if (opts.json) {
|
|
20
|
+
console.log(JSON.stringify({ activeBuilds: builds }, null, 2));
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
console.log(chalk.bold('\n 🔥 pyre build — Active Build System Tracker\n'));
|
|
25
|
+
|
|
26
|
+
if (builds.length === 0) {
|
|
27
|
+
console.log(chalk.dim(' No active build or compilation processes detected.'));
|
|
28
|
+
console.log(chalk.dim(' (Supports: xcodebuild, cargo, swift build, make, ninja, bazel, go build)\n'));
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
for (const b of builds) {
|
|
33
|
+
const elapsedMins = Math.floor(b.elapsedSec / 60);
|
|
34
|
+
const elapsedSecs = b.elapsedSec % 60;
|
|
35
|
+
const timeStr = elapsedMins > 0 ? `${elapsedMins}m ${elapsedSecs}s` : `${elapsedSecs}s`;
|
|
36
|
+
|
|
37
|
+
console.log(` ${chalk.bgCyan.black.bold(` ${b.tool.toUpperCase()} `)} ${chalk.bold(`PID ${b.rootPid}`)}`);
|
|
38
|
+
console.log(` Command: ${chalk.white(b.command)}`);
|
|
39
|
+
if (b.target) {
|
|
40
|
+
console.log(` Target: ${chalk.cyan(b.target)}`);
|
|
41
|
+
}
|
|
42
|
+
console.log(` Compiler Workers: ${chalk.green.bold(String(b.compilerProcesses))} active thread/processes`);
|
|
43
|
+
console.log(` Combined CPU: ${chalk.yellow.bold(b.totalCpu.toFixed(1) + '%')}`);
|
|
44
|
+
console.log(` Combined RAM: ${chalk.magenta(b.totalMem.toFixed(1) + '%')}`);
|
|
45
|
+
console.log(` Elapsed Time: ${chalk.dim(timeStr)}`);
|
|
46
|
+
console.log();
|
|
47
|
+
}
|
|
48
|
+
}
|
package/src/checkCmd.ts
CHANGED
|
@@ -15,7 +15,7 @@ export async function runCheckCommand(opts: CheckOptions = {}): Promise<void> {
|
|
|
15
15
|
const cpuUsage = data.cpu.usage;
|
|
16
16
|
const tempC = data.cpu.temperature ?? data.thermal.temperatures?.cpu_die;
|
|
17
17
|
const memUsage = data.memory.usagePercent;
|
|
18
|
-
const disk = data.disk.
|
|
18
|
+
const disk = data.disk && data.disk.length > 0 ? data.disk[0] : null;
|
|
19
19
|
|
|
20
20
|
const sentences: string[] = [];
|
|
21
21
|
let isWarning = false;
|
|
@@ -61,10 +61,10 @@ export async function runCheckCommand(opts: CheckOptions = {}): Promise<void> {
|
|
|
61
61
|
|
|
62
62
|
// Disk sentence
|
|
63
63
|
if (disk) {
|
|
64
|
-
const
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
if (
|
|
64
|
+
const freeStr = disk.available;
|
|
65
|
+
sentences.push(`${freeStr} free on ${disk.mountpoint}.`);
|
|
66
|
+
const cap = parseInt(disk.capacity, 10);
|
|
67
|
+
if (!isNaN(cap) && cap >= 90) {
|
|
68
68
|
isWarning = true;
|
|
69
69
|
}
|
|
70
70
|
}
|
package/src/completions.ts
CHANGED
|
@@ -116,3 +116,38 @@ complete -c pyre -l sort -x -a "cpu mem pid user command state threads runtime"
|
|
|
116
116
|
complete -c pyre -l temp-unit -x -a "c f" -d "Temperature unit"
|
|
117
117
|
`;
|
|
118
118
|
}
|
|
119
|
+
|
|
120
|
+
export function generatePowerShellCompletions(): string {
|
|
121
|
+
return `# PowerShell completion for pyre
|
|
122
|
+
Register-ArgumentCompleter -Native -CommandName pyre -ScriptBlock {
|
|
123
|
+
param($wordToComplete, $commandAst, $cursorPosition)
|
|
124
|
+
$commands = @('live', 'check', 'pipe', 'stress', 'ui', 'web', 'ssh', 'fleet', 'bench', 'benchmark', 'anomalies', 'doctor', 'extensions', 'brew', 'update', 'profile', 'config', 'history', 'diff', 'info', 'completions', 'p2p', 'blender', 'prometheus', 'smart', 'replay', 'explain')
|
|
125
|
+
$options = @('--json', '--html', '--md', '--csv', '--tsv', '--detailed', '--theme', '--interval', '--once', '--out', '--export-dir', '--log', '--tree', '--sort', '--packets', '--limit', '--alert-cpu', '--alert-temp', '--temp-unit', '--plain', '--help', '--version')
|
|
126
|
+
|
|
127
|
+
$elements = $commandAst.CommandElements
|
|
128
|
+
if ($elements.Count -le 2) {
|
|
129
|
+
$commands | Where-Object { $_ -like "$wordToComplete*" } | ForEach-Object {
|
|
130
|
+
[System.Management.Automation.CompletionResult]::new($_, $_, 'ParameterValue', $_)
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
$options | Where-Object { $_ -like "$wordToComplete*" } | ForEach-Object {
|
|
134
|
+
[System.Management.Automation.CompletionResult]::new($_, $_, 'ParameterName', $_)
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
`;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
export function printCompletions(shell: string): void {
|
|
141
|
+
const s = (shell || '').toLowerCase();
|
|
142
|
+
if (s === 'bash') {
|
|
143
|
+
console.log(generateBashCompletions());
|
|
144
|
+
} else if (s === 'fish') {
|
|
145
|
+
console.log(generateFishCompletions());
|
|
146
|
+
} else if (s === 'powershell' || s === 'pwsh') {
|
|
147
|
+
console.log(generatePowerShellCompletions());
|
|
148
|
+
} else {
|
|
149
|
+
console.log(generateZshCompletions());
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
|