pyre-cli 10.1.0 → 10.2.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 (46) hide show
  1. package/README.md +195 -494
  2. package/dist/{checkCmd-RKW6QGDR.js → checkCmd-WQAHAUWO.js} +1 -1
  3. package/dist/{chunk-GHRDW646.js → chunk-23YWCI3O.js} +375 -135
  4. package/dist/{service-Q74BBILO.js → chunk-KFPTD266.js} +43 -3
  5. package/dist/{doctor-GYHFTNZQ.js → chunk-KVUMOA6C.js} +7 -6
  6. package/dist/{chunk-53O2RGSL.js → chunk-QM5L43EK.js} +19 -2
  7. package/dist/{chunk-6UHZP4QP.js → chunk-XTOOEKLM.js} +24 -12
  8. package/dist/{collectors-H43PN4PS.js → collectors-JDN5Y7EV.js} +1 -1
  9. package/dist/{completions-JKYEJNGR.js → completions-ZVTNE52B.js} +15 -11
  10. package/dist/{config-GYGJXU2Q.js → config-J4YMADEF.js} +3 -1
  11. package/dist/doctor-LHFW4UJP.js +10 -0
  12. package/dist/firebaseSync-ON3RZ6KX.js +91 -0
  13. package/dist/index.js +4243 -735
  14. package/dist/monitors/platform/windows-ui.ps1 +42 -0
  15. package/dist/{netUsageCmd-WKBTW2YG.js → netUsageCmd-67IBZZYN.js} +2 -2
  16. package/dist/{pipeCmd-7REDBLBU.js → pipeCmd-2N4JPKYE.js} +1 -1
  17. package/dist/{prometheusCmd-PL64BLN5.js → prometheusCmd-LEUM5WCZ.js} +1 -1
  18. package/dist/serveCmd-L7LVJOZN.js +353 -0
  19. package/dist/service-7GIX3YNC.js +16 -0
  20. package/dist/syncCmd-42IRF633.js +246 -0
  21. package/dist/{topoCmd-DU2HHZNH.js → topoCmd-DZ3YS5IL.js} +1 -1
  22. package/dist/{watchdogCmd-UF53JPZB.js → watchdogCmd-6GR4UN6B.js} +7 -7
  23. package/dist/{wizard-TD7BGX6O.js → wizard-JQMQWFAW.js} +1 -1
  24. package/package.json +4 -3
  25. package/parity.md +2 -0
  26. package/src/completions.ts +15 -11
  27. package/src/easy_features.test.ts +149 -0
  28. package/src/firebaseSync.ts +157 -0
  29. package/src/formatters/html_template.ts +3086 -598
  30. package/src/formatters/render.ts +25 -12
  31. package/src/index.ts +516 -23
  32. package/src/live/input.ts +501 -148
  33. package/src/live/render.ts +163 -18
  34. package/src/live/state.ts +52 -2
  35. package/src/live/types.ts +1 -1
  36. package/src/monitors/collectors.ts +3 -10
  37. package/src/monitors/platform/windows-ui.ps1 +42 -0
  38. package/src/monitors/platform/windows.ts +442 -147
  39. package/src/monitors/types.ts +8 -0
  40. package/src/serveCmd.ts +17 -2
  41. package/src/service.ts +49 -0
  42. package/src/state/config.ts +48 -0
  43. package/src/syncCmd.ts +159 -11
  44. package/src/web/dashboard.ts +205 -0
  45. package/dist/serveCmd-2H5VLF3P.js +0 -153
  46. package/dist/syncCmd-A2W3QB3S.js +0 -126
