pyre-cli 9.5.2 → 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 +73 -16
- package/dist/alertChannels-TPSQIJ7S.js +8 -0
- package/dist/{blender-7UT5J7IP.js → blender-FGH3ASEQ.js} +2 -2
- package/dist/brewHealth-P2GW5Y5C.js +176 -0
- package/dist/buildCmd-CDPZ2ZFA.js +38 -0
- package/dist/{checkCmd-T7O4KXXA.js → checkCmd-RKW6QGDR.js} +9 -11
- package/dist/{chunk-CXL4GYGQ.js → chunk-53O2RGSL.js} +44 -17
- package/dist/{chunk-3TE7MJLS.js → chunk-6UHZP4QP.js} +36 -10
- 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-25I533OF.js → chunk-VIACN2RU.js} +1 -1
- package/dist/chunk-Z2YV5HKV.js +87 -0
- package/dist/chunk-ZLVIVFSO.js +110 -0
- package/dist/{collectors-JB4OGUEF.js → collectors-H43PN4PS.js} +6 -3
- package/dist/{completions-VQMHQCXE.js → completions-JKYEJNGR.js} +34 -1
- package/dist/{config-KS5ZZ3VN.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 +460 -88
- package/dist/ioreport.py +72 -0
- package/dist/netUsageCmd-WKBTW2YG.js +90 -0
- package/dist/{pipeCmd-TYLJHQ5B.js → pipeCmd-7REDBLBU.js} +4 -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-Z3RGA3VB.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/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/render.ts +34 -10
- package/src/formatters/types.ts +2 -0
- package/src/index.ts +251 -36
- package/src/live/input.ts +60 -0
- package/src/live/render.ts +67 -0
- package/src/live/state.ts +5 -0
- package/src/live/types.ts +1 -1
- package/src/monitors/batteryPredictor.ts +143 -0
- package/src/monitors/buildTracker.ts +121 -0
- package/src/monitors/collectors.ts +342 -178
- 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 +15 -0
- 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 +58 -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-N4WJVF5M.js +0 -1184
- package/dist/doctor-UV7TWIHX.js +0 -184
- package/dist/extensions-DVA5YLGH.js +0 -74
- package/dist/service-WTS3NBQU.js +0 -73
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* pyre watchdog — Persistent Autonomous Rules Engine.
|
|
3
|
+
*
|
|
4
|
+
* Evaluates configurable metric threshold and process rules continuously,
|
|
5
|
+
* executing remediation actions (kill, renice) and dispatching multi-channel alerts.
|
|
6
|
+
*
|
|
7
|
+
* Example watchdog configuration rule:
|
|
8
|
+
* {
|
|
9
|
+
* "name": "Stop runaway background renderers",
|
|
10
|
+
* "metric": "cpu",
|
|
11
|
+
* "process": "photoanalysisd",
|
|
12
|
+
* "threshold": 80,
|
|
13
|
+
* "durationSec": 10,
|
|
14
|
+
* "action": "kill", // "kill" | "notify" | "alert"
|
|
15
|
+
* "cooldownSec": 60
|
|
16
|
+
* }
|
|
17
|
+
*/
|
|
18
|
+
import fs from 'node:fs';
|
|
19
|
+
import path from 'node:path';
|
|
20
|
+
import chalk from 'chalk';
|
|
21
|
+
import { collectAll } from './monitors/collectors.js';
|
|
22
|
+
import { sendAlert } from './alertChannels.js';
|
|
23
|
+
import { getConfigDir, readConfig } from './state/config.js';
|
|
24
|
+
|
|
25
|
+
export interface WatchdogRule {
|
|
26
|
+
name: string;
|
|
27
|
+
metric?: 'cpu' | 'mem' | 'temp' | 'process_cpu' | 'process_mem';
|
|
28
|
+
process?: string;
|
|
29
|
+
threshold: number;
|
|
30
|
+
durationSec?: number;
|
|
31
|
+
action: 'kill' | 'notify' | 'alert';
|
|
32
|
+
cooldownSec?: number;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export interface WatchdogOptions {
|
|
36
|
+
configFile?: string;
|
|
37
|
+
dryRun?: boolean;
|
|
38
|
+
interval?: number;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const DEFAULT_WATCHDOG_RULES: WatchdogRule[] = [
|
|
42
|
+
{
|
|
43
|
+
name: 'High CPU System Alert',
|
|
44
|
+
metric: 'cpu',
|
|
45
|
+
threshold: 92,
|
|
46
|
+
durationSec: 5,
|
|
47
|
+
action: 'alert',
|
|
48
|
+
cooldownSec: 120,
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
name: 'Critical Temperature Protection',
|
|
52
|
+
metric: 'temp',
|
|
53
|
+
threshold: 98,
|
|
54
|
+
durationSec: 5,
|
|
55
|
+
action: 'alert',
|
|
56
|
+
cooldownSec: 180,
|
|
57
|
+
},
|
|
58
|
+
];
|
|
59
|
+
|
|
60
|
+
export async function runWatchdogCommand(opts: WatchdogOptions = {}): Promise<void> {
|
|
61
|
+
const configDir = getConfigDir();
|
|
62
|
+
const defaultRulePath = path.join(configDir, 'watchdog.json');
|
|
63
|
+
const rulePath = opts.configFile || defaultRulePath;
|
|
64
|
+
const intervalSec = opts.interval || 2;
|
|
65
|
+
const isDryRun = !!opts.dryRun;
|
|
66
|
+
|
|
67
|
+
let rules: WatchdogRule[] = DEFAULT_WATCHDOG_RULES;
|
|
68
|
+
|
|
69
|
+
if (fs.existsSync(rulePath)) {
|
|
70
|
+
try {
|
|
71
|
+
rules = JSON.parse(fs.readFileSync(rulePath, 'utf-8'));
|
|
72
|
+
} catch (err: any) {
|
|
73
|
+
console.error(chalk.yellow(` ⚠ Could not parse watchdog config at ${rulePath}: ${err.message}. Using default rules.`));
|
|
74
|
+
}
|
|
75
|
+
} else if (!opts.configFile) {
|
|
76
|
+
try {
|
|
77
|
+
if (!fs.existsSync(configDir)) fs.mkdirSync(configDir, { recursive: true });
|
|
78
|
+
fs.writeFileSync(defaultRulePath, JSON.stringify(DEFAULT_WATCHDOG_RULES, null, 2));
|
|
79
|
+
} catch {
|
|
80
|
+
// ignore
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
console.log(chalk.bold('\n 🔥 pyre watchdog — Autonomous Monitoring Daemon\n'));
|
|
85
|
+
console.log(` ${chalk.green('✔')} Loaded ${chalk.bold(String(rules.length))} rule(s) from ${chalk.cyan(rulePath)}`);
|
|
86
|
+
console.log(` ${chalk.green('✔')} Refresh interval: ${intervalSec}s | Dry run mode: ${isDryRun ? chalk.yellow('ON') : chalk.dim('OFF')}`);
|
|
87
|
+
console.log(`\n ${chalk.dim('Active Rules:')}`);
|
|
88
|
+
for (const r of rules) {
|
|
89
|
+
const target = r.process ? `proc "${r.process}"` : r.metric || 'system';
|
|
90
|
+
console.log(` • ${chalk.bold(r.name)} [if ${target} > ${r.threshold} → ${chalk.cyan(r.action)}]`);
|
|
91
|
+
}
|
|
92
|
+
console.log(chalk.dim('\n Watching... Press Ctrl+C to stop.\n'));
|
|
93
|
+
|
|
94
|
+
// Track rule trigger history for cooldowns
|
|
95
|
+
const lastTriggered = new Map<string, number>();
|
|
96
|
+
|
|
97
|
+
const config = readConfig();
|
|
98
|
+
const alertChannels = {
|
|
99
|
+
slackUrl: config.slackAlertUrl,
|
|
100
|
+
discordUrl: config.discordAlertUrl,
|
|
101
|
+
pushoverToken: config.pushoverToken,
|
|
102
|
+
pushoverUser: config.pushoverUser,
|
|
103
|
+
ntfyUrl: config.ntfyUrl,
|
|
104
|
+
};
|
|
105
|
+
|
|
106
|
+
const evaluate = async () => {
|
|
107
|
+
try {
|
|
108
|
+
const data = await collectAll();
|
|
109
|
+
const now = Date.now();
|
|
110
|
+
|
|
111
|
+
for (const rule of rules) {
|
|
112
|
+
const cooldown = (rule.cooldownSec || 60) * 1000;
|
|
113
|
+
const last = lastTriggered.get(rule.name) || 0;
|
|
114
|
+
if (now - last < cooldown) continue;
|
|
115
|
+
|
|
116
|
+
let triggered = false;
|
|
117
|
+
let detail = '';
|
|
118
|
+
let targetPid: number | null = null;
|
|
119
|
+
|
|
120
|
+
if (rule.process) {
|
|
121
|
+
const match = data.processes.find(p => p.command.toLowerCase().includes(rule.process!.toLowerCase()));
|
|
122
|
+
if (match) {
|
|
123
|
+
const val = rule.metric === 'process_mem' ? match.mem : match.cpu;
|
|
124
|
+
if (val >= rule.threshold) {
|
|
125
|
+
triggered = true;
|
|
126
|
+
targetPid = match.pid;
|
|
127
|
+
detail = `Process "${match.command}" (PID ${match.pid}) at ${val.toFixed(1)}% (threshold ${rule.threshold}%)`;
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
} else if (rule.metric === 'cpu') {
|
|
131
|
+
if (data.cpu.usage >= rule.threshold) {
|
|
132
|
+
triggered = true;
|
|
133
|
+
detail = `System CPU usage at ${data.cpu.usage.toFixed(1)}% (threshold ${rule.threshold}%)`;
|
|
134
|
+
}
|
|
135
|
+
} else if (rule.metric === 'mem') {
|
|
136
|
+
if (data.memory.usagePercent >= rule.threshold) {
|
|
137
|
+
triggered = true;
|
|
138
|
+
detail = `System Memory at ${data.memory.usagePercent.toFixed(1)}% (threshold ${rule.threshold}%)`;
|
|
139
|
+
}
|
|
140
|
+
} else if (rule.metric === 'temp') {
|
|
141
|
+
const temp = data.cpu.temperature ?? data.thermal.temperatures?.cpu_die;
|
|
142
|
+
if (temp !== undefined && temp >= rule.threshold) {
|
|
143
|
+
triggered = true;
|
|
144
|
+
detail = `System Temperature at ${temp.toFixed(1)}°C (threshold ${rule.threshold}°C)`;
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
if (triggered) {
|
|
149
|
+
lastTriggered.set(rule.name, now);
|
|
150
|
+
const timeStr = new Date().toLocaleTimeString();
|
|
151
|
+
console.log(` [${chalk.dim(timeStr)}] ${chalk.red.bold('⚠ TRIGGERED:')} ${chalk.bold(rule.name)}: ${detail}`);
|
|
152
|
+
|
|
153
|
+
if (isDryRun) {
|
|
154
|
+
console.log(chalk.yellow(` [DRY RUN] Would execute action: ${rule.action}`));
|
|
155
|
+
continue;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
if (rule.action === 'kill' && targetPid) {
|
|
159
|
+
try {
|
|
160
|
+
process.kill(targetPid, 'SIGTERM');
|
|
161
|
+
console.log(chalk.green(` ✔ Killed PID ${targetPid} with SIGTERM`));
|
|
162
|
+
} catch (err: any) {
|
|
163
|
+
console.log(chalk.red(` ✖ Failed to kill PID ${targetPid}: ${err.message}`));
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
if (rule.action === 'alert') {
|
|
168
|
+
await sendAlert({
|
|
169
|
+
metric: rule.name,
|
|
170
|
+
value: rule.threshold,
|
|
171
|
+
threshold: rule.threshold,
|
|
172
|
+
unit: '%',
|
|
173
|
+
host: data.header.hostname,
|
|
174
|
+
timestamp: new Date().toISOString(),
|
|
175
|
+
severity: 'critical',
|
|
176
|
+
}, alertChannels).catch(() => {});
|
|
177
|
+
console.log(chalk.green(' ✔ Multi-channel alert dispatched.'));
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
} catch {
|
|
182
|
+
// ignore loop error
|
|
183
|
+
}
|
|
184
|
+
};
|
|
185
|
+
|
|
186
|
+
await evaluate();
|
|
187
|
+
const handle = setInterval(evaluate, intervalSec * 1000);
|
|
188
|
+
|
|
189
|
+
// Keep alive until SIGINT
|
|
190
|
+
await new Promise<void>((resolve) => {
|
|
191
|
+
process.on('SIGINT', () => {
|
|
192
|
+
clearInterval(handle);
|
|
193
|
+
console.log(chalk.dim('\n Watchdog stopped.'));
|
|
194
|
+
resolve();
|
|
195
|
+
process.exit(0);
|
|
196
|
+
});
|
|
197
|
+
});
|
|
198
|
+
}
|
package/src/xbar.ts
CHANGED
|
@@ -6,16 +6,15 @@ import chalk from 'chalk';
|
|
|
6
6
|
export function generateXbarPlugin() {
|
|
7
7
|
const pyrePath = process.argv[1];
|
|
8
8
|
const nodePath = process.execPath;
|
|
9
|
-
|
|
9
|
+
|
|
10
10
|
const script = `#!/bin/bash
|
|
11
11
|
# <xbar.title>Pyre Monitor</xbar.title>
|
|
12
12
|
# <xbar.version>v1.0</xbar.version>
|
|
13
13
|
# <xbar.author>somalip</xbar.author>
|
|
14
14
|
# <xbar.author.github>somalip</xbar.author.github>
|
|
15
|
-
# <xbar.desc>
|
|
15
|
+
# <xbar.desc>Cross-platform system monitoring powered by pyre.</xbar.desc>
|
|
16
16
|
|
|
17
17
|
# Run pyre to get a JSON snapshot
|
|
18
|
-
# We use node directly to avoid env issues in xbar
|
|
19
18
|
DATA=$("${nodePath}" "${pyrePath}" --once --json)
|
|
20
19
|
|
|
21
20
|
if [ -z "$DATA" ]; then
|
|
@@ -39,15 +38,27 @@ echo "---"
|
|
|
39
38
|
echo "Open Dashboard | bash='${nodePath}' param1='${pyrePath}' param2='live' terminal=true"
|
|
40
39
|
`;
|
|
41
40
|
|
|
42
|
-
const pluginDir = path.join(os.homedir(), 'Library', 'Application Support', 'xbar', 'plugins');
|
|
43
41
|
const filename = 'pyre-monitor.2s.sh';
|
|
44
42
|
const outPath = path.join(process.cwd(), filename);
|
|
45
|
-
|
|
43
|
+
|
|
46
44
|
fs.writeFileSync(outPath, script);
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
45
|
+
try {
|
|
46
|
+
fs.chmodSync(outPath, 0o755);
|
|
47
|
+
} catch {
|
|
48
|
+
// ignore on non-POSIX filesystems
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
console.log(chalk.green(`Generated menu bar plugin script at ${outPath}`));
|
|
52
|
+
|
|
53
|
+
if (process.platform === 'darwin') {
|
|
54
|
+
const pluginDir = path.join(os.homedir(), 'Library', 'Application Support', 'xbar', 'plugins');
|
|
55
|
+
console.log(`To install in xbar or SwiftBar on macOS:`);
|
|
56
|
+
console.log(chalk.cyan(` mv ${filename} "${pluginDir}/"`));
|
|
57
|
+
} else if (process.platform === 'linux') {
|
|
58
|
+
const argosDir = path.join(os.homedir(), '.config', 'argos');
|
|
59
|
+
console.log(`To install in Argos (GNOME Shell) on Linux:`);
|
|
60
|
+
console.log(chalk.cyan(` mkdir -p "${argosDir}" && mv ${filename} "${argosDir}/"`));
|
|
61
|
+
} else {
|
|
62
|
+
console.log(chalk.dim(`Compatible with BitBar, xbar, and Argos shell plugins.`));
|
|
63
|
+
}
|
|
53
64
|
}
|
|
@@ -1,74 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
run
|
|
3
|
-
} from "./chunk-FH5WDJBF.js";
|
|
4
|
-
|
|
5
|
-
// src/brewHealth.ts
|
|
6
|
-
import chalk from "chalk";
|
|
7
|
-
async function getBrewHealth() {
|
|
8
|
-
try {
|
|
9
|
-
const brewPath = await run("which brew 2>&1", "");
|
|
10
|
-
if (!brewPath.trim() || brewPath.includes("not found")) {
|
|
11
|
-
return { installedCount: 0, outdatedCount: 0, cellarSize: "N/A", doctorWarnings: [], brewAvailable: false };
|
|
12
|
-
}
|
|
13
|
-
const outdatedRaw = await run("brew outdated --quiet 2>&1", "");
|
|
14
|
-
const outdatedLines = outdatedRaw.trim().split("\n").filter((l) => l.length > 0 && !l.startsWith("Homebrew") && !l.startsWith("==>"));
|
|
15
|
-
const listRaw = await run("brew list --formula -1 2>&1", "");
|
|
16
|
-
const listLines = listRaw.trim().split("\n").filter((l) => l.length > 0);
|
|
17
|
-
let cellarSize = "N/A";
|
|
18
|
-
try {
|
|
19
|
-
const cellarPath = await run("brew --cellar 2>&1", "");
|
|
20
|
-
if (cellarPath.trim()) {
|
|
21
|
-
const duRaw = await run(`du -sh "${cellarPath.trim()}" 2>&1`, "");
|
|
22
|
-
const duMatch = duRaw.match(/^([0-9\.\,]+[KMGTP]?i?B?)/i);
|
|
23
|
-
if (duMatch) cellarSize = duMatch[1];
|
|
24
|
-
}
|
|
25
|
-
} catch {
|
|
26
|
-
cellarSize = "N/A";
|
|
27
|
-
}
|
|
28
|
-
const doctorRaw = await run("brew doctor 2>&1", "");
|
|
29
|
-
const doctorWarnings = [];
|
|
30
|
-
const docLines = doctorRaw.split("\n");
|
|
31
|
-
for (const line of docLines) {
|
|
32
|
-
if (line.startsWith("Warning:")) {
|
|
33
|
-
doctorWarnings.push(line.replace(/^Warning:\s*/, "").trim());
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
return {
|
|
37
|
-
installedCount: listLines.length,
|
|
38
|
-
outdatedCount: outdatedLines.length,
|
|
39
|
-
cellarSize,
|
|
40
|
-
doctorWarnings,
|
|
41
|
-
brewAvailable: true
|
|
42
|
-
};
|
|
43
|
-
} catch (err) {
|
|
44
|
-
return { installedCount: 0, outdatedCount: 0, cellarSize: "N/A", doctorWarnings: [], brewAvailable: false };
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
async function printBrewHealthReport() {
|
|
48
|
-
console.log(chalk.bold("\n pyre brew \u2014 Homebrew Health Summary\n"));
|
|
49
|
-
const health = await getBrewHealth();
|
|
50
|
-
if (!health.brewAvailable) {
|
|
51
|
-
console.log(chalk.yellow(" \u26A0 Homebrew is not installed or not available on PATH.\n"));
|
|
52
|
-
return;
|
|
53
|
-
}
|
|
54
|
-
console.log(` \u{1F4E6} Installed Formulae: ${chalk.bold(health.installedCount)}`);
|
|
55
|
-
console.log(` \u23F3 Outdated Packages: ${health.outdatedCount > 0 ? chalk.yellow.bold(health.outdatedCount) : chalk.green("0 (Up to date)")}`);
|
|
56
|
-
console.log(` \u{1F4BE} Cellar Disk Usage: ${chalk.bold(health.cellarSize)}`);
|
|
57
|
-
console.log();
|
|
58
|
-
if (health.doctorWarnings.length === 0) {
|
|
59
|
-
console.log(chalk.green(" \u2714 brew doctor: No warnings detected system-wide."));
|
|
60
|
-
} else {
|
|
61
|
-
console.log(chalk.yellow(` \u26A0 brew doctor warnings (${health.doctorWarnings.length}):`));
|
|
62
|
-
for (const warn of health.doctorWarnings.slice(0, 5)) {
|
|
63
|
-
console.log(chalk.dim(` \u2022 ${warn}`));
|
|
64
|
-
}
|
|
65
|
-
if (health.doctorWarnings.length > 5) {
|
|
66
|
-
console.log(chalk.dim(` ... and ${health.doctorWarnings.length - 5} more.`));
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
console.log();
|
|
70
|
-
}
|
|
71
|
-
export {
|
|
72
|
-
getBrewHealth,
|
|
73
|
-
printBrewHealthReport
|
|
74
|
-
};
|
package/dist/chunk-FH5WDJBF.js
DELETED
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
// src/monitors/run.ts
|
|
2
|
-
import { exec } from "child_process";
|
|
3
|
-
import { promisify } from "util";
|
|
4
|
-
var execAsync = promisify(exec);
|
|
5
|
-
async function run(cmd, fallback = "", timeout = 3e3) {
|
|
6
|
-
try {
|
|
7
|
-
return (await execAsync(cmd, { encoding: "utf8", timeout })).stdout.trim();
|
|
8
|
-
} catch {
|
|
9
|
-
return fallback;
|
|
10
|
-
}
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
export {
|
|
14
|
-
run
|
|
15
|
-
};
|