pyre-cli 3.7.0 → 3.9.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 CHANGED
@@ -197,6 +197,30 @@ The client connects to the server, authenticates with the password, and displays
197
197
  | `--p2p-audit-log <dir>` | Directory for P2P client audit logs |
198
198
  | `--p2p-hmac-key <key>` | HMAC key for message signing (must match server) |
199
199
 
200
+ ### Same local network (LAN)
201
+
202
+ Both machines must be connected to the same local network (same WiFi or wired subnet). The server listens on `0.0.0.0` (all interfaces) by default, so any device on the LAN can reach it as long as the port is reachable.
203
+
204
+ On the **server machine**, find its local IP address:
205
+
206
+ ```bash
207
+ hostname -I
208
+ # or
209
+ ifconfig | grep "inet " | grep -v 127.0.0
210
+ ```
211
+
212
+ Use the server's local IP (for example `192.168.1.25`) in the client command:
213
+
214
+ ```bash
215
+ pyre p2p connect --p2p-host 192.168.1.25 --p2p-port 9876 --p2p-password mysecret
216
+ ```
217
+
218
+ **Troubleshooting**
219
+
220
+ - If the client cannot reach the server, confirm both machines are on the same subnet (ping the server IP from the client).
221
+ - Verify the port is open (no local firewall blocking TCP `9876`).
222
+ - Never expose the server directly to the public internet; it is designed for LAN use only.
223
+
200
224
  ### P2P Protocol
201
225
 
202
226
  The P2P connection uses a length-prefixed JSON protocol over TCP with HMAC-SHA256 message signing:
package/dist/index.js CHANGED
@@ -2238,8 +2238,12 @@ var P2PServer = class {
2238
2238
  }
2239
2239
  }
