gm-plugkit 2.0.1952 → 2.0.1954

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.1952",
3
+ "version": "2.0.1954",
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": {
@@ -3507,6 +3507,26 @@ async function runSpoolWatcher(instance, spoolDir) {
3507
3507
  fs.mkdirSync(inDir, { recursive: true });
3508
3508
  fs.mkdirSync(outDir, { recursive: true });
3509
3509
 
3510
+ // A heartbeat must exist BEFORE any boot step that can block for a while (the
3511
+ // browser-runner orphan reaps below shell out to `bun x playwriter@latest`, a
3512
+ // network-bound resolution that can run long under real network degradation).
3513
+ // The full writeStatus/_writeStatusBusy pair is defined ~1000 lines later in
3514
+ // this function (it needs _bootReason/_supervisorPid/_instanceVersionAtBoot/
3515
+ // IDLE_LIMIT_MS, all assigned further down) -- calling _writeStatusBusy from
3516
+ // runBrowserRunner during these early reaps was a no-op (undefined) until that
3517
+ // point, so the supervisor's heartbeat-stale check (30s, no busy_until to
3518
+ // shield it) killed the watcher every ~10s before it ever wrote a real status,
3519
+ // an unrecoverable respawn loop. Write a minimal, dependency-free heartbeat with
3520
+ // a busy window up front (real writeStatus() overwrites it correctly once its
3521
+ // dependencies exist) so the supervisor sees genuine liveness immediately.
3522
+ try {
3523
+ fs.writeFileSync(path.join(spoolDir, '.status.json'), JSON.stringify({
3524
+ pid: process.pid,
3525
+ ts: Date.now(),
3526
+ busy_until: Date.now() + 60000,
3527
+ }));
3528
+ } catch (_) {}
3529
+
3510
3530
  try {
3511
3531
  const gmDir = path.dirname(spoolDir);
3512
3532
  fs.writeFileSync(path.join(gmDir, 'last-instruction-ts'), String(Date.now()));
@@ -4672,7 +4692,7 @@ async function runSpoolWatcher(instance, spoolDir) {
4672
4692
  setInterval(() => { try { scanStalledTurns(); } catch (_) {} }, 30000);
4673
4693
  writeStatus();
4674
4694
 
4675
- setTimeout(() => {
4695
+ setTimeout(async () => {
4676
4696
  try {
4677
4697
  // The boot warmup's codesearch triggers a codeinsight reindex + full
4678
4698
  // in-wasm embed of the project when the stored digest is absent/stale.
@@ -4718,6 +4738,7 @@ async function runSpoolWatcher(instance, spoolDir) {
4718
4738
  if (deferred === 0) break;
4719
4739
  if (deferred === lastDeferred) { stagnant++; if (stagnant >= 4) break; } else { stagnant = 0; }
4720
4740
  lastDeferred = deferred;
4741
+ await new Promise((r) => setImmediate(r));
4721
4742
  }
4722
4743
  writeStatus();
4723
4744
  logEvent('plugkit', 'boot.index-warmup', { ms: Date.now() - t0, passes, converged: lastDeferred === -1 || lastDeferred === 0 });