shadok-ai 0.3.111 → 0.4.0
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/dist/lock.d.ts +23 -3
- package/dist/lock.js +38 -5
- package/dist/lock.js.map +1 -1
- package/package.json +1 -1
package/dist/lock.d.ts
CHANGED
|
@@ -9,14 +9,34 @@
|
|
|
9
9
|
*/
|
|
10
10
|
/** The lock file for the instance launched in `cwd` (default: process.cwd()). */
|
|
11
11
|
export declare function instanceLockPath(cwd?: string): string;
|
|
12
|
-
/**
|
|
13
|
-
|
|
12
|
+
/**
|
|
13
|
+
* Pure: the process state letter from a `/proc/<pid>/stat` line, or null when
|
|
14
|
+
* the line is unusable.
|
|
15
|
+
*
|
|
16
|
+
* Read from the LAST `)`: the second field is the command name, parenthesised
|
|
17
|
+
* and arbitrary, so it may itself contain spaces and brackets. Splitting from
|
|
18
|
+
* the left mis-parses every process whose name has one.
|
|
19
|
+
*/
|
|
20
|
+
export declare function stateFromProcStat(contents: string): string | null;
|
|
21
|
+
/** How `pidAlive` looks a process up; injected in tests. */
|
|
22
|
+
export type ProcStatReader = (pid: number) => string | null;
|
|
23
|
+
/**
|
|
24
|
+
* Whether a process with `pid` is currently running.
|
|
25
|
+
*
|
|
26
|
+
* A **zombie** answers signal 0: it has exited, but nobody has reaped it, so
|
|
27
|
+
* its pid entry survives. That is the normal case in a container, where pid 1
|
|
28
|
+
* is the application rather than an init that reaps — so a stopped instance
|
|
29
|
+
* held its launch directory's lock forever, and every later start was refused
|
|
30
|
+
* while naming a pid that no longer existed. `/proc` is Linux-only; where it is
|
|
31
|
+
* absent the signal's answer stands.
|
|
32
|
+
*/
|
|
33
|
+
export declare function pidAlive(pid: number, procStat?: ProcStatReader): boolean;
|
|
14
34
|
/**
|
|
15
35
|
* Try to become the single instance for this launch dir. Returns { ok: true }
|
|
16
36
|
* when the lock is held, or { ok: false, pid } when a LIVE instance already
|
|
17
37
|
* holds it. A stale lock (dead holder) is reclaimed.
|
|
18
38
|
*/
|
|
19
|
-
export declare function acquireInstanceLock(lockPath?: string): {
|
|
39
|
+
export declare function acquireInstanceLock(lockPath?: string, procStat?: ProcStatReader): {
|
|
20
40
|
ok: true;
|
|
21
41
|
} | {
|
|
22
42
|
ok: false;
|
package/dist/lock.js
CHANGED
|
@@ -15,24 +15,57 @@ export function instanceLockPath(cwd = process.cwd()) {
|
|
|
15
15
|
const enc = cwd.replace(/[^a-zA-Z0-9]/g, "-");
|
|
16
16
|
return path.join(os.homedir(), ".shadok-ai", "locks", enc + ".lock");
|
|
17
17
|
}
|
|
18
|
-
/**
|
|
19
|
-
|
|
18
|
+
/**
|
|
19
|
+
* Pure: the process state letter from a `/proc/<pid>/stat` line, or null when
|
|
20
|
+
* the line is unusable.
|
|
21
|
+
*
|
|
22
|
+
* Read from the LAST `)`: the second field is the command name, parenthesised
|
|
23
|
+
* and arbitrary, so it may itself contain spaces and brackets. Splitting from
|
|
24
|
+
* the left mis-parses every process whose name has one.
|
|
25
|
+
*/
|
|
26
|
+
export function stateFromProcStat(contents) {
|
|
27
|
+
const close = contents.lastIndexOf(")");
|
|
28
|
+
if (close < 0)
|
|
29
|
+
return null;
|
|
30
|
+
const [state] = contents.slice(close + 1).trim().split(/\s+/);
|
|
31
|
+
return state || null;
|
|
32
|
+
}
|
|
33
|
+
const readProcStat = (pid) => {
|
|
34
|
+
try {
|
|
35
|
+
return fs.readFileSync(`/proc/${pid}/stat`, "utf8");
|
|
36
|
+
}
|
|
37
|
+
catch {
|
|
38
|
+
return null; // no /proc (macOS), or the process just vanished
|
|
39
|
+
}
|
|
40
|
+
};
|
|
41
|
+
/**
|
|
42
|
+
* Whether a process with `pid` is currently running.
|
|
43
|
+
*
|
|
44
|
+
* A **zombie** answers signal 0: it has exited, but nobody has reaped it, so
|
|
45
|
+
* its pid entry survives. That is the normal case in a container, where pid 1
|
|
46
|
+
* is the application rather than an init that reaps — so a stopped instance
|
|
47
|
+
* held its launch directory's lock forever, and every later start was refused
|
|
48
|
+
* while naming a pid that no longer existed. `/proc` is Linux-only; where it is
|
|
49
|
+
* absent the signal's answer stands.
|
|
50
|
+
*/
|
|
51
|
+
export function pidAlive(pid, procStat = readProcStat) {
|
|
20
52
|
if (!pid || pid <= 0)
|
|
21
53
|
return false;
|
|
22
54
|
try {
|
|
23
55
|
process.kill(pid, 0); // signal 0 = existence check, doesn't kill
|
|
24
|
-
return true;
|
|
25
56
|
}
|
|
26
57
|
catch (e) {
|
|
27
58
|
return e?.code === "EPERM"; // exists but owned by another user → still alive
|
|
28
59
|
}
|
|
60
|
+
const stat = procStat(pid);
|
|
61
|
+
return stat === null ? true : stateFromProcStat(stat) !== "Z";
|
|
29
62
|
}
|
|
30
63
|
/**
|
|
31
64
|
* Try to become the single instance for this launch dir. Returns { ok: true }
|
|
32
65
|
* when the lock is held, or { ok: false, pid } when a LIVE instance already
|
|
33
66
|
* holds it. A stale lock (dead holder) is reclaimed.
|
|
34
67
|
*/
|
|
35
|
-
export function acquireInstanceLock(lockPath = instanceLockPath()) {
|
|
68
|
+
export function acquireInstanceLock(lockPath = instanceLockPath(), procStat = readProcStat) {
|
|
36
69
|
fs.mkdirSync(path.dirname(lockPath), { recursive: true });
|
|
37
70
|
for (let i = 0; i < 3; i++) {
|
|
38
71
|
try {
|
|
@@ -49,7 +82,7 @@ export function acquireInstanceLock(lockPath = instanceLockPath()) {
|
|
|
49
82
|
pid = parseInt(fs.readFileSync(lockPath, "utf8").trim(), 10) || 0;
|
|
50
83
|
}
|
|
51
84
|
catch { /* unreadable */ }
|
|
52
|
-
if (pid && pid !== process.pid && pidAlive(pid))
|
|
85
|
+
if (pid && pid !== process.pid && pidAlive(pid, procStat))
|
|
53
86
|
return { ok: false, pid };
|
|
54
87
|
try {
|
|
55
88
|
fs.rmSync(lockPath);
|
package/dist/lock.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"lock.js","sourceRoot":"","sources":["../src/lock.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,WAAW,CAAC;AAE7B;;;;;;;;GAQG;AAEH,iFAAiF;AACjF,MAAM,UAAU,gBAAgB,CAAC,GAAG,GAAG,OAAO,CAAC,GAAG,EAAE;IAClD,MAAM,GAAG,GAAG,GAAG,CAAC,OAAO,CAAC,eAAe,EAAE,GAAG,CAAC,CAAC;IAC9C,OAAO,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,EAAE,YAAY,EAAE,OAAO,EAAE,GAAG,GAAG,OAAO,CAAC,CAAC;AACvE,CAAC;AAED,
|
|
1
|
+
{"version":3,"file":"lock.js","sourceRoot":"","sources":["../src/lock.ts"],"names":[],"mappings":"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"}
|