shraga 0.1.84 → 0.1.85
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/package.json +1 -1
- package/src/server/port-reclaim.ts +13 -2
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "shraga",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.85",
|
|
4
4
|
"description": "The teammate you delegate coding to — a self-hostable, multi-user AI coding agent web UI (Claude Code, with a pluggable engine seam).",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./src/index.ts",
|
|
@@ -20,7 +20,12 @@ export function reclaimStalePort(port: number, opts: { entrypoint?: string; cwd?
|
|
|
20
20
|
const cwd = opts.cwd ?? process.cwd();
|
|
21
21
|
const grace = opts.termGraceMs ?? 5000;
|
|
22
22
|
|
|
23
|
-
|
|
23
|
+
// Any state, not just LISTEN: an orphan that closed its listener inside a drain it never finished
|
|
24
|
+
// still OWNS the socket, and looking only for LISTEN made it invisible while it blocked every
|
|
25
|
+
// replacement (feedox 2026-09-06: ppid-1 orphan, listener closed, port held for six minutes and
|
|
26
|
+
// counting). `isStaleSelf` is what keeps this narrow — a bystander is never a candidate.
|
|
27
|
+
const holders = [...new Set([...listeners(port), ...portUsers(port)])]
|
|
28
|
+
.filter((pid) => pid !== process.pid && isStaleSelf(pid, entrypoint, cwd));
|
|
24
29
|
if (!holders.length) return false;
|
|
25
30
|
|
|
26
31
|
for (const pid of holders) {
|
|
@@ -32,11 +37,17 @@ export function reclaimStalePort(port: number, opts: { entrypoint?: string; cwd?
|
|
|
32
37
|
waitGone(pid, 2000);
|
|
33
38
|
}
|
|
34
39
|
}
|
|
35
|
-
const free = listeners(port).filter((pid) => pid !== process.pid).length === 0;
|
|
40
|
+
const free = [...new Set([...listeners(port), ...portUsers(port)])].filter((pid) => pid !== process.pid).length === 0;
|
|
36
41
|
console.warn(`[server] port ${port} ${free ? 'reclaimed' : 'STILL held after reclaim'}`);
|
|
37
42
|
return free;
|
|
38
43
|
}
|
|
39
44
|
|
|
45
|
+
/** Every process holding the port in ANY socket state (a half-closed orphan included). */
|
|
46
|
+
function portUsers(port: number): number[] {
|
|
47
|
+
return sh('lsof', ['-ti', `tcp:${port}`])
|
|
48
|
+
.split('\n').map((l) => Number(l.trim())).filter((n) => Number.isInteger(n) && n > 0);
|
|
49
|
+
}
|
|
50
|
+
|
|
40
51
|
function listeners(port: number): number[] {
|
|
41
52
|
return sh('lsof', ['-ti', `tcp:${port}`, '-sTCP:LISTEN'])
|
|
42
53
|
.split('\n').map((l) => Number(l.trim())).filter((n) => Number.isInteger(n) && n > 0);
|