gm-plugkit 2.0.1779 → 2.0.1793
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/bootstrap.js +28 -0
- package/package.json +1 -1
- package/plugkit-wasm-wrapper.js +48 -2
- package/plugkit.version +1 -1
- package/supervisor.js +30 -3
package/bootstrap.js
CHANGED
|
@@ -450,6 +450,28 @@ function writeDaemonVersion(v) {
|
|
|
450
450
|
try { fs.writeFileSync(daemonVersionSentinel(), String(v)); } catch (_) {}
|
|
451
451
|
}
|
|
452
452
|
|
|
453
|
+
function pidCommandLineForKillGuard(pid) {
|
|
454
|
+
try {
|
|
455
|
+
if (process.platform === 'win32') {
|
|
456
|
+
const r = spawnSync('powershell.exe', ['-NoProfile', '-NonInteractive', '-Command', `(Get-CimInstance Win32_Process -Filter "ProcessId=${Number(pid)}").CommandLine`], { encoding: 'utf8', windowsHide: true, timeout: 5000 });
|
|
457
|
+
return String((r && r.stdout) || '');
|
|
458
|
+
}
|
|
459
|
+
const r = spawnSync('ps', ['-p', String(pid), '-o', 'args='], { encoding: 'utf8', timeout: 5000 });
|
|
460
|
+
return String((r && r.stdout) || '');
|
|
461
|
+
} catch (_) { return ''; }
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
function pidIsPlugkitProcess(pid) {
|
|
465
|
+
return /plugkit-wasm-wrapper\.js|plugkit-supervisor\.js|gm-plugkit[\\\/]supervisor\.js/i.test(pidCommandLineForKillGuard(pid));
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
function writeKillAttribution(targetSpoolDir, info) {
|
|
469
|
+
try {
|
|
470
|
+
fs.mkdirSync(targetSpoolDir, { recursive: true });
|
|
471
|
+
fs.writeFileSync(path.join(targetSpoolDir, '.kill-attribution.json'), JSON.stringify({ killer_pid: process.pid, killer_cwd: process.cwd(), killer_script: __filename, ts: Date.now(), ...info }, null, 2));
|
|
472
|
+
} catch (_) {}
|
|
473
|
+
}
|
|
474
|
+
|
|
453
475
|
function killPid(pid) {
|
|
454
476
|
if (!Number.isFinite(pid) || pid === process.pid || !pidAlive(pid)) return false;
|
|
455
477
|
try { process.kill(pid, 'SIGTERM'); }
|
|
@@ -465,6 +487,12 @@ function killSpoolWatcherInCwd(reason) {
|
|
|
465
487
|
const pidPath = path.join(process.cwd(), '.gm', 'exec-spool', '.watcher.pid');
|
|
466
488
|
if (!fs.existsSync(pidPath)) return null;
|
|
467
489
|
const pid = parseInt(fs.readFileSync(pidPath, 'utf8').trim(), 10);
|
|
490
|
+
if (pidAlive(pid) && !pidIsPlugkitProcess(pid)) {
|
|
491
|
+
obsEvent('bootstrap', 'watcher.kill-skipped-pid-reused', { pid, reason });
|
|
492
|
+
try { fs.unlinkSync(pidPath); } catch (_) {}
|
|
493
|
+
return null;
|
|
494
|
+
}
|
|
495
|
+
writeKillAttribution(path.join(process.cwd(), '.gm', 'exec-spool'), { reason, target_pid: pid, via: 'killSpoolWatcherInCwd' });
|
|
468
496
|
if (killPid(pid)) {
|
|
469
497
|
obsEvent('bootstrap', 'watcher.killed', { pid, reason });
|
|
470
498
|
try { fs.unlinkSync(pidPath); } catch (_) {}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "gm-plugkit",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.1793",
|
|
4
4
|
"description": "Bootstrap and daemon-spawn tool for gm plugkit binary. Downloads the correct platform binary, verifies SHA256, and starts the spool watcher daemon. Includes plugkit-wasm-wrapper for WASM-based spool watching.",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"bin": {
|
package/plugkit-wasm-wrapper.js
CHANGED
|
@@ -74,6 +74,28 @@ function emitShutdownReason(reason, err) {
|
|
|
74
74
|
} catch (_) {}
|
|
75
75
|
}
|
|
76
76
|
|
|
77
|
+
function pidCommandLineForKillGuard(pid) {
|
|
78
|
+
try {
|
|
79
|
+
if (process.platform === 'win32') {
|
|
80
|
+
const r = spawnSync('powershell.exe', ['-NoProfile', '-NonInteractive', '-Command', `(Get-CimInstance Win32_Process -Filter "ProcessId=${Number(pid)}").CommandLine`], { encoding: 'utf8', windowsHide: true, timeout: 5000 });
|
|
81
|
+
return String((r && r.stdout) || '');
|
|
82
|
+
}
|
|
83
|
+
const r = spawnSync('ps', ['-p', String(pid), '-o', 'args='], { encoding: 'utf8', timeout: 5000 });
|
|
84
|
+
return String((r && r.stdout) || '');
|
|
85
|
+
} catch (_) { return ''; }
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
function pidIsPlugkitProcess(pid) {
|
|
89
|
+
return /plugkit-wasm-wrapper\.js|plugkit-supervisor\.js|gm-plugkit[\\\/]supervisor\.js/i.test(pidCommandLineForKillGuard(pid));
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
function writeKillAttribution(targetSpoolDir, info) {
|
|
93
|
+
try {
|
|
94
|
+
fs.mkdirSync(targetSpoolDir, { recursive: true });
|
|
95
|
+
fs.writeFileSync(path.join(targetSpoolDir, '.kill-attribution.json'), JSON.stringify({ killer_pid: process.pid, killer_cwd: process.cwd(), killer_script: 'plugkit-wasm-wrapper', ts: Date.now(), ...info }, null, 2));
|
|
96
|
+
} catch (_) {}
|
|
97
|
+
}
|
|
98
|
+
|
|
77
99
|
function writeVerbActive(verb, task) {
|
|
78
100
|
__currentVerbContext = { verb, task, started_at_ms: Date.now(), pid: process.pid };
|
|
79
101
|
try {
|
|
@@ -1558,7 +1580,8 @@ function cosineSim(a, b) {
|
|
|
1558
1580
|
}
|
|
1559
1581
|
|
|
1560
1582
|
let __wasmAbortFlag = { aborted: false, code: 0 };
|
|
1561
|
-
const
|
|
1583
|
+
const WASI_PROJECT_SLUG = crypto.createHash('sha256').update(String(process.env.CLAUDE_PROJECT_DIR || process.cwd()).toLowerCase().replace(/\\/g, '/')).digest('hex').slice(0, 16);
|
|
1584
|
+
const WASI_FILESYSTEM_ROOT = path.join(GM_TOOLS_ROOT, 'wasi-fs', WASI_PROJECT_SLUG);
|
|
1562
1585
|
const wasiOpenFiles = new Map();
|
|
1563
1586
|
let wasiNextFd = 100;
|
|
1564
1587
|
|
|
@@ -2256,6 +2279,19 @@ function makeHostFunctions(instanceRef) {
|
|
|
2256
2279
|
}
|
|
2257
2280
|
},
|
|
2258
2281
|
|
|
2282
|
+
host_fs_remove: (pathPtr, pathLen) => {
|
|
2283
|
+
try {
|
|
2284
|
+
const filePath = readWasmStr(instanceRef.value, pathPtr, pathLen);
|
|
2285
|
+
if (!filePath) return 0;
|
|
2286
|
+
const st = fs.statSync(filePath);
|
|
2287
|
+
if (st.isDirectory()) return 0;
|
|
2288
|
+
fs.unlinkSync(filePath);
|
|
2289
|
+
return 1;
|
|
2290
|
+
} catch (e) {
|
|
2291
|
+
return 0;
|
|
2292
|
+
}
|
|
2293
|
+
},
|
|
2294
|
+
|
|
2259
2295
|
host_fs_readdir: (pathPtr, pathLen) => {
|
|
2260
2296
|
try {
|
|
2261
2297
|
const dirPath = readWasmStr(instanceRef.value, pathPtr, pathLen);
|
|
@@ -3038,7 +3074,12 @@ async function runSpoolWatcher(instance, spoolDir) {
|
|
|
3038
3074
|
holder_sha: holderSha,
|
|
3039
3075
|
}));
|
|
3040
3076
|
} catch (_) {}
|
|
3041
|
-
|
|
3077
|
+
if (pidIsPlugkitProcess(holderPidNum)) {
|
|
3078
|
+
writeKillAttribution(spoolDir, { reason: 'peer-stale-takeover', target_pid: holderPidNum, via: 'lock-takeover', holder_sha: holderSha });
|
|
3079
|
+
try { process.kill(holderPidNum, 'SIGTERM'); } catch (_) {}
|
|
3080
|
+
} else {
|
|
3081
|
+
try { logEvent('plugkit', 'takeover-kill-skipped-pid-reused', { holder_pid: pidStr }); } catch (_) {}
|
|
3082
|
+
}
|
|
3042
3083
|
return 'takeover';
|
|
3043
3084
|
} else {
|
|
3044
3085
|
const msg = JSON.stringify({ ok: false, reason: 'another-watcher-active', pid: pidStr, age_ms: age });
|
|
@@ -3249,6 +3290,11 @@ async function runSpoolWatcher(instance, spoolDir) {
|
|
|
3249
3290
|
try {
|
|
3250
3291
|
process.kill(peerPid, 0);
|
|
3251
3292
|
} catch (_) { continue; }
|
|
3293
|
+
if (!pidIsPlugkitProcess(peerPid)) {
|
|
3294
|
+
logEvent('plugkit', 'peer.kill-skipped-pid-reused', { peer_cwd: peerCwd, peer_pid: peerPid });
|
|
3295
|
+
continue;
|
|
3296
|
+
}
|
|
3297
|
+
writeKillAttribution(path.join(peerCwd, '.gm', 'exec-spool'), { reason: 'peer-stale-takeover', target_pid: peerPid, via: 'peer-sweep', peer_sha: peerSha, own_sha: _ownWrapperSha12 });
|
|
3252
3298
|
logEvent('plugkit', 'peer.stale-wrapper-killed', { peer_cwd: peerCwd, peer_pid: peerPid, peer_sha: peerSha, own_sha: _ownWrapperSha12, lock_age_ms: age });
|
|
3253
3299
|
console.error(`[plugkit-wasm] peer-sweep killing stale-wrapper watcher pid=${peerPid} cwd=${peerCwd} sha=${peerSha} (own=${_ownWrapperSha12})`);
|
|
3254
3300
|
try {
|
package/plugkit.version
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
0.1.
|
|
1
|
+
0.1.818
|
package/supervisor.js
CHANGED
|
@@ -64,6 +64,28 @@ function writeSupervisorStatus(state, extra) {
|
|
|
64
64
|
} catch (_) {}
|
|
65
65
|
}
|
|
66
66
|
|
|
67
|
+
function pidCommandLineForKillGuard(pid) {
|
|
68
|
+
try {
|
|
69
|
+
if (process.platform === 'win32') {
|
|
70
|
+
const r = spawnSync('powershell.exe', ['-NoProfile', '-NonInteractive', '-Command', `(Get-CimInstance Win32_Process -Filter "ProcessId=${Number(pid)}").CommandLine`], { encoding: 'utf8', windowsHide: true, timeout: 5000 });
|
|
71
|
+
return String((r && r.stdout) || '');
|
|
72
|
+
}
|
|
73
|
+
const r = spawnSync('ps', ['-p', String(pid), '-o', 'args='], { encoding: 'utf8', timeout: 5000 });
|
|
74
|
+
return String((r && r.stdout) || '');
|
|
75
|
+
} catch (_) { return ''; }
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
function pidIsPlugkitProcess(pid) {
|
|
79
|
+
return /plugkit-wasm-wrapper\.js|plugkit-supervisor\.js|gm-plugkit[\\\/]supervisor\.js/i.test(pidCommandLineForKillGuard(pid));
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
function writeKillAttribution(targetSpoolDir, info) {
|
|
83
|
+
try {
|
|
84
|
+
fs.mkdirSync(targetSpoolDir, { recursive: true });
|
|
85
|
+
fs.writeFileSync(path.join(targetSpoolDir, '.kill-attribution.json'), JSON.stringify({ killer_pid: process.pid, killer_cwd: process.cwd(), killer_script: __filename, ts: Date.now(), ...info }, null, 2));
|
|
86
|
+
} catch (_) {}
|
|
87
|
+
}
|
|
88
|
+
|
|
67
89
|
function pidAlive(pid) {
|
|
68
90
|
if (!Number.isFinite(pid) || pid <= 0) return false;
|
|
69
91
|
try { process.kill(pid, 0); return true; } catch (_) { return false; }
|
|
@@ -100,9 +122,14 @@ function acquireSingleInstance() {
|
|
|
100
122
|
spool_status_age_ms: now - spoolTs,
|
|
101
123
|
severity: 'critical',
|
|
102
124
|
});
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
try {
|
|
125
|
+
if (pidIsPlugkitProcess(other)) {
|
|
126
|
+
writeKillAttribution(spoolDir, { reason: 'supervisor-takeover-wedged', target_pid: other, via: 'supervisor-duel' });
|
|
127
|
+
try { process.kill(other, 'SIGTERM'); } catch (_) {}
|
|
128
|
+
if (process.platform === 'win32') {
|
|
129
|
+
try { spawnSync('taskkill', ['/F', '/T', '/PID', String(other)], { stdio: 'ignore', windowsHide: true, timeout: 3000 }); } catch (_) {}
|
|
130
|
+
}
|
|
131
|
+
} else {
|
|
132
|
+
logEvent('supervisor.takeover-kill-skipped-pid-reused', { existing_pid: other, severity: 'warn' });
|
|
106
133
|
}
|
|
107
134
|
}
|
|
108
135
|
try { fs.unlinkSync(SUPERVISOR_PID_PATH); } catch (_) {}
|