pyre-cli 9.5.2 → 10.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.
Files changed (86) hide show
  1. package/README.md +73 -16
  2. package/dist/alertChannels-TPSQIJ7S.js +8 -0
  3. package/dist/{blender-7UT5J7IP.js → blender-FGH3ASEQ.js} +2 -2
  4. package/dist/brewHealth-P2GW5Y5C.js +176 -0
  5. package/dist/buildCmd-CDPZ2ZFA.js +38 -0
  6. package/dist/{checkCmd-T7O4KXXA.js → checkCmd-RKW6QGDR.js} +9 -11
  7. package/dist/{chunk-CXL4GYGQ.js → chunk-53O2RGSL.js} +44 -17
  8. package/dist/{chunk-3TE7MJLS.js → chunk-6UHZP4QP.js} +36 -10
  9. package/dist/chunk-GHRDW646.js +2506 -0
  10. package/dist/{prometheus-LFYHF6VO.js → chunk-HT4VQ4OH.js} +1 -0
  11. package/dist/chunk-M73HCQD2.js +95 -0
  12. package/dist/chunk-MZO5QKUR.js +32 -0
  13. package/dist/{chunk-25I533OF.js → chunk-VIACN2RU.js} +1 -1
  14. package/dist/chunk-Z2YV5HKV.js +87 -0
  15. package/dist/chunk-ZLVIVFSO.js +110 -0
  16. package/dist/{collectors-JB4OGUEF.js → collectors-H43PN4PS.js} +6 -3
  17. package/dist/{completions-VQMHQCXE.js → completions-JKYEJNGR.js} +34 -1
  18. package/dist/{config-KS5ZZ3VN.js → config-GYGJXU2Q.js} +9 -1
  19. package/dist/doctor-GYHFTNZQ.js +387 -0
  20. package/dist/explainCmd-MF6PIMLW.js +222 -0
  21. package/dist/extensions-XJGHG7X3.js +134 -0
  22. package/dist/index.js +460 -88
  23. package/dist/ioreport.py +72 -0
  24. package/dist/netUsageCmd-WKBTW2YG.js +90 -0
  25. package/dist/{pipeCmd-TYLJHQ5B.js → pipeCmd-7REDBLBU.js} +4 -3
  26. package/dist/profileProcCmd-N4H6MCBT.js +107 -0
  27. package/dist/prometheus-5BL5PVLC.js +6 -0
  28. package/dist/prometheusCmd-PL64BLN5.js +93 -0
  29. package/dist/replayCmd-Z3PYXY7V.js +164 -0
  30. package/dist/run-HOGQDDTA.js +8 -0
  31. package/dist/serveCmd-2H5VLF3P.js +153 -0
  32. package/dist/service-Q74BBILO.js +181 -0
  33. package/dist/smartCmd-ODWKSFNG.js +166 -0
  34. package/dist/syncCmd-A2W3QB3S.js +126 -0
  35. package/dist/topoCmd-DU2HHZNH.js +148 -0
  36. package/dist/watchdogCmd-UF53JPZB.js +161 -0
  37. package/dist/{wizard-Z3RGA3VB.js → wizard-TD7BGX6O.js} +1 -1
  38. package/install.ps1 +29 -0
  39. package/install.sh +10 -9
  40. package/package.json +7 -3
  41. package/src/ai/models.ts +138 -0
  42. package/src/alertChannels.ts +119 -0
  43. package/src/brewHealth.ts +157 -40
  44. package/src/buildCmd.ts +48 -0
  45. package/src/checkCmd.ts +5 -5
  46. package/src/completions.ts +35 -0
  47. package/src/doctor.ts +235 -7
  48. package/src/easy_features.test.ts +40 -0
  49. package/src/explainCmd.ts +261 -0
  50. package/src/extensions.ts +71 -7
  51. package/src/formatters/render.ts +34 -10
  52. package/src/formatters/types.ts +2 -0
  53. package/src/index.ts +251 -36
  54. package/src/live/input.ts +60 -0
  55. package/src/live/render.ts +67 -0
  56. package/src/live/state.ts +5 -0
  57. package/src/live/types.ts +1 -1
  58. package/src/monitors/batteryPredictor.ts +143 -0
  59. package/src/monitors/buildTracker.ts +121 -0
  60. package/src/monitors/collectors.ts +342 -178
  61. package/src/monitors/ioreport.py +72 -0
  62. package/src/monitors/platform/linux.ts +756 -0
  63. package/src/monitors/platform/windows.ts +519 -0
  64. package/src/monitors/run.ts +27 -3
  65. package/src/monitors/smc.ts +21 -1
  66. package/src/monitors/types.ts +15 -0
  67. package/src/netUsageCmd.ts +121 -0
  68. package/src/platform.test.ts +99 -0
  69. package/src/plugins/index.ts +143 -0
  70. package/src/profileProcCmd.ts +133 -0
  71. package/src/prometheusCmd.ts +107 -0
  72. package/src/replayCmd.ts +186 -0
  73. package/src/serveCmd.ts +180 -0
  74. package/src/service.ts +125 -7
  75. package/src/smartCmd.ts +205 -0
  76. package/src/state/config.ts +58 -17
  77. package/src/syncCmd.ts +166 -0
  78. package/src/topoCmd.ts +176 -0
  79. package/src/watchdogCmd.ts +198 -0
  80. package/src/xbar.ts +22 -11
  81. package/dist/brewHealth-F2BXF5M6.js +0 -74
  82. package/dist/chunk-FH5WDJBF.js +0 -15
  83. package/dist/chunk-N4WJVF5M.js +0 -1184
  84. package/dist/doctor-UV7TWIHX.js +0 -184
  85. package/dist/extensions-DVA5YLGH.js +0 -74
  86. package/dist/service-WTS3NBQU.js +0 -73