@@ -1,153 +0,0 @@
1
- import {
2
- collectAll,
3
- collectBattery,
4
- collectContainers,
5
- collectCpu,
6
- collectDisk,
7
- collectGpu,
8
- collectMemory,
9
- collectNetwork,
10
- collectProcesses,
11
- collectSystem,
12
- collectThermal
13
- } from "./chunk-GHRDW646.js";
14
- import "./chunk-M73HCQD2.js";
15
- import "./chunk-VIACN2RU.js";
16
- import "./chunk-MZO5QKUR.js";
17
-
18
- // src/serveCmd.ts
19
- import http from "http";
20
- import os from "os";
21
- import chalk from "chalk";
22
- async function runServeCommand(opts = {}) {
23
- const port = opts.port || 8080;
24
- const apiKey = opts.apiKey || process.env.PYRE_API_KEY || "";
25
- const server = http.createServer(async (req, res) => {
26
- res.setHeader("Access-Control-Allow-Origin", "*");
27
- res.setHeader("Access-Control-Allow-Methods", "GET, OPTIONS");
28
- res.setHeader("Access-Control-Allow-Headers", "Content-Type, Authorization, x-api-key");
29
- if (req.method === "OPTIONS") {
30
- res.writeHead(204);
31
- res.end();
32
- return;
33
- }
34
- const urlObj = new URL(req.url || "/", `http://localhost:${port}`);
35
- const pathname = urlObj.pathname;
36
- if (apiKey) {
37
- const authHeader = req.headers["authorization"] || "";
38
- const xApiKey = req.headers["x-api-key"] || "";
39
- const queryKey = urlObj.searchParams.get("key") || "";
40
- const token = authHeader.startsWith("Bearer ") ? authHeader.slice(7) : authHeader;
41
- if (token !== apiKey && xApiKey !== apiKey && queryKey !== apiKey) {
42
- res.writeHead(401, { "Content-Type": "application/json" });
43
- res.end(JSON.stringify({ error: "Unauthorized: Invalid or missing API key" }));
44
- return;
45
- }
46
- }
47
- try {
48
- let data;
49
- switch (pathname) {
50
- case "/api/all":
51
- case "/api/stats":
52
- case "/api":
53
- data = await collectAll({ detailed: opts.detailed });
54
- break;
55
- case "/api/cpu":
56
- data = await collectCpu();
57
- break;
58
- case "/api/memory":
59
- case "/api/mem":
60
- data = await collectMemory();
61
- break;
62
- case "/api/gpu":
63
- data = await collectGpu(opts.detailed);
64
- break;
65
- case "/api/battery":
66
- case "/api/power":
67
- data = await collectBattery();
68
- break;
69
- case "/api/thermal":
70
- case "/api/temp":
71
- data = await collectThermal(opts.detailed);
72
- break;
73
- case "/api/network":
74
- case "/api/net":
75
- data = await collectNetwork();
76
- break;
77
- case "/api/disk":
78
- data = await collectDisk();
79
- break;
80
- case "/api/processes":
81
- case "/api/proc":
82
- data = await collectProcesses(50);
83
- break;
84
- case "/api/containers":
85
- data = await collectContainers();
86
- break;
87
- case "/api/system":
88
- case "/api/info":
89
- data = await collectSystem();
90
- break;
91
- case "/health":
92
- case "/api/health":
93
- res.writeHead(200, { "Content-Type": "application/json" });
94
- res.end(JSON.stringify({ status: "ok", uptime: os.uptime(), timestamp: (/* @__PURE__ */ new Date()).toISOString() }));
95
- return;
96
- default:
97
- res.writeHead(404, { "Content-Type": "application/json" });
98
- res.end(JSON.stringify({
99
- error: "Not found",
100
- availableEndpoints: [
101
- "/api/all",
102
- "/api/cpu",
103
- "/api/memory",
104
- "/api/gpu",
105
- "/api/battery",
106
- "/api/thermal",
107
- "/api/network",
108
- "/api/disk",
109
- "/api/processes",
110
- "/api/containers",
111
- "/api/system",
112
- "/api/health"
113
- ]
114
- }));
115
- return;
116
- }
117
- res.writeHead(200, { "Content-Type": "application/json" });
118
- res.end(JSON.stringify(data, null, 2));
119
- } catch (err) {
120
- res.writeHead(500, { "Content-Type": "application/json" });
121
- res.end(JSON.stringify({ error: err.message || "Internal metric collection error" }));
122
- }
123
- });
124
- server.on("error", (err) => {
125
- if (err.code === "EADDRINUSE") {
126
- console.error(chalk.red(`
127
- \u2716 Error: Port ${port} is already in use. Use --port <port> to select an alternate port.
128
- `));
129
- } else {
130
- console.error(chalk.red(`
131
- \u2716 Server error: ${err.message}
132
- `));
133
- }
134
- process.exit(1);
135
- });
136
- await new Promise((resolve) => server.listen(port, "0.0.0.0", resolve));
137
- console.log(chalk.bold("\n \u{1F525} pyre serve \u2014 REST API Server\n"));
138
- console.log(` ${chalk.green("\u2714")} API base URL: ${chalk.cyan(`http://0.0.0.0:${port}/api/all`)}`);
139
- console.log(` ${chalk.green("\u2714")} Health check: ${chalk.cyan(`http://0.0.0.0:${port}/api/health`)}`);
140
- if (apiKey) {
141
- console.log(` ${chalk.yellow("\u{1F512}")} API Key protection: ${chalk.bold("ENABLED")} (Pass via header x-api-key or ?key=)`);
142
- } else {
143
- console.log(` ${chalk.dim("\u{1F513}")} API Key protection: ${chalk.dim("DISABLED (Public local network access)")}`);
144
- }
145
- console.log(`
146
- ${chalk.dim("Endpoints: /api/cpu, /api/memory, /api/gpu, /api/battery, /api/thermal, /api/network, /api/disk, /api/processes")}`);
147
- console.log(chalk.dim("\n Press Ctrl+C to stop.\n"));
148
- await new Promise(() => {
149
- });
150
- }
151
- export {
152
- runServeCommand
153
- };
@@ -1,126 +0,0 @@
1
- import {
2
- getConfigFile,
3
- getProfilesDir,
4
- writeConfig
5
- } from "./chunk-53O2RGSL.js";
6
-
7
- // src/syncCmd.ts
8
- import fs from "fs";
9
- import path from "path";
10
- import os from "os";
11
- import crypto from "crypto";
12
- import chalk from "chalk";
13
- function getDefaultSyncDir() {
14
- if (process.env.PYRE_SYNC_DIR) return process.env.PYRE_SYNC_DIR;
15
- const icloudPath = path.join(os.homedir(), "Library", "Mobile Documents", "com~apple~CloudDocs", "PyreSync");
16
- if (fs.existsSync(path.dirname(icloudPath))) {
17
- return icloudPath;
18
- }
19
- return path.join(os.homedir(), ".pyre-sync");
20
- }
21
- function computeDirChecksum(dirPath) {
22
- const hash = crypto.createHash("sha256");
23
- if (!fs.existsSync(dirPath)) return "";
24
- const files = fs.readdirSync(dirPath).sort();
25
- for (const file of files) {
26
- const full = path.join(dirPath, file);
27
- if (fs.statSync(full).isFile()) {
28
- hash.update(file);
29
- hash.update(fs.readFileSync(full));
30
- }
31
- }
32
- return hash.digest("hex").slice(0, 16);
33
- }
34
- async function runSyncCommand(subcommand = "status", opts = {}) {
35
- const syncDir = opts.syncDir || getDefaultSyncDir();
36
- const manifestPath = path.join(syncDir, "sync-manifest.json");
37
- const remoteProfilesDir = path.join(syncDir, "profiles");
38
- const remoteConfigFile = path.join(syncDir, "config.json");
39
- const localProfilesDir = getProfilesDir();
40
- const localConfigFile = getConfigFile();
41
- console.log(chalk.bold("\n \u{1F525} pyre sync \u2014 Configuration & Profile Cloud Sync\n"));
42
- console.log(` Sync Target Directory: ${chalk.cyan(syncDir)}`);
43
- if (subcommand === "status" || !subcommand) {
44
- const hasSyncDir = fs.existsSync(syncDir);
45
- const hasManifest = fs.existsSync(manifestPath);
46
- console.log(` Local Profiles: ${chalk.bold(String(fs.existsSync(localProfilesDir) ? fs.readdirSync(localProfilesDir).filter((f) => f.endsWith(".json")).length : 0))}`);
47
- console.log(` Sync Target Available: ${hasSyncDir ? chalk.green("YES") : chalk.yellow("NO (will be created on push)")}`);
48
- if (hasManifest) {
49
- try {
50
- const manifest = JSON.parse(fs.readFileSync(manifestPath, "utf-8"));
51
- console.log(` Remote Last Updated: ${chalk.green(manifest.lastUpdated)} (from ${chalk.bold(manifest.sourceHost)})`);
52
- console.log(` Remote Profiles Count: ${chalk.bold(String(manifest.profilesCount))}`);
53
- console.log(` Remote Checksum: ${chalk.dim(manifest.checksum)}`);
54
- } catch {
55
- console.log(chalk.yellow(" Remote manifest corrupted."));
56
- }
57
- } else {
58
- console.log(chalk.dim(' No remote sync bundle detected yet. Run "pyre sync push" to initialize.'));
59
- }
60
- console.log();
61
- return;
62
- }
63
- if (subcommand === "push") {
64
- if (!fs.existsSync(syncDir)) {
65
- fs.mkdirSync(syncDir, { recursive: true });
66
- }
67
- if (!fs.existsSync(remoteProfilesDir)) {
68
- fs.mkdirSync(remoteProfilesDir, { recursive: true });
69
- }
70
- if (fs.existsSync(localConfigFile)) {
71
- fs.copyFileSync(localConfigFile, remoteConfigFile);
72
- }
73
- let profileCount = 0;
74
- if (fs.existsSync(localProfilesDir)) {
75
- const files = fs.readdirSync(localProfilesDir).filter((f) => f.endsWith(".json"));
76
- profileCount = files.length;
77
- for (const f of files) {
78
- fs.copyFileSync(path.join(localProfilesDir, f), path.join(remoteProfilesDir, f));
79
- }
80
- }
81
- const checksum = computeDirChecksum(remoteProfilesDir);
82
- const manifest = {
83
- version: 1,
84
- lastUpdated: (/* @__PURE__ */ new Date()).toISOString(),
85
- sourceHost: os.hostname(),
86
- checksum,
87
- profilesCount: profileCount
88
- };
89
- fs.writeFileSync(manifestPath, JSON.stringify(manifest, null, 2));
90
- console.log(chalk.green(` \u2714 Successfully pushed config and ${profileCount} profile(s) to sync target.`));
91
- console.log(` Checksum: ${chalk.dim(checksum)} | Timestamp: ${chalk.dim(manifest.lastUpdated)}
92
- `);
93
- return;
94
- }
95
- if (subcommand === "pull") {
96
- if (!fs.existsSync(manifestPath) || !fs.existsSync(remoteConfigFile)) {
97
- console.error(chalk.red(` \u2716 Error: No sync manifest found at ${syncDir}. Run "pyre sync push" first from another machine.
98
- `));
99
- process.exit(1);
100
- }
101
- if (fs.existsSync(remoteConfigFile)) {
102
- const remoteConfig = JSON.parse(fs.readFileSync(remoteConfigFile, "utf-8"));
103
- writeConfig(remoteConfig);
104
- }
105
- let pulledCount = 0;
106
- if (fs.existsSync(remoteProfilesDir)) {
107
- if (!fs.existsSync(localProfilesDir)) {
108
- fs.mkdirSync(localProfilesDir, { recursive: true });
109
- }
110
- const files = fs.readdirSync(remoteProfilesDir).filter((f) => f.endsWith(".json"));
111
- pulledCount = files.length;
112
- for (const f of files) {
113
- fs.copyFileSync(path.join(remoteProfilesDir, f), path.join(localProfilesDir, f));
114
- }
115
- }
116
- console.log(chalk.green(` \u2714 Successfully pulled latest configuration and ${pulledCount} profile(s).`));
117
- console.log(chalk.dim(` Applied to ${localConfigFile}
118
- `));
119
- return;
120
- }
121
- console.log(chalk.yellow(` Unknown subcommand: "${subcommand}". Available: status, push, pull
122
- `));
123
- }
124
- export {
125
- runSyncCommand
126
- };