@dylanpiercey/work 0.0.12 → 0.0.13
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/bin/work.mjs +107 -0
- package/package.json +1 -1
package/bin/work.mjs
CHANGED
|
@@ -208,7 +208,114 @@ function serviceEnv() {
|
|
|
208
208
|
return env;
|
|
209
209
|
}
|
|
210
210
|
|
|
211
|
+
/** True when `cmd` is a work *server* (not `work setup` / `work update`). */
|
|
212
|
+
function isWorkServerCmd(cmd) {
|
|
213
|
+
if (/\bwork(\.mjs)?\s+(setup|update|version)\b/.test(cmd)) return false;
|
|
214
|
+
return (
|
|
215
|
+
/\bwork\.mjs\s+start\b/.test(cmd) ||
|
|
216
|
+
/\bwork\s+start\b/.test(cmd) ||
|
|
217
|
+
/run-prod\.sh/.test(cmd) ||
|
|
218
|
+
/work server is running/.test(cmd) ||
|
|
219
|
+
(/@dylanpiercey\/work\//.test(cmd) && !/\bnpm\b/.test(cmd)) ||
|
|
220
|
+
/\/work\/\S*\/dist\/index\.mjs/.test(cmd)
|
|
221
|
+
);
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
function pidsListening(port) {
|
|
225
|
+
const lsof = spawnSync(
|
|
226
|
+
"lsof",
|
|
227
|
+
["-nP", `-iTCP:${port}`, "-sTCP:LISTEN", "-t"],
|
|
228
|
+
{ encoding: "utf8" },
|
|
229
|
+
);
|
|
230
|
+
if (lsof.stdout) {
|
|
231
|
+
return [
|
|
232
|
+
...new Set(
|
|
233
|
+
lsof.stdout
|
|
234
|
+
.trim()
|
|
235
|
+
.split(/\s+/)
|
|
236
|
+
.map(Number)
|
|
237
|
+
.filter((n) => n > 1 && n !== process.pid),
|
|
238
|
+
),
|
|
239
|
+
];
|
|
240
|
+
}
|
|
241
|
+
const ss = spawnSync("ss", ["-ltnp", `sport = :${port}`], { encoding: "utf8" });
|
|
242
|
+
const pids = [];
|
|
243
|
+
for (const m of (ss.stdout || "").matchAll(/pid=(\d+)/g)) {
|
|
244
|
+
const pid = Number(m[1]);
|
|
245
|
+
if (pid > 1 && pid !== process.pid) pids.push(pid);
|
|
246
|
+
}
|
|
247
|
+
return [...new Set(pids)];
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
function workServerPids() {
|
|
251
|
+
const out = spawnSync("ps", ["-ax", "-o", "pid=,command="], {
|
|
252
|
+
encoding: "utf8",
|
|
253
|
+
});
|
|
254
|
+
const pids = [];
|
|
255
|
+
for (const line of (out.stdout || "").split("\n")) {
|
|
256
|
+
const m = line.trim().match(/^(\d+)\s+(.*)$/);
|
|
257
|
+
if (!m) continue;
|
|
258
|
+
const pid = Number(m[1]);
|
|
259
|
+
if (pid === process.pid || pid === process.ppid) continue;
|
|
260
|
+
if (isWorkServerCmd(m[2])) pids.push(pid);
|
|
261
|
+
}
|
|
262
|
+
return pids;
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
function killPids(pids, signal) {
|
|
266
|
+
for (const pid of pids) {
|
|
267
|
+
try {
|
|
268
|
+
process.kill(pid, signal);
|
|
269
|
+
} catch {}
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
/** Stop the managed service *and* any leftover checkout / `work start`
|
|
274
|
+
* process still bound to the port. A pre-npm install often wasn't the
|
|
275
|
+
* current unit (or was a bare node), so restarting work.service left it
|
|
276
|
+
* sitting in front of the new one. */
|
|
277
|
+
function stopOldCopies(port) {
|
|
278
|
+
log("stopping any previous work server");
|
|
279
|
+
if (process.platform === "darwin") {
|
|
280
|
+
const uid = process.getuid();
|
|
281
|
+
spawnSync("launchctl", ["bootout", `gui/${uid}/dev.work.app`], {
|
|
282
|
+
stdio: "ignore",
|
|
283
|
+
});
|
|
284
|
+
const agents = path.join(os.homedir(), "Library/LaunchAgents");
|
|
285
|
+
try {
|
|
286
|
+
for (const name of fs.readdirSync(agents)) {
|
|
287
|
+
if (!name.endsWith(".plist")) continue;
|
|
288
|
+
const file = path.join(agents, name);
|
|
289
|
+
const text = fs.readFileSync(file, "utf8");
|
|
290
|
+
if (!/dev\.work\.app|work\.mjs|run-prod\.sh|@dylanpiercey\/work/.test(text))
|
|
291
|
+
continue;
|
|
292
|
+
const label = text.match(
|
|
293
|
+
/<key>Label<\/key>\s*<string>([^<]+)<\/string>/,
|
|
294
|
+
)?.[1];
|
|
295
|
+
if (label) {
|
|
296
|
+
spawnSync("launchctl", ["bootout", `gui/${uid}/${label}`], {
|
|
297
|
+
stdio: "ignore",
|
|
298
|
+
});
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
} catch {}
|
|
302
|
+
} else if (have("systemctl")) {
|
|
303
|
+
spawnSync("systemctl", ["--user", "stop", "work.service"], {
|
|
304
|
+
stdio: "ignore",
|
|
305
|
+
});
|
|
306
|
+
}
|
|
307
|
+
const seen = new Set([...pidsListening(port), ...workServerPids()]);
|
|
308
|
+
if (seen.size) {
|
|
309
|
+
log(`stopping ${seen.size} leftover work process(es)`);
|
|
310
|
+
killPids(seen, "SIGTERM");
|
|
311
|
+
spawnSync("sleep", ["0.4"], { stdio: "ignore" });
|
|
312
|
+
}
|
|
313
|
+
killPids(pidsListening(port), "SIGKILL");
|
|
314
|
+
}
|
|
315
|
+
|
|
211
316
|
function installService() {
|
|
317
|
+
const port = serviceEnv().PORT;
|
|
318
|
+
stopOldCopies(port);
|
|
212
319
|
const cliPath = fileURLToPath(import.meta.url);
|
|
213
320
|
if (process.platform === "darwin") {
|
|
214
321
|
const plist = serviceFile();
|