pyre-cli 10.3.0 → 10.5.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 (88) hide show
  1. package/README.md +41 -0
  2. package/dist/{alertChannels-TPSQIJ7S.js → alertChannels-MNX4XH6J.js} +1 -0
  3. package/dist/{anomaliesCmd-25OFKYPK.js → anomaliesCmd-HHTY5LYL.js} +2 -0
  4. package/dist/benchGitCmd-HIXUC5EK.js +87 -0
  5. package/dist/{benchmarkCmd-A3ETK6VY.js → benchmarkCmd-B7DLP2VC.js} +2 -0
  6. package/dist/{blender-FGH3ASEQ.js → blender-6ZX5SPYC.js} +3 -1
  7. package/dist/{brewHealth-P2GW5Y5C.js → brewHealth-VFW33QB3.js} +1 -0
  8. package/dist/budgetCmd-TGO3RYLN.js +11 -0
  9. package/dist/{buildCmd-CDPZ2ZFA.js → buildCmd-E7KUCFYG.js} +3 -1
  10. package/dist/{checkCmd-WQAHAUWO.js → checkCmd-QLYTP77Y.js} +5 -3
  11. package/dist/chunk-3RG5ZIWI.js +10 -0
  12. package/dist/{chunk-VIACN2RU.js → chunk-FYCBGUTW.js} +41 -19
  13. package/dist/chunk-JH7P6KLN.js +143 -0
  14. package/dist/{chunk-QM5L43EK.js → chunk-LDJB5V4N.js} +5 -1
  15. package/dist/chunk-NMGQVRCA.js +111 -0
  16. package/dist/chunk-OCL7P7N7.js +936 -0
  17. package/dist/{chunk-23YWCI3O.js → chunk-QEH4LR6P.js} +28 -686
  18. package/dist/{chunk-KVUMOA6C.js → chunk-RKPGPVTO.js} +77 -4
  19. package/dist/chunk-UF3XQ3R3.js +3800 -0
  20. package/dist/{collectors-JDN5Y7EV.js → collectors-V7SCIIDH.js} +5 -3
  21. package/dist/{completions-ZVTNE52B.js → completions-FTPXDSR2.js} +44 -3
  22. package/dist/{config-J4YMADEF.js → config-5WW5M63G.js} +2 -1
  23. package/dist/containersCmd-FSMYOBG2.js +84 -0
  24. package/dist/{doctor-LHFW4UJP.js → doctor-O4DIAMHK.js} +3 -2
  25. package/dist/{explainCmd-MF6PIMLW.js → explainCmd-7PBPA7O5.js} +1 -0
  26. package/dist/{extensions-XJGHG7X3.js → extensions-QQEV7U3D.js} +1 -0
  27. package/dist/{firebaseSync-ON3RZ6KX.js → firebaseSync-LRN67UTV.js} +2 -0
  28. package/dist/flightRecorder-GJIAQOXC.js +162 -0
  29. package/dist/index.js +736 -4125
  30. package/dist/inspectCmd-5FXJBJTK.js +137 -0
  31. package/dist/menu-AJFGDLBP.js +1233 -0
  32. package/dist/monitors/platform/windows-ui.ps1 +31 -29
  33. package/dist/{netUsageCmd-67IBZZYN.js → netUsageCmd-JP6YKBPF.js} +7 -5
  34. package/dist/optimizeCmd-WZKLFYZU.js +1110 -0
  35. package/dist/{pipeCmd-2N4JPKYE.js → pipeCmd-CPK6FVKB.js} +5 -3
  36. package/dist/playbookCmd-FRROIEXR.js +145 -0
  37. package/dist/{profileProcCmd-N4H6MCBT.js → profileProcCmd-5Y3733E7.js} +64 -13
  38. package/dist/{prometheus-5BL5PVLC.js → prometheus-CYNUR3QT.js} +1 -0
  39. package/dist/{prometheusCmd-LEUM5WCZ.js → prometheusCmd-G2CSEZRQ.js} +5 -3
  40. package/dist/{replayCmd-Z3PYXY7V.js → replayCmd-ODB5SPOQ.js} +25 -6
  41. package/dist/{run-HOGQDDTA.js → run-UJQYT2TO.js} +1 -0
  42. package/dist/{serveCmd-L7LVJOZN.js → serveCmd-KDPWLVQI.js} +5 -3
  43. package/dist/{service-7GIX3YNC.js → service-LIYYR3UI.js} +1 -0
  44. package/dist/{smartCmd-ODWKSFNG.js → smartCmd-2BJJ37GV.js} +130 -5
  45. package/dist/statuslineCmd-EUKYRR2G.js +75 -0
  46. package/dist/{stressCmd-MFXMFXYX.js → stressCmd-GKHGY26X.js} +2 -0
  47. package/dist/{syncCmd-42IRF633.js → syncCmd-MIBFKX24.js} +16 -5
  48. package/dist/topoCmd-RTXQJ6XA.js +189 -0
  49. package/dist/{updateCheck-52X6LJG5.js → updateCheck-LJHEMG3G.js} +2 -0
  50. package/dist/{watchdogCmd-6GR4UN6B.js → watchdogCmd-XM6OPTKM.js} +41 -6
  51. package/dist/{wizard-JQMQWFAW.js → wizard-PRDOJROQ.js} +2 -1
  52. package/package.json +2 -2
  53. package/src/benchGitCmd.ts +110 -0
  54. package/src/budgetCmd.ts +199 -0
  55. package/src/completions.ts +42 -3
  56. package/src/containersCmd.ts +106 -0
  57. package/src/doctor.ts +86 -6
  58. package/src/easy_features.test.ts +83 -0
  59. package/src/flightRecorder.ts +214 -0
  60. package/src/index.ts +181 -8
  61. package/src/inspectCmd.ts +165 -0
  62. package/src/live/input.ts +70 -3
  63. package/src/live/render.ts +1 -1
  64. package/src/live/state.ts +2 -1
  65. package/src/menu/commands.ts +754 -0
  66. package/src/menu/index.ts +358 -0
  67. package/src/menu/render.ts +272 -0
  68. package/src/menu/types.ts +63 -0
  69. package/src/menu.test.ts +110 -0
  70. package/src/monitors/blender.ts +49 -19
  71. package/src/monitors/buildTracker.ts +72 -54
  72. package/src/monitors/platform/windows-ui.ps1 +31 -29
  73. package/src/monitors/platform/windows.ts +636 -280
  74. package/src/optimizeCmd.ts +1248 -0
  75. package/src/platform.test.ts +146 -0
  76. package/src/playbookCmd.ts +156 -0
  77. package/src/power_features.test.ts +251 -0
  78. package/src/profileProcCmd.ts +68 -21
  79. package/src/replayCmd.ts +15 -6
  80. package/src/smartCmd.ts +149 -10
  81. package/src/state/config.ts +13 -0
  82. package/src/statuslineCmd.ts +87 -0
  83. package/src/syncCmd.ts +12 -0
  84. package/src/topoCmd.ts +83 -50
  85. package/src/watchdogCmd.ts +40 -3
  86. package/src/xbar.ts +195 -17
  87. package/dist/chunk-M73HCQD2.js +0 -95
  88. package/dist/topoCmd-DZ3YS5IL.js +0 -148
