gm-plugkit 2.0.1794 → 2.0.1799

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gm-plugkit",
3
- "version": "2.0.1794",
3
+ "version": "2.0.1799",
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": {
@@ -89,6 +89,11 @@ function pidIsPlugkitProcess(pid) {
89
89
  return /plugkit-wasm-wrapper\.js|plugkit-supervisor\.js|gm-plugkit[\\\/]supervisor\.js/i.test(pidCommandLineForKillGuard(pid));
90
90
  }
91
91
 
92
+ function pidIsManagedChromium(pid) {
93
+ const cmd = pidCommandLineForKillGuard(pid).toLowerCase().replace(/\\/g, '/');
94
+ return cmd.includes('browser-profile') && cmd.includes('--remote-debugging-port');
95
+ }
96
+
92
97
  function writeKillAttribution(targetSpoolDir, info) {
93
98
  try {
94
99
  fs.mkdirSync(targetSpoolDir, { recursive: true });
@@ -1380,10 +1385,14 @@ function gracefulCloseBrowser(entry, reason) {
1380
1385
  } catch (_) {}
1381
1386
  }
1382
1387
  if (Number.isFinite(pid) && pid > 0) {
1383
- const deadline = Date.now() + 1500;
1384
- try { process.kill(pid, 'SIGTERM'); } catch (_) {}
1385
- while (Date.now() < deadline && isProcessAliveSync(pid)) sleepSyncMs(Math.min(150, deadline - Date.now()));
1386
- if (isProcessAliveSync(pid)) killPidQuiet(pid);
1388
+ if (isProcessAliveSync(pid) && !pidIsManagedChromium(pid)) {
1389
+ try { logEvent('plugkit', 'browser.kill-skipped-pid-reused', { pid, reason: reason || 'close' }); } catch (_) {}
1390
+ } else {
1391
+ const deadline = Date.now() + 1500;
1392
+ try { process.kill(pid, 'SIGTERM'); } catch (_) {}
1393
+ while (Date.now() < deadline && isProcessAliveSync(pid)) sleepSyncMs(Math.min(150, deadline - Date.now()));
1394
+ if (isProcessAliveSync(pid)) killPidQuiet(pid);
1395
+ }
1387
1396
  }
1388
1397
  purgeProfileLockFiles(profileDir);
1389
1398
  try { logEvent('plugkit', 'browser.closed', { reason: reason || 'closed', pid, port, profileDir }); } catch (_) {}
@@ -1450,7 +1459,11 @@ function resolveExistingBrowserEntry(cwd, claudeSessionId, pw, portsFile, sessio
1450
1459
  if (typeof gracefulCloseBrowser === 'function') {
1451
1460
  try { gracefulCloseBrowser(existing, `collision:${reason}`); } catch (_) {}
1452
1461
  } else if (pidOk && Number.isFinite(existing.pid)) {
1453
- try { killPidQuiet(existing.pid); } catch (_) {}
1462
+ if (pidIsManagedChromium(existing.pid)) {
1463
+ try { killPidQuiet(existing.pid); } catch (_) {}
1464
+ } else {
1465
+ try { logEvent('plugkit', 'browser.kill-skipped-pid-reused', { pid: existing.pid, reason: 'collision' }); } catch (_) {}
1466
+ }
1454
1467
  }
1455
1468
  purgeProfileLockFiles(existing.profileDir);
1456
1469
  delete ports[claudeSessionId];
@@ -4650,14 +4663,56 @@ async function selfHealFromGithubReleases() {
4650
4663
  });
4651
4664
  }
4652
4665
 
4666
+ function writeHealBusyStatus() {
4667
+ try {
4668
+ const spoolDir = spoolDirForSentinel();
4669
+ fs.mkdirSync(spoolDir, { recursive: true });
4670
+ fs.writeFileSync(path.join(spoolDir, '.status.json'), JSON.stringify({ pid: process.pid, ts: Date.now(), healing: true, busy_until: Date.now() + 60_000 }));
4671
+ } catch (_) {}
4672
+ }
4673
+
4674
+ function restoreWasmFromLocalCache() {
4675
+ try {
4676
+ const root = path.join(process.env.LOCALAPPDATA || path.join(os.homedir(), '.cache'), 'plugkit', 'bin');
4677
+ const dirs = fs.readdirSync(root).filter(d => /^v\d+\.\d+\.\d+$/.test(d));
4678
+ dirs.sort((a, b) => {
4679
+ const pa = a.slice(1).split('.').map(Number), pb = b.slice(1).split('.').map(Number);
4680
+ return (pb[0] - pa[0]) || (pb[1] - pa[1]) || (pb[2] - pa[2]);
4681
+ });
4682
+ for (const d of dirs) {
4683
+ const wasm = path.join(root, d, 'plugkit.wasm');
4684
+ if (!fs.existsSync(wasm) || !fs.existsSync(path.join(root, d, '.ok'))) continue;
4685
+ const target = path.join(GM_TOOLS_ROOT, 'plugkit.wasm');
4686
+ const tmp = `${target}.partial-${process.pid}`;
4687
+ fs.copyFileSync(wasm, tmp);
4688
+ try { fs.renameSync(tmp, target); }
4689
+ catch (_) { try { fs.unlinkSync(target); } catch (_) {} fs.renameSync(tmp, target); }
4690
+ fs.writeFileSync(path.join(GM_TOOLS_ROOT, 'plugkit.version'), d.slice(1));
4691
+ return d.slice(1);
4692
+ }
4693
+ } catch (_) {}
4694
+ return null;
4695
+ }
4696
+
4653
4697
  async function selfHeal(reason) {
4654
4698
  console.error(`[plugkit-wasm] self-heal: ${reason}`);
4699
+ writeHealBusyStatus();
4700
+ const healBusy = setInterval(writeHealBusyStatus, 5000);
4655
4701
  try {
4702
+ if (/not installed/.test(reason)) {
4703
+ const restored = restoreWasmFromLocalCache();
4704
+ if (restored) {
4705
+ console.error(`[plugkit-wasm] self-heal: restored v${restored} from local install cache`);
4706
+ return true;
4707
+ }
4708
+ }
4656
4709
  const r = await selfHealFromGithubReleases();
4657
4710
  console.error(`[plugkit-wasm] self-heal: installed v${r.version} from GH Releases`);
4658
4711
  return true;
4659
4712
  } catch (e) {
4660
4713
  console.error(`[plugkit-wasm] self-heal GH fetch failed: ${e.message}`);
4714
+ } finally {
4715
+ clearInterval(healBusy);
4661
4716
  }
4662
4717
  console.error('[plugkit-wasm] self-heal: run `bun x gm-plugkit@latest spool` to recover manually');
4663
4718
  return false;
package/plugkit.version CHANGED
@@ -1 +1 @@
1
- 0.1.819
1
+ 0.1.823