@hienlh/ppm 0.13.22 → 0.13.23

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/bunfig.toml ADDED
@@ -0,0 +1,2 @@
1
+ [test]
2
+ preload = ["./tests/test-setup.ts"]
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hienlh/ppm",
3
- "version": "0.13.22",
3
+ "version": "0.13.23",
4
4
  "description": "Personal Project Manager — mobile-first web IDE with AI assistance",
5
5
  "author": "hienlh",
6
6
  "license": "MIT",
package/src/index.ts CHANGED
File without changes
@@ -838,6 +838,38 @@ export async function runSupervisor(opts: {
838
838
  const logFd = openSync(logFile(), "a");
839
839
  log("INFO", `Supervisor started (PID: ${process.pid}, port: ${opts.port}, share: ${opts.share})`);
840
840
 
841
+ // ── Systemd self-heal: if the unit file is stale (e.g. still has
842
+ // Restart=on-failure), we were likely spawned by the old Bun.spawn()
843
+ // upgrade path and systemd can't track us ("not our child"). Restart=always
844
+ // won't trigger on exit because systemd never notices we exited.
845
+ // Fix: regenerate the unit, then restart *through* systemd so it spawns a
846
+ // properly-tracked child. The restart runs in a separate systemd-run scope
847
+ // so it survives our cgroup teardown.
848
+ const underSystemd = !!process.env.INVOCATION_ID && process.platform === "linux";
849
+ if (underSystemd) {
850
+ try {
851
+ const { isAutoStartUnitStale, enableAutoStart } = await import("./autostart-register.ts");
852
+ if (isAutoStartUnitStale()) {
853
+ log("INFO", "Stale systemd unit detected — regenerating and restarting through systemd for proper process tracking");
854
+ await enableAutoStart(
855
+ { port: opts.port, host: opts.host, share: opts.share, profile: opts.profile },
856
+ { skipStart: true },
857
+ );
858
+ // Schedule restart in a separate scope (survives our cgroup teardown)
859
+ Bun.spawn({
860
+ cmd: ["systemd-run", "--user", "--scope", "--quiet", "--collect",
861
+ "--", "systemctl", "--user", "restart", "ppm.service"],
862
+ stdio: ["ignore", "ignore", "ignore"],
863
+ }).unref();
864
+ // Give systemd-run a moment to register the scope, then exit
865
+ await Bun.sleep(1000);
866
+ process.exit(0);
867
+ }
868
+ } catch (e) {
869
+ log("WARN", `Systemd self-heal failed (non-fatal): ${e}`);
870
+ }
871
+ }
872
+
841
873
  // Global exception handlers — supervisor must never crash
842
874
  process.on("uncaughtException", (err) => {
843
875
  log("ERROR", `Uncaught exception: ${err.stack || err.message}`);