gm-skill 2.0.1781 → 2.0.1794
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/bootstrap.js +29 -0
- package/bin/plugkit.version +1 -1
- package/bin/plugkit.wasm.sha256 +1 -1
- package/gm-plugkit/bootstrap.js +28 -0
- package/gm-plugkit/package.json +1 -1
- package/gm-plugkit/plugkit-wasm-wrapper.js +48 -2
- package/gm-plugkit/plugkit.version +1 -1
- package/gm-plugkit/supervisor.js +30 -3
- package/gm.json +2 -2
- package/lib/skill-bootstrap.js +28 -1
- package/package.json +1 -1
package/bin/bootstrap.js
CHANGED
|
@@ -606,6 +606,29 @@ function writeDaemonVersion(v) {
|
|
|
606
606
|
try { fs.writeFileSync(daemonVersionSentinel(), String(v)); } catch (_) {}
|
|
607
607
|
}
|
|
608
608
|
|
|
609
|
+
function pidCommandLineForKillGuard(pid) {
|
|
610
|
+
try {
|
|
611
|
+
const { spawnSync } = require('child_process');
|
|
612
|
+
if (process.platform === 'win32') {
|
|
613
|
+
const r = spawnSync('powershell.exe', ['-NoProfile', '-NonInteractive', '-Command', `(Get-CimInstance Win32_Process -Filter "ProcessId=${Number(pid)}").CommandLine`], { encoding: 'utf8', windowsHide: true, timeout: 5000 });
|
|
614
|
+
return String((r && r.stdout) || '');
|
|
615
|
+
}
|
|
616
|
+
const r = spawnSync('ps', ['-p', String(pid), '-o', 'args='], { encoding: 'utf8', timeout: 5000 });
|
|
617
|
+
return String((r && r.stdout) || '');
|
|
618
|
+
} catch (_) { return ''; }
|
|
619
|
+
}
|
|
620
|
+
|
|
621
|
+
function pidIsPlugkitProcess(pid) {
|
|
622
|
+
return /plugkit-wasm-wrapper\.js|plugkit-supervisor\.js|gm-plugkit[\\\/]supervisor\.js/i.test(pidCommandLineForKillGuard(pid));
|
|
623
|
+
}
|
|
624
|
+
|
|
625
|
+
function writeKillAttribution(targetSpoolDir, info) {
|
|
626
|
+
try {
|
|
627
|
+
fs.mkdirSync(targetSpoolDir, { recursive: true });
|
|
628
|
+
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));
|
|
629
|
+
} catch (_) {}
|
|
630
|
+
}
|
|
631
|
+
|
|
609
632
|
function killPid(pid) {
|
|
610
633
|
if (!Number.isFinite(pid) || pid === process.pid || !pidAlive(pid)) return false;
|
|
611
634
|
try { process.kill(pid, 'SIGTERM'); }
|
|
@@ -624,6 +647,12 @@ function killSpoolWatcherInCwd(reason) {
|
|
|
624
647
|
const pidPath = path.join(process.cwd(), '.gm', 'exec-spool', '.watcher.pid');
|
|
625
648
|
if (!fs.existsSync(pidPath)) return null;
|
|
626
649
|
const pid = parseInt(fs.readFileSync(pidPath, 'utf8').trim(), 10);
|
|
650
|
+
if (pidAlive(pid) && !pidIsPlugkitProcess(pid)) {
|
|
651
|
+
obsEvent('bootstrap', 'watcher.kill-skipped-pid-reused', { pid, reason });
|
|
652
|
+
try { fs.unlinkSync(pidPath); } catch (_) {}
|
|
653
|
+
return null;
|
|
654
|
+
}
|
|
655
|
+
writeKillAttribution(path.join(process.cwd(), '.gm', 'exec-spool'), { reason, target_pid: pid, via: 'killSpoolWatcherInCwd' });
|
|
627
656
|
if (killPid(pid)) {
|
|
628
657
|
obsEvent('bootstrap', 'watcher.killed', { pid, reason });
|
|
629
658
|
try { fs.unlinkSync(pidPath); } catch (_) {}
|
package/bin/plugkit.version
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
0.1.
|
|
1
|
+
0.1.819
|
package/bin/plugkit.wasm.sha256
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
|
|
1
|
+
6a4cd71644fb10f35340c1bf17091eb671cef43246b98a36352935aafed0a41c plugkit.wasm
|
package/gm-plugkit/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/gm-plugkit/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "gm-plugkit",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.1794",
|
|
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": {
|
|
@@ -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 {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
0.1.
|
|
1
|
+
0.1.819
|
package/gm-plugkit/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 (_) {}
|
package/gm.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "gm",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.1794",
|
|
4
4
|
"description": "Spool-dispatch orchestration engine with unified state machine, skills, and automated git enforcement",
|
|
5
5
|
"author": "AnEntrypoint",
|
|
6
6
|
"license": "MIT",
|
|
@@ -17,5 +17,5 @@
|
|
|
17
17
|
"publishConfig": {
|
|
18
18
|
"access": "public"
|
|
19
19
|
},
|
|
20
|
-
"plugkitVersion": "0.1.
|
|
20
|
+
"plugkitVersion": "0.1.819"
|
|
21
21
|
}
|
package/lib/skill-bootstrap.js
CHANGED
|
@@ -406,6 +406,26 @@ function isProcessRunning() {
|
|
|
406
406
|
return findPlugkitWasmPids().length > 0;
|
|
407
407
|
}
|
|
408
408
|
|
|
409
|
+
function pidCommandLineForKillGuard(pid) {
|
|
410
|
+
try {
|
|
411
|
+
if (process.platform === 'win32') {
|
|
412
|
+
return execFileSync('powershell.exe', ['-NoProfile', '-NonInteractive', '-Command', `(Get-CimInstance Win32_Process -Filter "ProcessId=${Number(pid)}").CommandLine`], { encoding: 'utf8', windowsHide: true, timeout: 5000 }) || '';
|
|
413
|
+
}
|
|
414
|
+
return execFileSync('ps', ['-p', String(pid), '-o', 'args='], { encoding: 'utf8', timeout: 5000 }) || '';
|
|
415
|
+
} catch (_) { return ''; }
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
function pidIsPlugkitProcess(pid) {
|
|
419
|
+
return /plugkit-wasm-wrapper\.js|plugkit-supervisor\.js|gm-plugkit[\\\/]supervisor\.js/i.test(pidCommandLineForKillGuard(pid));
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
function writeKillAttribution(targetSpoolDir, info) {
|
|
423
|
+
try {
|
|
424
|
+
fs.mkdirSync(targetSpoolDir, { recursive: true });
|
|
425
|
+
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));
|
|
426
|
+
} catch (_) {}
|
|
427
|
+
}
|
|
428
|
+
|
|
409
429
|
function killExistingPlugkit() {
|
|
410
430
|
try {
|
|
411
431
|
const pids = findPlugkitWasmPids();
|
|
@@ -413,17 +433,24 @@ function killExistingPlugkit() {
|
|
|
413
433
|
emitBootstrapEvent('info', 'No existing plugkit WASM watcher to kill');
|
|
414
434
|
return;
|
|
415
435
|
}
|
|
436
|
+
const killed = [];
|
|
416
437
|
for (const pid of pids) {
|
|
438
|
+
if (!pidIsPlugkitProcess(pid)) {
|
|
439
|
+
emitBootstrapEvent('warn', 'Kill skipped: pid is not a plugkit process (stale or reused pid)', { pid });
|
|
440
|
+
continue;
|
|
441
|
+
}
|
|
442
|
+
writeKillAttribution(path.join(process.cwd(), '.gm', 'exec-spool'), { reason: 'bootstrap-refresh', target_pid: Number(pid), via: 'killExistingPlugkit' });
|
|
417
443
|
try {
|
|
418
444
|
if (process.platform === 'win32') {
|
|
419
445
|
execFileSync('taskkill', ['/F', '/T', '/PID', String(pid)], { stdio: 'ignore', windowsHide: true });
|
|
420
446
|
} else {
|
|
421
447
|
execFileSync('kill', ['-9', String(pid)], { stdio: 'ignore' });
|
|
422
448
|
}
|
|
449
|
+
killed.push(pid);
|
|
423
450
|
} catch (e) {
|
|
424
451
|
}
|
|
425
452
|
}
|
|
426
|
-
emitBootstrapEvent('info', 'Killed existing plugkit WASM watcher', { pids });
|
|
453
|
+
emitBootstrapEvent('info', 'Killed existing plugkit WASM watcher', { pids: killed });
|
|
427
454
|
} catch (e) {
|
|
428
455
|
emitBootstrapEvent('warn', 'Failed to kill existing plugkit', { error: e.message });
|
|
429
456
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "gm-skill",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.1794",
|
|
4
4
|
"description": "Canonical universal harness — AI-native software engineering via skill-driven orchestration; bootstraps plugkit for task execution and session isolation. Install in any AI coding agent host.",
|
|
5
5
|
"author": "AnEntrypoint",
|
|
6
6
|
"license": "MIT",
|