@@ -1,10 +1,12 @@
1
1
  import "./chunk-IM3IQMMT.js";
2
2
  import {
3
3
  collectAll
4
- } from "./chunk-23YWCI3O.js";
5
- import "./chunk-M73HCQD2.js";
6
- import "./chunk-VIACN2RU.js";
4
+ } from "./chunk-QEH4LR6P.js";
5
+ import "./chunk-NMGQVRCA.js";
6
+ import "./chunk-FYCBGUTW.js";
7
+ import "./chunk-OCL7P7N7.js";
7
8
  import "./chunk-MZO5QKUR.js";
9
+ import "./chunk-3RG5ZIWI.js";
8
10
 
9
11
  // src/pipeCmd.ts
10
12
  async function runPipeCommand(opts = {}) {
@@ -0,0 +1,145 @@
1
+ import {
2
+ getConfigDir
3
+ } from "./chunk-LDJB5V4N.js";
4
+ import "./chunk-3RG5ZIWI.js";
5
+
6
+ // src/playbookCmd.ts
7
+ import fs from "fs";
8
+ import path from "path";
9
+ import { spawnSync } from "child_process";
10
+ import chalk from "chalk";
11
+ var BUILTIN_PLAYBOOKS = [
12
+ {
13
+ id: "audit",
14
+ name: "Full System Health Audit",
15
+ description: "Run health check, diagnostic doctor, drive S.M.A.R.T., and package manager audit",
16
+ category: "audit",
17
+ steps: [
18
+ { name: "System Health Check", command: "check" },
19
+ { name: "Doctor Diagnostics", command: "doctor" },
20
+ { name: "Drive S.M.A.R.T. Health", command: "smart", allowFailure: true },
21
+ { name: "Package Manager Health", command: "brew", allowFailure: true }
22
+ ]
23
+ },
24
+ {
25
+ id: "clean",
26
+ name: "Complete Mac Maintenance & Cleanup",
27
+ description: "Quit long-idle background apps, purge inactive memory, clean caches, flush DNS",
28
+ category: "maintenance",
29
+ steps: [
30
+ { name: "Quit Idle Apps", command: "optimize apps --idle 2h -y" },
31
+ { name: "Purge Inactive Memory", command: "optimize memory -y" },
32
+ { name: "Clean Application Caches", command: "optimize caches --clean -y" },
33
+ { name: "Flush DNS Resolver Cache", command: "optimize dns -y" }
34
+ ]
35
+ },
36
+ {
37
+ id: "triage",
38
+ name: "Performance Spike & Incident Triage",
39
+ description: "Detect historical anomalies, inspect active network usage, and audit drivers",
40
+ category: "triage",
41
+ steps: [
42
+ { name: "Z-Score Anomaly Digest", command: "anomalies --since 1d" },
43
+ { name: "Per-Application Network Usage", command: "netusage --top 10" },
44
+ { name: "System Extensions Audit", command: "extensions", allowFailure: true }
45
+ ]
46
+ },
47
+ {
48
+ id: "bench",
49
+ name: "Quick Compute & Storage Baseline",
50
+ description: "Execute CPU Pi benchmark and query physical disk health",
51
+ category: "bench",
52
+ steps: [
53
+ { name: "CPU Pi Benchmark", command: "benchmark" },
54
+ { name: "Physical Disk Health", command: "smart", allowFailure: true }
55
+ ]
56
+ }
57
+ ];
58
+ function getCustomPlaybooks() {
59
+ const filePath = path.join(getConfigDir(), "playbooks.json");
60
+ if (!fs.existsSync(filePath)) return [];
61
+ try {
62
+ const raw = fs.readFileSync(filePath, "utf-8");
63
+ const parsed = JSON.parse(raw);
64
+ return Array.isArray(parsed) ? parsed : [];
65
+ } catch {
66
+ return [];
67
+ }
68
+ }
69
+ function getAllPlaybooks() {
70
+ return [...BUILTIN_PLAYBOOKS, ...getCustomPlaybooks()];
71
+ }
72
+ async function runPlaybook(playbookId) {
73
+ const all = getAllPlaybooks();
74
+ const playbook = all.find((p) => p.id === playbookId || p.name.toLowerCase() === playbookId.toLowerCase());
75
+ if (!playbook) {
76
+ console.error(chalk.red(`
77
+ \u2716 Unknown playbook: '${playbookId}'`));
78
+ console.log(chalk.dim(` Available playbooks: ${all.map((p) => p.id).join(", ")}
79
+ `));
80
+ return false;
81
+ }
82
+ console.log(chalk.bold(`
83
+ \u{1F525} pyre playbook: ${chalk.hex("#ff6a39")(playbook.name)}`));
84
+ console.log(chalk.dim(` ${playbook.description}`));
85
+ console.log(chalk.dim(` Steps (${playbook.steps.length}):`));
86
+ playbook.steps.forEach((step, idx) => {
87
+ console.log(chalk.dim(` ${idx + 1}. ${step.name} (pyre ${step.command})`));
88
+ });
89
+ console.log(chalk.dim(" \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n"));
90
+ const scriptPath = process.argv[1];
91
+ const startTime = Date.now();
92
+ let stepIndex = 1;
93
+ let allSuccess = true;
94
+ for (const step of playbook.steps) {
95
+ console.log(chalk.bold.cyan(`
96
+ \u25B6 [${stepIndex}/${playbook.steps.length}] ${step.name} ...`));
97
+ console.log(chalk.dim(` $ pyre ${step.command}
98
+ `));
99
+ const tokens = step.command.trim().split(/\s+/).filter(Boolean);
100
+ const result = spawnSync(process.argv[0], [scriptPath, ...tokens], {
101
+ stdio: "inherit",
102
+ env: process.env
103
+ });
104
+ if (result.status !== 0 && !step.allowFailure) {
105
+ console.log(chalk.red(`
106
+ \u2716 Step '${step.name}' failed with exit code ${result.status}`));
107
+ allSuccess = false;
108
+ break;
109
+ } else if (result.status !== 0 && step.allowFailure) {
110
+ console.log(chalk.yellow(`
111
+ \u26A0 Step '${step.name}' failed but marked as optional \u2014 continuing...`));
112
+ } else {
113
+ console.log(chalk.green(`
114
+ \u2714 Step '${step.name}' completed.`));
115
+ }
116
+ stepIndex++;
117
+ }
118
+ const durationSec = ((Date.now() - startTime) / 1e3).toFixed(1);
119
+ console.log(chalk.dim("\n \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"));
120
+ if (allSuccess) {
121
+ console.log(chalk.bold.green(` \u2714 Playbook '${playbook.name}' completed successfully in ${durationSec}s
122
+ `));
123
+ } else {
124
+ console.log(chalk.bold.red(` \u2716 Playbook '${playbook.name}' aborted after ${durationSec}s
125
+ `));
126
+ }
127
+ return allSuccess;
128
+ }
129
+ function listPlaybooks() {
130
+ const all = getAllPlaybooks();
131
+ console.log(chalk.bold("\n \u{1F525} pyre Playbooks & Macro Recipes:\n"));
132
+ for (const p of all) {
133
+ console.log(` \u2022 ${chalk.bold.hex("#ff6a39")(p.id.padEnd(12))} ${p.name}`);
134
+ console.log(chalk.dim(` ${p.description}`));
135
+ console.log(chalk.dim(` Steps: ${p.steps.map((s) => s.command).join(" \u2794 ")}
136
+ `));
137
+ }
138
+ }
139
+ export {
140
+ BUILTIN_PLAYBOOKS,
141
+ getAllPlaybooks,
142
+ getCustomPlaybooks,
143
+ listPlaybooks,
144
+ runPlaybook
145
+ };
@@ -1,5 +1,10 @@
1
+ import {
2
+ runPowerShell
3
+ } from "./chunk-MZO5QKUR.js";
4
+ import "./chunk-3RG5ZIWI.js";
5
+
1
6
  // src/profileProcCmd.ts
2
- import { execFile } from "child_process";
7
+ import { execFile, execSync } from "child_process";
3
8
  import { promisify } from "util";
4
9
  import chalk from "chalk";
5
10
  var execFileAsync = promisify(execFile);
@@ -9,9 +14,20 @@ async function runProfileProcCommand(opts) {
9
14
  console.error(chalk.red("\n \u2716 Error: Valid PID is required. Usage: pyre profile-proc <pid> [--duration <sec>]\n"));
10
15
  process.exit(1);
11
16
  }
17
+ let processAlive = false;
12
18
  try {
13
19
  process.kill(pid, 0);
20
+ processAlive = true;
14
21
  } catch {
22
+ if (process.platform === "win32") {
23
+ try {
24
+ const out = execSync(`tasklist /fi "PID eq ${pid}" /nh`, { stdio: "pipe" }).toString();
25
+ processAlive = out.includes(String(pid));
26
+ } catch {
27
+ }
28
+ }
29
+ }
30
+ if (!processAlive) {
15
31
  console.error(chalk.red(`
16
32
  \u2716 Error: Process with PID ${pid} is not running or accessible.
17
33
  `));
@@ -22,7 +38,38 @@ async function runProfileProcCommand(opts) {
22
38
  `));
23
39
  let sampleOutput = "";
24
40
  let usedFallback = false;
25
- if (process.platform === "darwin") {
41
+ if (process.platform === "win32") {
42
+ try {
43
+ const psScript = `
44
+ $p1 = Get-Process -Id ${pid} -ErrorAction SilentlyContinue
45
+ if (-not $p1) { exit 1 }
46
+ $cpu1 = $p1.TotalProcessorTime.TotalSeconds
47
+ $start = Get-Date
48
+ Start-Sleep -Seconds ${durationSec}
49
+ $p2 = Get-Process -Id ${pid} -ErrorAction SilentlyContinue
50
+ $cpu2 = if ($p2) { $p2.TotalProcessorTime.TotalSeconds } else { $cpu1 }
51
+ $elapsed = ((Get-Date) - $start).TotalSeconds
52
+ $cpuPct = if ($elapsed -gt 0) { [math]::Round((($cpu2 - $cpu1) / $elapsed) * 100, 1) } else { 0 }
53
+
54
+ Write-Output "Process: $($p1.ProcessName) (PID $($p1.Id))"
55
+ Write-Output "Path: $($p1.Path)"
56
+ Write-Output "Average CPU Utilization: $cpuPct%"
57
+ Write-Output "Working Set (RAM): $([math]::Round($p1.WorkingSet64 / 1MB, 1)) MB"
58
+ Write-Output "Threads Total: $($p1.Threads.Count)"
59
+ Write-Output ""
60
+ Write-Output "Call graph / Active Threads:"
61
+ $p1.Threads | Select-Object -First 25 | ForEach-Object {
62
+ $state = $_.ThreadState
63
+ $wait = $_.WaitReason
64
+ $time = [math]::Round($_.TotalProcessorTime.TotalSeconds, 3)
65
+ Write-Output " + [TID $($_.Id)] CPU: $($time)s | State: $state | WaitReason: $wait"
66
+ }
67
+ `;
68
+ sampleOutput = await runPowerShell(psScript, "", (durationSec + 8) * 1e3);
69
+ } catch {
70
+ }
71
+ }
72
+ if (!sampleOutput && process.platform === "darwin") {
26
73
  try {
27
74
  const { stdout } = await execFileAsync("sample", [String(pid), String(durationSec), "-file", "/dev/stdout"], {
28
75
  timeout: (durationSec + 5) * 1e3,
@@ -33,13 +80,17 @@ async function runProfileProcCommand(opts) {
33
80
  sampleOutput = err.stdout || "";
34
81
  }
35
82
  }
36
- if (!sampleOutput || sampleOutput.length < 100) {
83
+ if (!sampleOutput || sampleOutput.length < 50) {
37
84
  usedFallback = true;
38
- try {
39
- const { stdout } = await execFileAsync("ps", ["-M", "-p", String(pid), "-o", "pid,thread,pcpu,pmem,state,time,command"]);
40
- sampleOutput = stdout;
41
- } catch {
42
- sampleOutput = `Process PID ${pid} active. Deep stack sampling requires elevated permissions or user-owned process.`;
85
+ if (process.platform !== "win32") {
86
+ try {
87
+ const { stdout } = await execFileAsync("ps", ["-M", "-p", String(pid), "-o", "pid,thread,pcpu,pmem,state,time,command"]);
88
+ sampleOutput = stdout;
89
+ } catch {
90
+ sampleOutput = `Process PID ${pid} active. Deep stack sampling requires elevated permissions or user-owned process.`;
91
+ }
92
+ } else {
93
+ sampleOutput = `Process PID ${pid} active. Profiling finished.`;
43
94
  }
44
95
  }
45
96
  if (raw) {
@@ -52,10 +103,10 @@ async function runProfileProcCommand(opts) {
52
103
  const stackLines = [];
53
104
  let inCallGraph = false;
54
105
  for (const line of lines) {
55
- if (line.includes("Analysis of sampling") || line.includes("Process:") || line.includes("Path:") || line.includes("Identifier:")) {
106
+ if (line.includes("Analysis of sampling") || line.includes("Process:") || line.includes("Path:") || line.includes("Identifier:") || line.includes("Average CPU Utilization:") || line.includes("Working Set") || line.includes("Threads Total:")) {
56
107
  headerLines.push(line.trim());
57
108
  }
58
- if (line.includes("Call graph:") || line.includes("+ Line Coverage")) {
109
+ if (line.includes("Call graph:") || line.includes("Call graph / Active Threads:") || line.includes("+ Line Coverage")) {
59
110
  inCallGraph = true;
60
111
  continue;
61
112
  }
@@ -69,12 +120,12 @@ async function runProfileProcCommand(opts) {
69
120
  }
70
121
  if (headerLines.length > 0) {
71
122
  console.log(chalk.dim(" Process Info:"));
72
- for (const h of headerLines.slice(0, 4)) {
123
+ for (const h of headerLines.slice(0, 6)) {
73
124
  console.log(` ${chalk.cyan(h)}`);
74
125
  }
75
126
  console.log();
76
127
  }
77
- console.log(chalk.bold(" Top Call Stacks & Hot Functions:"));
128
+ console.log(chalk.bold(" Top Call Stacks & Hot Threads:"));
78
129
  console.log(chalk.dim(" " + "\u2500".repeat(70)));
79
130
  if (stackLines.length === 0) {
80
131
  for (const l of lines.slice(0, 20)) {
@@ -92,7 +143,7 @@ async function runProfileProcCommand(opts) {
92
143
  }
93
144
  }
94
145
  } else {
95
- console.log(chalk.yellow(" Note: Kernel/SIP restriction prevented deep call-graph unwind."));
146
+ console.log(chalk.yellow(" Note: Operating system permissions prevented deep call-graph unwind."));
96
147
  console.log(chalk.dim(" Showing process thread snapshot:\n"));
97
148
  for (const l of sampleOutput.split("\n")) {
98
149
  if (l.trim()) console.log(` ${l}`);
@@ -1,6 +1,7 @@
1
1
  import {
2
2
  formatPrometheusMetrics
3
3
  } from "./chunk-HT4VQ4OH.js";
4
+ import "./chunk-3RG5ZIWI.js";
4
5
  export {
5
6
  formatPrometheusMetrics
6
7
  };
@@ -4,10 +4,12 @@ import {
4
4
  import "./chunk-IM3IQMMT.js";
5
5
  import {
6
6
  collectAll
7
- } from "./chunk-23YWCI3O.js";
8
- import "./chunk-M73HCQD2.js";
9
- import "./chunk-VIACN2RU.js";
7
+ } from "./chunk-QEH4LR6P.js";
8
+ import "./chunk-NMGQVRCA.js";
9
+ import "./chunk-FYCBGUTW.js";
10
+ import "./chunk-OCL7P7N7.js";
10
11
  import "./chunk-MZO5QKUR.js";
12
+ import "./chunk-3RG5ZIWI.js";
11
13
 
12
14
  // src/prometheusCmd.ts
13
15
  import http from "http";
@@ -1,3 +1,5 @@
1
+ import "./chunk-3RG5ZIWI.js";
2
+
1
3
  // src/replayCmd.ts
2
4
  import fs from "fs";
3
5
  import readline from "readline";
@@ -65,14 +67,15 @@ function renderFrame(row, idx, total, speed, paused, cols) {
65
67
  }
66
68
  lines.push("");
67
69
  lines.push(" " + divider);
68
- const progWidth = 30;
70
+ const progWidth = Math.min(40, Math.max(20, cols - 30));
71
+ const pct = total > 1 ? idx / (total - 1) * 100 : 0;
69
72
  const progress = total > 1 ? Math.round(idx / (total - 1) * progWidth) : 0;
70
- const progressBar = chalk.cyan("\u2588".repeat(progress)) + chalk.dim("\u2591".repeat(progWidth - progress));
73
+ const progressBar = chalk.cyan("\u2501".repeat(progress)) + chalk.bold.yellow("\u25C6") + chalk.dim("\u2500".repeat(Math.max(0, progWidth - progress)));
71
74
  const icon = paused ? chalk.yellow("\u23F8") : chalk.green("\u25B6");
72
75
  const spStr = speed === 1 ? "1\xD7" : `${speed}\xD7`;
73
- lines.push(` ${icon} ${progressBar} ${chalk.bold(`${idx + 1}/${total}`)} ${chalk.dim(spStr)}`);
76
+ lines.push(` ${icon} [${progressBar}] ${chalk.bold(`${pct.toFixed(0)}%`)} (${idx + 1}/${total}) ${chalk.dim(spStr)}`);
74
77
  lines.push("");
75
- lines.push(chalk.dim(" Space/p=pause ]/[=speed \u2190/\u2192=step q=quit"));
78
+ lines.push(chalk.dim(" Space/p=pause ]/[=speed \u2190/\u2192=step 0-9=jump % Home/End=seek q=quit"));
76
79
  return lines;
77
80
  }
78
81
  async function runReplayCommand(opts) {
@@ -132,12 +135,28 @@ async function runReplayCommand(opts) {
132
135
  return;
133
136
  }
134
137
  if (key.name === "right") {
135
- frameIdx = Math.min(frameIdx + 1, rows.length - 1);
138
+ frameIdx = Math.min(frameIdx + (key.shift ? 10 : 1), rows.length - 1);
136
139
  renderCurrent();
137
140
  return;
138
141
  }
139
142
  if (key.name === "left") {
140
- frameIdx = Math.max(frameIdx - 1, 0);
143
+ frameIdx = Math.max(frameIdx - (key.shift ? 10 : 1), 0);
144
+ renderCurrent();
145
+ return;
146
+ }
147
+ if (key.name === "home" || str === "0") {
148
+ frameIdx = 0;
149
+ renderCurrent();
150
+ return;
151
+ }
152
+ if (key.name === "end") {
153
+ frameIdx = rows.length - 1;
154
+ renderCurrent();
155
+ return;
156
+ }
157
+ if (str >= "1" && str <= "9") {
158
+ const frac = parseInt(str, 10) / 10;
159
+ frameIdx = Math.min(rows.length - 1, Math.round(frac * (rows.length - 1)));
141
160
  renderCurrent();
142
161
  return;
143
162
  }
@@ -2,6 +2,7 @@ import {
2
2
  run,
3
3
  runPowerShell
4
4
  } from "./chunk-MZO5QKUR.js";
5
+ import "./chunk-3RG5ZIWI.js";
5
6
  export {
6
7
  run,
7
8
  runPowerShell
@@ -10,10 +10,12 @@ import {
10
10
  collectProcesses,
11
11
  collectSystem,
12
12
  collectThermal
13
- } from "./chunk-23YWCI3O.js";
14
- import "./chunk-M73HCQD2.js";
15
- import "./chunk-VIACN2RU.js";
13
+ } from "./chunk-QEH4LR6P.js";
14
+ import "./chunk-NMGQVRCA.js";
15
+ import "./chunk-FYCBGUTW.js";
16
+ import "./chunk-OCL7P7N7.js";
16
17
  import "./chunk-MZO5QKUR.js";
18
+ import "./chunk-3RG5ZIWI.js";
17
19
 
18
20
  // src/serveCmd.ts
19
21
  import http from "http";
@@ -6,6 +6,7 @@ import {
6
6
  uninstallLaunchdAgent,
7
7
  uninstallService
8
8
  } from "./chunk-KFPTD266.js";
9
+ import "./chunk-3RG5ZIWI.js";
9
10
  export {
10
11
  getServiceStatus,
11
12
  installLaunchdAgent,
@@ -1,3 +1,8 @@
1
+ import {
2
+ runPowerShell
3
+ } from "./chunk-MZO5QKUR.js";
4
+ import "./chunk-3RG5ZIWI.js";
5
+
1
6
  // src/smartCmd.ts
2
7
  import { execFile } from "child_process";
3
8
  import { promisify } from "util";
@@ -11,6 +16,62 @@ async function runCmd(cmd, args, timeoutMs = 5e3) {
11
16
  return "";
12
17
  }
13
18
  }
19
+ function parseWindowsPhysicalDiskCsv(csvRaw) {
20
+ const lines = csvRaw.split("\n").filter((l) => l.trim().length > 0);
21
+ if (lines.length < 2) return [];
22
+ const headers = lines[0].split(",").map((h) => h.trim().replace(/^"|"$/g, ""));
23
+ const disks = [];
24
+ for (const line of lines.slice(1)) {
25
+ const values = line.split(",").map((v) => v.trim().replace(/^"|"$/g, ""));
26
+ const row = {};
27
+ headers.forEach((h, i) => {
28
+ row[h] = values[i] || "";
29
+ });
30
+ const deviceId = row.DeviceId || row.DeviceID || "0";
31
+ const friendlyName = row.FriendlyName || row.Model || "Physical Disk";
32
+ const serialNumber = row.SerialNumber || "";
33
+ const mediaType = row.MediaType || row.InterfaceType || "";
34
+ const healthStatus = (row.HealthStatus || row.Status || "").toUpperCase();
35
+ const sizeBytes = parseFloat(row.Size) || 0;
36
+ let health = "Unknown";
37
+ if (healthStatus.includes("HEALTHY") || healthStatus.includes("OK") || healthStatus.includes("PASSED")) {
38
+ health = "PASSED";
39
+ } else if (healthStatus.includes("UNHEALTHY") || healthStatus.includes("ERROR") || healthStatus.includes("FAILED")) {
40
+ health = "FAILED";
41
+ }
42
+ const capacity = sizeBytes > 0 ? sizeBytes >= 1e12 ? `${(sizeBytes / 1e12).toFixed(1)} TB` : sizeBytes >= 1e9 ? `${(sizeBytes / 1e9).toFixed(0)} GB` : `${(sizeBytes / 1e6).toFixed(0)} MB` : void 0;
43
+ disks.push({
44
+ device: `\\\\.\\PhysicalDrive${deviceId}`,
45
+ model: friendlyName,
46
+ serialNumber,
47
+ health,
48
+ protocol: mediaType,
49
+ capacity
50
+ });
51
+ }
52
+ return disks;
53
+ }
54
+ function parseWindowsReliabilityCsv(csvRaw) {
55
+ const lines = csvRaw.split("\n").filter((l) => l.trim().length > 0);
56
+ if (lines.length < 2) return {};
57
+ const headers = lines[0].split(",").map((h) => h.trim().replace(/^"|"$/g, ""));
58
+ const values = lines[1].split(",").map((v) => v.trim().replace(/^"|"$/g, ""));
59
+ const row = {};
60
+ headers.forEach((h, i) => {
61
+ row[h] = values[i] || "";
62
+ });
63
+ const temp = parseFloat(row.Temperature);
64
+ const wear = parseFloat(row.Wear);
65
+ const poh = parseFloat(row.PowerOnHours);
66
+ const readErrors = parseFloat(row.ReadErrorsTotal);
67
+ const writeErrors = parseFloat(row.WriteErrorsTotal);
68
+ return {
69
+ tempC: Number.isFinite(temp) && temp > 0 && temp < 120 ? temp : void 0,
70
+ percentUsed: Number.isFinite(wear) && wear >= 0 && wear <= 100 ? wear : void 0,
71
+ powerOnHours: Number.isFinite(poh) && poh >= 0 ? poh : void 0,
72
+ reallocatedSectors: (Number.isFinite(readErrors) ? readErrors : 0) + (Number.isFinite(writeErrors) ? writeErrors : 0)
73
+ };
74
+ }
14
75
  async function getPhysicalDisks() {
15
76
  const scanRaw = await runCmd("smartctl", ["--scan", "--json"]);
16
77
  if (scanRaw) {
@@ -31,7 +92,18 @@ async function getPhysicalDisks() {
31
92
  return ["/dev/sda"];
32
93
  }
33
94
  if (process.platform === "win32") {
34
- return ["/dev/sda", "/dev/csmi0,0"];
95
+ try {
96
+ const raw2 = await runPowerShell(
97
+ `Get-PhysicalDisk -ErrorAction SilentlyContinue | Select-Object -ExpandProperty DeviceId`,
98
+ ""
99
+ );
100
+ const ids = raw2.split("\n").map((s) => s.trim()).filter(Boolean);
101
+ if (ids.length > 0) {
102
+ return ids.map((id) => `\\\\.\\PhysicalDrive${id}`);
103
+ }
104
+ } catch {
105
+ }
106
+ return ["\\\\.\\PhysicalDrive0"];
35
107
  }
36
108
  const raw = await runCmd("diskutil", ["list", "-plist"]);
37
109
  if (!raw) return ["/dev/disk0"];
@@ -88,6 +160,55 @@ async function collectSmartctlDisk(device) {
88
160
  return null;
89
161
  }
90
162
  }
163
+ async function collectWindowsDiskFallback(device) {
164
+ const match = device.match(/PhysicalDrive(\d+)/i);
165
+ const diskNumber = match ? match[1] : "0";
166
+ try {
167
+ const rawDisk = await runPowerShell(
168
+ `Get-PhysicalDisk -DeviceId '${diskNumber}' -ErrorAction SilentlyContinue | Select-Object DeviceId, FriendlyName, SerialNumber, MediaType, HealthStatus, Size | ConvertTo-Csv -NoTypeInformation`,
169
+ ""
170
+ );
171
+ const parsed = parseWindowsPhysicalDiskCsv(rawDisk);
172
+ if (parsed.length > 0) {
173
+ const info = parsed[0];
174
+ info.device = device;
175
+ try {
176
+ const rawReliability = await runPowerShell(
177
+ `Get-StorageReliabilityCounter -Disk (Get-Disk -Number ${diskNumber} -ErrorAction SilentlyContinue) -ErrorAction SilentlyContinue | Select-Object Temperature, Wear, PowerOnHours, ReadErrorsTotal, WriteErrorsTotal | ConvertTo-Csv -NoTypeInformation`,
178
+ ""
179
+ );
180
+ const rel = parseWindowsReliabilityCsv(rawReliability);
181
+ if (rel.tempC !== void 0) info.tempC = rel.tempC;
182
+ if (rel.percentUsed !== void 0) info.percentUsed = rel.percentUsed;
183
+ if (rel.powerOnHours !== void 0) info.powerOnHours = rel.powerOnHours;
184
+ if (rel.reallocatedSectors !== void 0) info.reallocatedSectors = rel.reallocatedSectors;
185
+ } catch {
186
+ }
187
+ return info;
188
+ }
189
+ } catch {
190
+ }
191
+ try {
192
+ const rawWmi = await runPowerShell(
193
+ `Get-CimInstance Win32_DiskDrive -Filter "Index = ${diskNumber}" -ErrorAction SilentlyContinue | Select-Object Model, SerialNumber, Status, Size | ConvertTo-Csv -NoTypeInformation`,
194
+ ""
195
+ );
196
+ const lines = rawWmi.split("\n").filter((l) => l.trim());
197
+ if (lines.length >= 2) {
198
+ const values = lines[1].split(",").map((s) => s.trim().replace(/^"|"$/g, ""));
199
+ const sizeBytes = parseFloat(values[3]) || 0;
200
+ return {
201
+ device,
202
+ model: values[0] || "Physical Disk",
203
+ serialNumber: values[1] || "",
204
+ health: values[2]?.toUpperCase().includes("OK") ? "PASSED" : "Unknown",
205
+ capacity: sizeBytes >= 1e12 ? `${(sizeBytes / 1e12).toFixed(1)} TB` : `${(sizeBytes / 1e9).toFixed(0)} GB`
206
+ };
207
+ }
208
+ } catch {
209
+ }
210
+ return null;
211
+ }
91
212
  async function collectDiskutilFallback(device) {
92
213
  const raw = await runCmd("diskutil", ["info", device]);
93
214
  if (!raw) return null;
@@ -118,8 +239,9 @@ async function runSmartCommand() {
118
239
  const smartctlVersion = await runCmd("smartctl", ["--version"], 2e3);
119
240
  const hasSmartctl = smartctlVersion.includes("smartmontools");
120
241
  if (!hasSmartctl) {
121
- console.log(chalk.yellow(" \u26A0 smartctl not found. Showing basic disk info."));
122
- console.log(chalk.dim(" For full SMART data: ") + chalk.cyan("brew install smartmontools") + "\n");
242
+ console.log(chalk.yellow(" \u26A0 smartctl not found. Showing native storage health metrics."));
243
+ const installHint = process.platform === "win32" ? "winget install smartmontools" : process.platform === "linux" ? "sudo apt install smartmontools" : "brew install smartmontools";
244
+ console.log(chalk.dim(" For full SMART data: ") + chalk.cyan(installHint) + "\n");
123
245
  }
124
246
  const devices = await getPhysicalDisks();
125
247
  if (devices.length === 0) {
@@ -129,7 +251,8 @@ async function runSmartCommand() {
129
251
  for (const device of devices) {
130
252
  let info = null;
131
253
  if (hasSmartctl) info = await collectSmartctlDisk(device);
132
- if (!info) info = await collectDiskutilFallback(device);
254
+ if (!info && process.platform === "win32") info = await collectWindowsDiskFallback(device);
255
+ if (!info && process.platform === "darwin") info = await collectDiskutilFallback(device);
133
256
  if (!info) continue;
134
257
  console.log(chalk.bold(` ${info.device}`));
135
258
  console.log(` Model: ${info.model}`);
@@ -158,9 +281,11 @@ async function runSmartCommand() {
158
281
  console.log();
159
282
  }
160
283
  if (!hasSmartctl) {
161
- console.log(chalk.dim(" Install smartmontools for full SMART attributes.\n"));
284
+ console.log(chalk.dim(" Install smartmontools for complete SMART attribute dump.\n"));
162
285
  }
163
286
  }
164
287
  export {
288
+ parseWindowsPhysicalDiskCsv,
289
+ parseWindowsReliabilityCsv,
165
290
  runSmartCommand
166
291
  };
@@ -0,0 +1,75 @@
1
+ import {
2
+ collectAll
3
+ } from "./chunk-QEH4LR6P.js";
4
+ import "./chunk-NMGQVRCA.js";
5
+ import "./chunk-FYCBGUTW.js";
6
+ import "./chunk-OCL7P7N7.js";
7
+ import "./chunk-MZO5QKUR.js";
8
+ import "./chunk-3RG5ZIWI.js";
9
+
10
+ // src/statuslineCmd.ts
11
+ async function collectStatuslineMetrics() {
12
+ const data = await collectAll();
13
+ const cpuUsage = data.cpu.usage;
14
+ const memUsage = data.memory.usagePercent;
15
+ const tempC = data.cpu.temperature;
16
+ const batteryPct = data.battery ? data.battery.percent : void 0;
17
+ const batteryCharging = data.battery ? data.battery.isCharging : void 0;
18
+ return {
19
+ cpuUsage,
20
+ memUsage,
21
+ tempC,
22
+ batteryPct,
23
+ batteryCharging
24
+ };
25
+ }
26
+ function formatStatusline(m, format) {
27
+ const cpu = Math.round(m.cpuUsage);
28
+ const mem = Math.round(m.memUsage);
29
+ const temp = m.tempC !== void 0 ? `${Math.round(m.tempC)}\xB0C` : "";
30
+ const batt = m.batteryPct !== void 0 ? `${m.batteryCharging ? "\u26A1" : ""}${m.batteryPct}%` : "";
31
+ switch (format) {
32
+ case "json":
33
+ return JSON.stringify({
34
+ cpu: m.cpuUsage,
35
+ mem: m.memUsage,
36
+ temp: m.tempC,
37
+ battery: m.batteryPct,
38
+ charging: m.batteryCharging
39
+ });
40
+ case "tmux": {
41
+ const parts = [];
42
+ parts.push(`#[fg=cyan]CPU: ${cpu}%`);
43
+ parts.push(`#[fg=magenta]RAM: ${mem}%`);
44
+ if (temp) parts.push(`#[fg=yellow]${temp}`);
45
+ if (batt) parts.push(`#[fg=green]${batt}`);
46
+ return parts.join(" #[fg=dim]| ");
47
+ }
48
+ case "pango": {
49
+ const parts = [];
50
+ parts.push(`<span color="#22d3ee">CPU: ${cpu}%</span>`);
51
+ parts.push(`<span color="#a78bfa">RAM: ${mem}%</span>`);
52
+ if (temp) parts.push(`<span color="#fb923c">${temp}</span>`);
53
+ if (batt) parts.push(`<span color="#34d399">${batt}</span>`);
54
+ return parts.join(" | ");
55
+ }
56
+ case "starship":
57
+ case "plain":
58
+ default: {
59
+ const parts = [`\u{1F525} ${cpu}%`, `${mem}%`];
60
+ if (temp) parts.push(temp);
61
+ if (batt) parts.push(batt);
62
+ return parts.join(" | ");
63
+ }
64
+ }
65
+ }
66
+ async function runStatuslineCommand(format = "plain") {
67
+ const metrics = await collectStatuslineMetrics();
68
+ const output = formatStatusline(metrics, format);
69
+ process.stdout.write(output + "\n");
70
+ }
71
+ export {
72
+ collectStatuslineMetrics,
73
+ formatStatusline,
74
+ runStatuslineCommand
75
+ };
@@ -1,3 +1,5 @@
1
+ import "./chunk-3RG5ZIWI.js";
2
+
1
3
  // src/stressCmd.ts
2
4
  import { Worker, isMainThread, workerData } from "worker_threads";
3
5
  import os from "os";