Initial commit of Descrybe v2 without local scratch artifacts.
Drop one-shot tmp/axe scripts and agent i18n scratch so the Gitea tree is deployable.
This commit is contained in:
@@ -0,0 +1,85 @@
|
||||
/**
|
||||
* Kill whatever is listening on the Descrybe dev ports so `npm run dev` can bind.
|
||||
* Skip when DESCRYBE_DEV_PORTS_FREED=1 (parent already freed; children must not
|
||||
* re-kill the just-started sibling).
|
||||
*
|
||||
* Usage: node scripts/free-dev-ports.mjs
|
||||
*/
|
||||
import { spawnSync } from "node:child_process";
|
||||
import { pathToFileURL } from "node:url";
|
||||
import { DEV_API_PORT, DEV_WEB_PORT } from "./dev-ports.mjs";
|
||||
|
||||
export function freeDevPorts(ports = [DEV_API_PORT, DEV_WEB_PORT]) {
|
||||
if (process.env.DESCRYBE_DEV_PORTS_FREED === "1") {
|
||||
return;
|
||||
}
|
||||
|
||||
for (const port of ports) {
|
||||
const pids = listenersOnPort(port);
|
||||
if (pids.length === 0) {
|
||||
console.log(`[dev-ports] ${port} free`);
|
||||
continue;
|
||||
}
|
||||
for (const pid of pids) {
|
||||
console.log(`[dev-ports] killing PID ${pid} on :${port}`);
|
||||
killPidTree(pid);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function listenersOnPort(port) {
|
||||
if (process.platform === "win32") {
|
||||
const ps = [
|
||||
`$conns = @(Get-NetTCPConnection -LocalPort ${port} -State Listen -ErrorAction SilentlyContinue);`,
|
||||
`if ($conns.Count -eq 0) { exit 0 };`,
|
||||
`$conns | ForEach-Object { $_.OwningProcess } | Sort-Object -Unique | ForEach-Object { Write-Output $_ }`,
|
||||
].join(" ");
|
||||
const r = spawnSync(
|
||||
"powershell.exe",
|
||||
["-NoProfile", "-NonInteractive", "-Command", ps],
|
||||
{ encoding: "utf8" },
|
||||
);
|
||||
return parsePids(r.stdout || "");
|
||||
}
|
||||
|
||||
const r = spawnSync("lsof", ["-tiTCP:" + port, "-sTCP:LISTEN"], {
|
||||
encoding: "utf8",
|
||||
});
|
||||
if (r.status !== 0) return [];
|
||||
return parsePids(r.stdout || "");
|
||||
}
|
||||
|
||||
function parsePids(text) {
|
||||
const seen = new Set();
|
||||
const out = [];
|
||||
for (const raw of text.split(/\r?\n/)) {
|
||||
const n = Number.parseInt(raw.trim(), 10);
|
||||
if (!Number.isFinite(n) || n <= 0 || seen.has(n)) continue;
|
||||
if (n === process.pid) continue;
|
||||
seen.add(n);
|
||||
out.push(n);
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
function killPidTree(pid) {
|
||||
if (process.platform === "win32") {
|
||||
spawnSync("taskkill.exe", ["/T", "/F", "/PID", String(pid)], {
|
||||
stdio: "ignore",
|
||||
});
|
||||
return;
|
||||
}
|
||||
try {
|
||||
process.kill(pid, "SIGKILL");
|
||||
} catch {
|
||||
/* already gone */
|
||||
}
|
||||
}
|
||||
|
||||
const isDirect =
|
||||
process.argv[1] &&
|
||||
import.meta.url === pathToFileURL(process.argv[1]).href;
|
||||
|
||||
if (isDirect) {
|
||||
freeDevPorts();
|
||||
}
|
||||
Reference in New Issue
Block a user