gm-plugkit 2.0.1544 → 2.0.1545

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/SKILL.md CHANGED
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: gm-skill
3
- description: Plugkit-served instruction stream. Three-layer admission (cost, bounds, direction) over every possible mutation. Closure on first emit; partial = non-monotonic.
3
+ description: Plugkit-served instruction stream. Three-layer admission (witness, single-writer, direction) over every possible mutation; effort unbounded, never gated on cost. Closure on first emit; partial = non-monotonic.
4
4
  allowed-tools: Skill, Read, Write, Bash(bun *), Bash(npx *)
5
5
  ---
6
6
 
package/bootstrap.js CHANGED
@@ -716,7 +716,8 @@ function ensureSkillMdFresh() {
716
716
  }
717
717
  const bundled = fs.readFileSync(bundledPath, 'utf-8');
718
718
  const crypto = require('crypto');
719
- const bundledHash = crypto.createHash('sha256').update(bundled).digest('hex');
719
+ const _norm = s => s.replace(/\r\n/g, '\n');
720
+ const bundledHash = crypto.createHash('sha256').update(_norm(bundled)).digest('hex');
720
721
  const home = process.env.HOME || process.env.USERPROFILE || require('os').homedir();
721
722
  const targets = [
722
723
  path.join(home, '.agents', 'skills', 'gm-skill', 'SKILL.md'),
@@ -728,7 +729,7 @@ function ensureSkillMdFresh() {
728
729
  let needsWrite = true;
729
730
  if (fs.existsSync(target)) {
730
731
  const existing = fs.readFileSync(target, 'utf-8');
731
- const existingHash = crypto.createHash('sha256').update(existing).digest('hex');
732
+ const existingHash = crypto.createHash('sha256').update(_norm(existing)).digest('hex');
732
733
  if (existingHash === bundledHash) needsWrite = false;
733
734
  }
734
735
  if (needsWrite) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gm-plugkit",
3
- "version": "2.0.1544",
3
+ "version": "2.0.1545",
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": {
@@ -2560,6 +2560,17 @@ async function runSpoolWatcher(instance, spoolDir) {
2560
2560
  setTimeout(probeGmPlugkitSelfStale, 5000);
2561
2561
  setInterval(probeGmPlugkitSelfStale, 300_000);
2562
2562
 
2563
+ // A supervised watcher self-exits on drift assuming the supervisor respawns it. If the
2564
+ // supervisor has died, that bare exit leaves the spool dead (worse than staying up). Treat a
2565
+ // dead/absent supervisor as unsupervised so the drift loops take the self-respawn-and-wait path
2566
+ // (spawn replacement, wait for its heartbeat, then exit) instead. False-negative is self-correcting:
2567
+ // if both the supervisor and this watcher respawn, the single-instance lock admits exactly one.
2568
+ function _supervisorIsDead() {
2569
+ try {
2570
+ const sp = parseInt(fs.readFileSync(path.join(spoolDir, '.supervisor.pid'), 'utf8').trim(), 10);
2571
+ return !(Number.isFinite(sp) && isProcessAliveSync(sp));
2572
+ } catch (_) { return true; }
2573
+ }
2563
2574
  const _instanceVersionAtBoot = readInstanceVersion(instance);
2564
2575
  let _driftLoggedOnce = false;
2565
2576
  setInterval(() => {
@@ -2568,7 +2579,7 @@ async function runSpoolWatcher(instance, spoolDir) {
2568
2579
  const instV = _instanceVersionAtBoot;
2569
2580
  if (!fileV || !instV || fileV === instV) return;
2570
2581
  const bootReason = process.env.PLUGKIT_BOOT_REASON || 'unknown';
2571
- const unsupervised = bootReason === 'direct-no-supervisor';
2582
+ const unsupervised = bootReason === 'direct-no-supervisor' || _supervisorIsDead();
2572
2583
  if (unsupervised) {
2573
2584
  if (_driftLoggedOnce) return;
2574
2585
  _driftLoggedOnce = true;
@@ -2665,7 +2676,7 @@ async function runSpoolWatcher(instance, spoolDir) {
2665
2676
  const cur = crypto.createHash('sha256').update(fs.readFileSync(_wrapperPathInstalled)).digest('hex');
2666
2677
  if (cur === _wrapperShaAtBoot) return;
2667
2678
  const bootReason = process.env.PLUGKIT_BOOT_REASON || 'unknown';
2668
- const unsupervised = bootReason === 'direct-no-supervisor';
2679
+ const unsupervised = bootReason === 'direct-no-supervisor' || _supervisorIsDead();
2669
2680
  if (unsupervised) {
2670
2681
  if (_wrapperDriftLoggedOnce) return;
2671
2682
  _wrapperDriftLoggedOnce = true;