@hienlh/ppm 0.8.77 → 0.8.78

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/CHANGELOG.md CHANGED
@@ -1,5 +1,10 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.8.78] - 2026-04-01
4
+
5
+ ### Fixed
6
+ - **Cloud version reporting**: Supervisor heartbeat now reads version from running server child (via `status.json`) instead of its own captured constant — after `ppm restart` or `bunx @hienlh/ppm@latest restart`, cloud dashboard correctly reflects the updated version
7
+
3
8
  ## [0.8.77] - 2026-04-01
4
9
 
5
10
  ### Added
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hienlh/ppm",
3
- "version": "0.8.77",
3
+ "version": "0.8.78",
4
4
  "description": "Personal Project Manager — mobile-first web IDE with AI assistance",
5
5
  "author": "hienlh",
6
6
  "license": "MIT",
@@ -360,12 +360,16 @@ if (process.argv.includes("__serve__")) {
360
360
 
361
361
  // Sync externally-started tunnel URL + PID into tunnelService
362
362
  // so GET /api/tunnel reflects the correct state and Share button doesn't start a duplicate.
363
+ // Also write server version to status.json so supervisor heartbeat reports the actual running version.
363
364
  try {
364
365
  const { resolve: r } = await import("node:path");
365
366
  const { homedir: h } = await import("node:os");
366
- const { readFileSync: rf } = await import("node:fs");
367
+ const { readFileSync: rf, writeFileSync: wf } = await import("node:fs");
367
368
  const statusFile = r(h(), ".ppm", "status.json");
368
369
  const status = JSON.parse(rf(statusFile, "utf-8"));
370
+ // Write running server version — source of truth for heartbeat
371
+ status.serverVersion = VERSION;
372
+ wf(statusFile, JSON.stringify(status));
369
373
  if (status.shareUrl) {
370
374
  const { tunnelService } = await import("../services/tunnel.service.ts");
371
375
  tunnelService.setExternalUrl(status.shareUrl);
@@ -451,16 +451,20 @@ async function connectCloud(opts: { port: number }, serverArgs: string[], logFd:
451
451
  cloudUrl: device.cloud_url,
452
452
  deviceId: device.device_id,
453
453
  secretKey: device.secret_key,
454
- heartbeatFn: () => ({
455
- type: "heartbeat" as const,
456
- tunnelUrl,
457
- state: supervisorState,
458
- appVersion: VERSION,
459
- availableVersion: (readStatus().availableVersion as string) || null,
460
- serverPid: serverChild?.pid ?? null,
461
- uptime: Math.floor((Date.now() - startTime) / 1000),
462
- timestamp: new Date().toISOString(),
463
- }),
454
+ heartbeatFn: () => {
455
+ const status = readStatus();
456
+ return {
457
+ type: "heartbeat" as const,
458
+ tunnelUrl,
459
+ state: supervisorState,
460
+ // Use server-reported version (source of truth) with supervisor fallback
461
+ appVersion: (status.serverVersion as string) || VERSION,
462
+ availableVersion: (status.availableVersion as string) || null,
463
+ serverPid: serverChild?.pid ?? null,
464
+ uptime: Math.floor((Date.now() - startTime) / 1000),
465
+ timestamp: new Date().toISOString(),
466
+ };
467
+ },
464
468
  });
465
469
 
466
470
  // Handle commands from Cloud