@hienlh/ppm 0.7.26 → 0.7.27
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 +7 -0
- package/package.json +1 -1
- package/src/cli/commands/restart.ts +59 -10
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.7.27] - 2026-03-22
|
|
4
|
+
|
|
5
|
+
### Fixed
|
|
6
|
+
- **Restart from PPM terminal**: restart spawns a detached worker process so it completes even when the server (and its terminals) are killed mid-restart
|
|
7
|
+
- **Restart result visibility**: restart command now polls for the worker's result and displays it inline; pre-restart message warns PPM terminal users to wait and reload
|
|
8
|
+
- **Restart server script path**: saved in `status.json` during `ppm start` to avoid ephemeral `bunx` cache path issues
|
|
9
|
+
|
|
3
10
|
## [0.7.26] - 2026-03-22
|
|
4
11
|
|
|
5
12
|
### Fixed
|
package/package.json
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import { resolve } from "node:path";
|
|
2
2
|
import { homedir } from "node:os";
|
|
3
|
-
import { readFileSync, writeFileSync, existsSync, openSync } from "node:fs";
|
|
3
|
+
import { readFileSync, writeFileSync, existsSync, openSync, unlinkSync } from "node:fs";
|
|
4
4
|
|
|
5
5
|
const PPM_DIR = resolve(homedir(), ".ppm");
|
|
6
6
|
const STATUS_FILE = resolve(PPM_DIR, "status.json");
|
|
7
7
|
const PID_FILE = resolve(PPM_DIR, "ppm.pid");
|
|
8
8
|
const RESTARTING_FLAG = resolve(PPM_DIR, ".restarting");
|
|
9
|
+
const RESTART_RESULT = resolve(PPM_DIR, ".restart-result");
|
|
9
10
|
|
|
10
11
|
/** Restart only the server process, keeping the tunnel alive */
|
|
11
12
|
export async function restartServer(options: { config?: string }) {
|
|
@@ -42,21 +43,28 @@ export async function restartServer(options: { config?: string }) {
|
|
|
42
43
|
// Write restarting flag so tunnel cleanup handler skips killing cloudflared
|
|
43
44
|
writeFileSync(RESTARTING_FLAG, "");
|
|
44
45
|
|
|
46
|
+
// Clear previous result
|
|
47
|
+
try { unlinkSync(RESTART_RESULT); } catch {}
|
|
48
|
+
|
|
49
|
+
// Pre-restart message — user sees this before terminal dies (if running inside PPM)
|
|
50
|
+
console.log("\n Restarting PPM server...");
|
|
51
|
+
console.log(" If you're using PPM terminal, wait a few seconds then reload the page.\n");
|
|
52
|
+
|
|
45
53
|
// Generate a self-contained restart worker script.
|
|
46
|
-
//
|
|
47
|
-
// (and the PPM server hosting its terminal) is killed.
|
|
54
|
+
// Runs as a detached process so it survives when the PPM server (and its terminals) die.
|
|
48
55
|
const params = JSON.stringify({
|
|
49
56
|
serverPid, port, host, serverScript,
|
|
50
57
|
config: options.config ?? "",
|
|
51
58
|
statusFile: STATUS_FILE,
|
|
52
59
|
pidFile: PID_FILE,
|
|
53
60
|
restartingFlag: RESTARTING_FLAG,
|
|
61
|
+
resultFile: RESTART_RESULT,
|
|
54
62
|
ppmDir: PPM_DIR,
|
|
55
63
|
});
|
|
56
64
|
|
|
57
65
|
const workerPath = resolve(PPM_DIR, ".restart-worker.ts");
|
|
58
66
|
writeFileSync(workerPath, `
|
|
59
|
-
import { readFileSync, writeFileSync, openSync, unlinkSync, appendFileSync
|
|
67
|
+
import { readFileSync, writeFileSync, openSync, unlinkSync, appendFileSync } from "node:fs";
|
|
60
68
|
import { createServer } from "node:net";
|
|
61
69
|
|
|
62
70
|
const P = ${params};
|
|
@@ -66,6 +74,9 @@ async function main() {
|
|
|
66
74
|
const ts = new Date().toISOString();
|
|
67
75
|
try { appendFileSync(P.ppmDir + "/ppm.log", "[" + ts + "] [" + level + "] " + msg + "\\n"); } catch {}
|
|
68
76
|
};
|
|
77
|
+
const writeResult = (ok: boolean, msg: string) => {
|
|
78
|
+
try { writeFileSync(P.resultFile, JSON.stringify({ ok, message: msg })); } catch {}
|
|
79
|
+
};
|
|
69
80
|
|
|
70
81
|
// Kill old server
|
|
71
82
|
try { process.kill(P.serverPid); log("INFO", "Restart: killed old server PID " + P.serverPid); } catch {}
|
|
@@ -115,12 +126,32 @@ async function main() {
|
|
|
115
126
|
await Bun.sleep(300);
|
|
116
127
|
}
|
|
117
128
|
|
|
129
|
+
// Check tunnel
|
|
130
|
+
let tunnelAlive = false;
|
|
131
|
+
let tunnelPid: number | undefined;
|
|
132
|
+
let shareUrl: string | undefined;
|
|
133
|
+
try {
|
|
134
|
+
const st = JSON.parse(readFileSync(P.statusFile, "utf-8"));
|
|
135
|
+
tunnelPid = st.tunnelPid;
|
|
136
|
+
shareUrl = st.shareUrl;
|
|
137
|
+
if (tunnelPid) { process.kill(tunnelPid, 0); tunnelAlive = true; }
|
|
138
|
+
} catch {}
|
|
139
|
+
|
|
118
140
|
if (ready) {
|
|
119
|
-
|
|
141
|
+
let msg = "Restart complete (PID: " + child.pid + ", port: " + P.port + ")";
|
|
142
|
+
if (shareUrl && tunnelPid) {
|
|
143
|
+
msg += tunnelAlive ? " — tunnel alive" : " — tunnel dead, run 'ppm stop && ppm start --share'";
|
|
144
|
+
}
|
|
145
|
+
log("INFO", msg);
|
|
146
|
+
writeResult(true, msg);
|
|
120
147
|
} else {
|
|
121
148
|
let alive = false;
|
|
122
149
|
try { process.kill(child.pid, 0); alive = true; } catch {}
|
|
123
|
-
|
|
150
|
+
const msg = alive
|
|
151
|
+
? "Server started but not responding on port " + P.port + ". Check: ppm logs"
|
|
152
|
+
: "Server crashed on startup. Check: ppm logs";
|
|
153
|
+
log("ERROR", msg);
|
|
154
|
+
writeResult(false, msg);
|
|
124
155
|
}
|
|
125
156
|
|
|
126
157
|
// Cleanup worker file
|
|
@@ -140,9 +171,27 @@ main();
|
|
|
140
171
|
});
|
|
141
172
|
worker.unref();
|
|
142
173
|
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
174
|
+
// Poll for result — if running from external terminal, we'll see the result.
|
|
175
|
+
// If running from PPM terminal, this process dies when server is killed — that's fine,
|
|
176
|
+
// the user already saw the pre-restart message above.
|
|
177
|
+
const pollStart = Date.now();
|
|
178
|
+
while (Date.now() - pollStart < 20000) {
|
|
179
|
+
await Bun.sleep(500);
|
|
180
|
+
if (existsSync(RESTART_RESULT)) {
|
|
181
|
+
try {
|
|
182
|
+
const result = JSON.parse(readFileSync(RESTART_RESULT, "utf-8"));
|
|
183
|
+
if (result.ok) {
|
|
184
|
+
console.log(` ✓ ${result.message}`);
|
|
185
|
+
} else {
|
|
186
|
+
console.error(` ✗ ${result.message}`);
|
|
187
|
+
}
|
|
188
|
+
unlinkSync(RESTART_RESULT);
|
|
189
|
+
} catch {}
|
|
190
|
+
process.exit(0);
|
|
191
|
+
}
|
|
192
|
+
}
|
|
146
193
|
|
|
147
|
-
|
|
194
|
+
// Timeout — worker might still be running
|
|
195
|
+
console.error(" ⚠ Restart timed out. Check: ppm logs");
|
|
196
|
+
process.exit(1);
|
|
148
197
|
}
|