2240
2240
  sendSigned(peer, message) {
2241
- if (!peer.socket.destroyed) {
2241
+ if (peer.socket.destroyed || !peer.socket.writable) {
2242
+ return;
2243
+ }
2244
+ try {
2242
2245
  peer.socket.write(message);
2246
+ } catch {
2243
2247
  }
2244
2248
  }
2245
2249
  startDataStream(peer) {
@@ -2272,6 +2276,8 @@ var P2PServer = class {
2272
2276
  this.log(chalk6.yellow(`Peer connection reset: ${peer.socket.remoteAddress}`));
2273
2277
  this.audit(peer.ip, "ERROR", "Connection reset");
2274
2278
  this.emitPeerEvent("error", `connection reset: ${peer.socket.remoteAddress}`);
2279
+ } else if (code === "EPIPE") {
2280
+ this.audit(peer.ip, "ERROR", "Broken pipe");
2275
2281
  } else {
2276
2282
  this.log(chalk6.red(`Peer error: ${err.message}`));
2277
2283
  this.audit(peer.ip, "ERROR", err.message);
@@ -2480,7 +2486,10 @@ var P2PClient = class {
2480
2486
  }
2481
2487
  sendSigned(message) {
2482
2488
  if (this.socket && !this.socket.destroyed) {
2483
- this.socket.write(message);
2489
+ try {
2490
+ this.socket.write(message);
2491
+ } catch {
2492
+ }
2484
2493
  }
2485
2494
  }
2486
2495
  startPing() {
@@ -3186,7 +3195,7 @@ async function showSplash() {
3186
3195
  // src/index.ts
3187
3196
  var pkg = JSON.parse(fs4.readFileSync(new URL("../package.json", import.meta.url), "utf-8"));
3188
3197
  var program = new Command();
3189
- program.name("pyre").version(pkg.version).description("Mac system monitoring CLI: interactive live dashboard, stats, graphs, export, packet monitor, battery predictor").option("-j, --json", "Output as JSON").option("-c, --csv", "Output as CSV").option("-t, --tsv", "Output as TSV").option("--detailed", "Include detailed system info and sensor readings").option("--theme <name>", "Default theme for live mode (default, dracula, cyberpunk, monochrome, nord, gruvbox)", "default").option("--interval <seconds>", "Refresh interval for live mode", "2").option("--once", "Show a single static snapshot instead of live feed").option("--out <file>", "Also write the snapshot output to a file (--once/--json/--csv/--tsv modes)").option("--export-dir <dir>", "Directory used for live-mode snapshot exports and logs", "./pyre-exports").option("--log", "Start continuous CSV logging immediately when live mode starts").option("--tree", "Show process tree view instead of flat list").option("--sort <key>", "Sort processes by: cpu, mem, pid, user, command, state, threads, runtime", "cpu").option("--packets", "Include packet monitor panel in output").option("--limit <n>", "Max number of processes to include in --once/--json/--csv/--tsv snapshots (0 = all)", "10").option("--p2p-host <host>", "P2P host address (server: bind address, client: server address)", "0.0.0.0").option("--p2p-port <port>", "P2P port number", "9876").option("--p2p-password <password>", "Password for P2P authentication").option("--p2p-tls", "Enable TLS encryption for P2P connections").option("--p2p-cert <file>", "TLS certificate file (PEM) for P2P server").option("--p2p-key <file>", "TLS private key file (PEM) for P2P server").option("--p2p-ca <file>", "TLS CA certificate file (PEM) for P2P client").option("--p2p-insecure", "Skip TLS certificate verification (client only)").option("--p2p-rate-limit <n>", "Max auth attempts per IP per minute (default: 5)", "5").option("--p2p-allow <ips>", "Comma-separated list of allowed IPs (empty = all)").option("--p2p-deny <ips>", "Comma-separated list of denied IPs").option("--p2p-audit-log <dir>", "Directory for P2P audit logs").option("--p2p-hmac-key <key>", "HMAC key for message signing (default: derived from password)");
3198
+ program.name("pyre").version(pkg.version).description("Mac system monitoring CLI: interactive live dashboard, stats, graphs, export, packet monitor, battery predictor").option("-j, --json", "Output as JSON").option("-c, --csv", "Output as CSV").option("-t, --tsv", "Output as TSV").option("--detailed", "Include detailed system info and sensor readings").option("--theme <name>", "Default theme for live mode (default, dracula, cyberpunk, monochrome, nord, gruvbox)", "default").option("--interval <seconds>", "Refresh interval for live mode", "2").option("--once", "Show a single static snapshot instead of live feed").option("--out <file>", "Also write the snapshot output to a file (--once/--json/--csv/--tsv modes)").option("--export-dir <dir>", "Directory used for live-mode snapshot exports and logs", "./pyre-exports").option("--log", "Start continuous CSV logging immediately when live mode starts").option("--tree", "Show process tree view instead of flat list").option("--sort <key>", "Sort processes by: cpu, mem, pid, user, command, state, threads, runtime", "cpu").option("--packets", "Include packet monitor panel in output").option("--limit <n>", "Max number of processes to include in --once/--json/--csv/--tsv snapshots (0 = all)", "10").option("--p2p-host <host>", "P2P host address (server: bind address, client: server address)").option("--p2p-port <port>", "P2P port number", "9876").option("--p2p-password <password>", "Password for P2P authentication").option("--p2p-tls", "Enable TLS encryption for P2P connections").option("--p2p-cert <file>", "TLS certificate file (PEM) for P2P server").option("--p2p-key <file>", "TLS private key file (PEM) for P2P server").option("--p2p-ca <file>", "TLS CA certificate file (PEM) for P2P client").option("--p2p-insecure", "Skip TLS certificate verification (client only)").option("--p2p-rate-limit <n>", "Max auth attempts per IP per minute (default: 5)", "5").option("--p2p-allow <ips>", "Comma-separated list of allowed IPs (empty = all)").option("--p2p-deny <ips>", "Comma-separated list of denied IPs").option("--p2p-audit-log <dir>", "Directory for P2P audit logs").option("--p2p-hmac-key <key>", "HMAC key for message signing (default: derived from password)");
3190
3199
  program.parse(process.argv);
3191
3200
  var opts = program.opts();
3192
3201
  function isExportMode() {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pyre-cli",
3
- "version": "3.7.0",
3
+ "version": "3.9.0",
4
4
  "description": "CLI Mac monitoring tool: temps, system stats, live dashboard, packet monitor, battery predictor, export",
5
5
  "main": "dist/index.js",
6
6
  "type": "module",
package/src/index.ts CHANGED
@@ -38,7 +38,7 @@ program
38
38
  .option('--sort <key>', 'Sort processes by: cpu, mem, pid, user, command, state, threads, runtime', 'cpu')
39
39
  .option('--packets', 'Include packet monitor panel in output')
40
40
  .option('--limit <n>', 'Max number of processes to include in --once/--json/--csv/--tsv snapshots (0 = all)', '10')
41
- .option('--p2p-host <host>', 'P2P host address (server: bind address, client: server address)', '0.0.0.0')
41
+ .option('--p2p-host <host>', 'P2P host address (server: bind address, client: server address)')
42
42
  .option('--p2p-port <port>', 'P2P port number', '9876')
43
43
  .option('--p2p-password <password>', 'Password for P2P authentication')
44
44
  .option('--p2p-tls', 'Enable TLS encryption for P2P connections')
package/src/p2p/client.ts CHANGED
@@ -207,7 +207,11 @@ export class P2PClient {
207
207
 
208
208
  private sendSigned(message: Buffer): void {
209
209
  if (this.socket && !this.socket.destroyed) {
210
- this.socket.write(message);
210
+ try {
211
+ this.socket.write(message);
212
+ } catch {
213
+ // ignore write errors; socket likely closed
214
+ }
211
215
  }
212
216
  }
213
217
 
package/src/p2p/server.ts CHANGED
@@ -350,8 +350,13 @@ export class P2PServer {
350
350
  }
351
351
 
352
352
  private sendSigned(peer: Peer, message: Buffer): void {
353
- if (!peer.socket.destroyed) {
353
+ if (peer.socket.destroyed || !peer.socket.writable) {
354
+ return;
355
+ }
356
+ try {
354
357
  peer.socket.write(message);
358
+ } catch {
359
+ // ignore write errors; peer likely disconnected
355
360
  }
356
361
  }
357
362
 
@@ -390,6 +395,8 @@ export class P2PServer {
390
395
  this.log(chalk.yellow(`Peer connection reset: ${peer.socket.remoteAddress}`));
391
396
  this.audit(peer.ip, 'ERROR', 'Connection reset');
392
397
  this.emitPeerEvent('error', `connection reset: ${peer.socket.remoteAddress}`);
398
+ } else if (code === 'EPIPE') {
399
+ this.audit(peer.ip, 'ERROR', 'Broken pipe');
393
400
  } else {
394
401
  this.log(chalk.red(`Peer error: ${err.message}`));
395
402
  this.audit(peer.ip, 'ERROR', err.message);