@@ -0,0 +1,143 @@
1
+ /**
2
+ * Smart Battery Predictor.
3
+ *
4
+ * Predicts multi-scenario battery longevity by synthesizing:
5
+ * 1. Current instantaneous discharge rate and state of charge.
6
+ * 2. Historical discharge profiles parsed from local CSV log exports.
7
+ * 3. Machine load heuristics (idle vs. current compute vs. sustained high-power).
8
+ */
9
+ import fs from 'node:fs';
10
+ import path from 'node:path';
11
+ import type { BatteryData, PowerData } from './types.js';
12
+
13
+ export interface BatteryPredictionScenario {
14
+ label: string;
15
+ ratePerHour: number;
16
+ timeRemaining: string;
17
+ hours: number;
18
+ }
19
+
20
+ export interface SmartBatteryPrediction {
21
+ currentLevel: number;
22
+ healthPercentage?: number;
23
+ cycleCount?: number;
24
+ powerWatts?: number;
25
+ scenarios: {
26
+ idle: BatteryPredictionScenario;
27
+ current: BatteryPredictionScenario;
28
+ heavy: BatteryPredictionScenario;
29
+ };
30
+ recommendation: string;
31
+ confidence: 'low' | 'medium' | 'high';
32
+ }
33
+
34
+ function formatHours(h: number): string {
35
+ if (!isFinite(h) || h <= 0) return 'calculating';
36
+ const hours = Math.floor(h);
37
+ const mins = Math.round((h - hours) * 60);
38
+ if (hours === 0 && mins === 0) return '< 1m';
39
+ if (hours === 0) return `${mins}m`;
40
+ return `${hours}h ${mins}m`;
41
+ }
42
+
43
+ export function computeSmartBatteryPrediction(
44
+ battery: BatteryData | null,
45
+ power: PowerData | null,
46
+ logDir: string = './pyre-exports'
47
+ ): SmartBatteryPrediction | null {
48
+ if (!battery) return null;
49
+
50
+ const level = battery.level;
51
+ const isCharging = battery.state.toLowerCase().includes('charg');
52
+
53
+ // Baseline assumption for typical MacBook battery Wh capacity
54
+ const assumedCapacityWh = 58;
55
+
56
+ // 1. Current discharge rate in %/hour
57
+ let currentRate = battery.dischargeRatePerHour || 12; // default fallback 12%/h
58
+ if (battery.dischargeRatePerHour === undefined && power && power.combinedWatts) {
59
+ currentRate = (power.combinedWatts / assumedCapacityWh) * 100;
60
+ }
61
+ currentRate = Math.max(2, Math.min(60, currentRate));
62
+
63
+ // 2. Scan historical logs for typical average discharge rate if available
64
+ let historicalSamples: number[] = [];
65
+ try {
66
+ if (fs.existsSync(logDir)) {
67
+ const files = fs.readdirSync(logDir).filter(f => f.startsWith('pyre-') && f.endsWith('.csv')).slice(-3);
68
+ for (const file of files) {
69
+ const content = fs.readFileSync(path.join(logDir, file), 'utf-8');
70
+ const lines = content.split('\n').slice(1);
71
+ for (const line of lines) {
72
+ const parts = line.split(',');
73
+ if (parts.length >= 4) {
74
+ const cpu = parseFloat(parts[1]);
75
+ if (!isNaN(cpu)) {
76
+ // Estimate power based on CPU history
77
+ const estRate = 5 + (cpu / 100) * 20;
78
+ historicalSamples.push(estRate);
79
+ }
80
+ }
81
+ }
82
+ }
83
+ }
84
+ } catch {
85
+ // fallback
86
+ }
87
+
88
+ const confidence: 'low' | 'medium' | 'high' = isCharging
89
+ ? 'low'
90
+ : historicalSamples.length > 50
91
+ ? 'high'
92
+ : battery.dischargeRatePerHour ? 'medium' : 'low';
93
+
94
+ // Compute scenarios
95
+ // Idle load scenario (light browser/reading, ~5-7% per hour)
96
+ const idleRate = 6.0;
97
+ const idleHours = level / idleRate;
98
+
99
+ // Current load scenario
100
+ const currentHours = level / currentRate;
101
+
102
+ // Heavy load scenario (compiling, 3D render, gaming: ~25-35% per hour)
103
+ const heavyRate = Math.max(28.0, currentRate * 1.5);
104
+ const heavyHours = level / heavyRate;
105
+
106
+ let recommendation = 'Power consumption is normal.';
107
+ if (isCharging) {
108
+ recommendation = `Device is currently ${battery.state}. Full capacity health: ${battery.health || 'Good'}.`;
109
+ } else if (currentRate > 25) {
110
+ recommendation = 'High power drain detected. Reducing display brightness and closing heavy background processes can extend battery significantly.';
111
+ } else if (currentRate < 10) {
112
+ recommendation = 'Excellent power efficiency. Machine is running under low-drain conditions.';
113
+ }
114
+
115
+ return {
116
+ currentLevel: level,
117
+ healthPercentage: battery.maxCapacityPercent,
118
+ cycleCount: battery.cycles,
119
+ powerWatts: battery.powerWatts || power?.combinedWatts,
120
+ scenarios: {
121
+ idle: {
122
+ label: 'Light / Reading Load',
123
+ ratePerHour: idleRate,
124
+ timeRemaining: formatHours(idleHours),
125
+ hours: idleHours,
126
+ },
127
+ current: {
128
+ label: 'Current Activity',
129
+ ratePerHour: Math.round(currentRate * 10) / 10,
130
+ timeRemaining: isCharging ? 'Charging' : formatHours(currentHours),
131
+ hours: currentHours,
132
+ },
133
+ heavy: {
134
+ label: 'Sustained Heavy Compute',
135
+ ratePerHour: Math.round(heavyRate * 10) / 10,
136
+ timeRemaining: formatHours(heavyHours),
137
+ hours: heavyHours,
138
+ },
139
+ },
140
+ recommendation,
141
+ confidence,
142
+ };
143
+ }
@@ -0,0 +1,121 @@
1
+ /**
2
+ * Build System Tracker.
3
+ *
4
+ * Scans active processes for compiler invocations (xcodebuild, cargo, rustc,
5
+ * clang, swift-frontend, make, ninja, bazel, go build), tracking compiler
6
+ * parallelism, CPU/RAM usage, and estimated elapsed time.
7
+ */
8
+ import { run } from './run.js';
9
+
10
+ export interface ActiveBuild {
11
+ tool: 'xcodebuild' | 'cargo' | 'swift' | 'make' | 'ninja' | 'bazel' | 'go' | 'clang' | 'compiler';
12
+ rootPid: number;
13
+ command: string;
14
+ compilerProcesses: number;
15
+ totalCpu: number;
16
+ totalMem: number;
17
+ elapsedSec: number;
18
+ target?: string;
19
+ }
20
+
21
+ export async function collectBuilds(): Promise<ActiveBuild[]> {
22
+ try {
23
+ const raw = await run('ps -eo pid,ppid,pcpu,pmem,etime,command -r', '');
24
+ if (!raw) return [];
25
+
26
+ const lines = raw.split('\n').slice(1);
27
+ const builds: Map<string, ActiveBuild> = new Map();
28
+
29
+ const buildToolPatterns: { name: ActiveBuild['tool']; match: RegExp }[] = [
30
+ { name: 'xcodebuild', match: /xcodebuild/i },
31
+ { name: 'cargo', match: /\bcargo\s+(build|check|test|run)\b/i },
32
+ { name: 'swift', match: /\bswift\s+(build|test)\b/i },
33
+ { name: 'make', match: /\bmake\b/i },
34
+ { name: 'ninja', match: /\bninja\b/i },
35
+ { name: 'bazel', match: /\bbazel\b/i },
36
+ { name: 'go', match: /\bgo\s+(build|test|run)\b/i },
37
+ ];
38
+
39
+ const compilerMatch = /(clang|swift-frontend|rustc|go tool compile|gcc|g\+\+|ghc)/i;
40
+
41
+ // First pass: identify build roots
42
+ for (const line of lines) {
43
+ if (!line.trim()) continue;
44
+ const parts = line.trim().split(/\s+/);
45
+ if (parts.length < 6) continue;
46
+
47
+ const pid = parseInt(parts[0], 10);
48
+ const cpu = parseFloat(parts[2]) || 0;
49
+ const mem = parseFloat(parts[3]) || 0;
50
+ const etimeStr = parts[4];
51
+ const cmd = parts.slice(5).join(' ');
52
+
53
+ for (const pattern of buildToolPatterns) {
54
+ if (pattern.match.test(cmd)) {
55
+ let elapsedSec = 0;
56
+ const etimeParts = etimeStr.split(':').map(Number);
57
+ if (etimeParts.length === 2) elapsedSec = etimeParts[0] * 60 + etimeParts[1];
58
+ else if (etimeParts.length === 3) elapsedSec = etimeParts[0] * 3600 + etimeParts[1] * 60 + etimeParts[2];
59
+
60
+ builds.set(pattern.name, {
61
+ tool: pattern.name,
62
+ rootPid: pid,
63
+ command: cmd.slice(0, 80),
64
+ compilerProcesses: 1,
65
+ totalCpu: cpu,
66
+ totalMem: mem,
67
+ elapsedSec,
68
+ target: cmd.split(' ').slice(1, 4).join(' '),
69
+ });
70
+ break;
71
+ }
72
+ }
73
+ }
74
+
75
+ // Second pass: associate child compiler processes
76
+ for (const line of lines) {
77
+ if (!line.trim()) continue;
78
+ const parts = line.trim().split(/\s+/);
79
+ if (parts.length < 6) continue;
80
+
81
+ const cpu = parseFloat(parts[2]) || 0;
82
+ const mem = parseFloat(parts[3]) || 0;
83
+ const cmd = parts.slice(5).join(' ');
84
+
85
+ if (compilerMatch.test(cmd)) {
86
+ // If an active build was found, associate this compiler worker
87
+ if (builds.size > 0) {
88
+ const firstBuild = builds.values().next().value;
89
+ if (firstBuild) {
90
+ firstBuild.compilerProcesses += 1;
91
+ firstBuild.totalCpu += cpu;
92
+ firstBuild.totalMem += mem;
93
+ }
94
+ } else {
95
+ // Standalone compiler invocation
96
+ const key = 'compiler';
97
+ const existing = builds.get(key);
98
+ if (existing) {
99
+ existing.compilerProcesses += 1;
100
+ existing.totalCpu += cpu;
101
+ existing.totalMem += mem;
102
+ } else {
103
+ builds.set(key, {
104
+ tool: 'compiler',
105
+ rootPid: parseInt(parts[0], 10),
106
+ command: cmd.slice(0, 80),
107
+ compilerProcesses: 1,
108
+ totalCpu: cpu,
109
+ totalMem: mem,
110
+ elapsedSec: 0,
111
+ });
112
+ }
113
+ }
114
+ }
115
+ }
116
+
117
+ return Array.from(builds.values());
118
+ } catch {
119
+ return [];
120
+ }
121
+ }