gm-plugkit 2.0.1483 → 2.0.1485

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.1483",
3
+ "version": "2.0.1485",
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": {
@@ -2757,6 +2757,16 @@ async function runSpoolWatcher(instance, spoolDir) {
2757
2757
  const relPath = path.relative(inDir, filePath);
2758
2758
  const dir = path.dirname(relPath);
2759
2759
  const verb = dir === '.' ? path.basename(filePath, path.extname(filePath)) : dir;
2760
+ // Defense-in-depth beyond walkDir's dot-dir skip: a real verb is a single clean
2761
+ // segment (e.g. instruction, prd-resolve). A derived verb containing a path
2762
+ // separator or a dot-segment means the file lives under a stray nested spool
2763
+ // (in/prd-resolve/.gm/exec-spool/…); dispatching it builds a bogus verb+outName
2764
+ // and ENOENT-storms every tick. Skip + unmark so it never re-enters the loop.
2765
+ if (/[\\/]/.test(verb) || verb.split(/[\\/]/).some(seg => seg.startsWith('.'))) {
2766
+ try { logEvent('plugkit', 'spool.skip-nested-verb', { rel: relPath, derived_verb: verb }); } catch (_) {}
2767
+ unmarkProcessed(key);
2768
+ return;
2769
+ }
2760
2770
  let body = content.trim() || '{}';
2761
2771
  const taskBase = path.basename(filePath, path.extname(filePath));
2762
2772
 
@@ -2876,18 +2886,24 @@ async function runSpoolWatcher(instance, spoolDir) {
2876
2886
  }
2877
2887
  };
2878
2888
 
2879
- function walkDir(dir) {
2889
+ function walkDir(dir, depth = 0) {
2880
2890
  const files = [];
2881
2891
  try {
2882
2892
  for (const entry of fs.readdirSync(dir)) {
2883
2893
  if (/\.tmp\.\d+(\.|$)/.test(entry)) continue;
2894
+ // The verb tree is in/<verb>/[<sub>/]<N>.<ext> — at most two levels deep. A
2895
+ // dot-prefixed dir (e.g. a stray nested .gm/exec-spool/ created by a misfire)
2896
+ // is never a verb dir; recursing into it derives a bogus verb like
2897
+ // `prd-resolve\.gm\exec-spool` and dispatch-errors on every tick forever.
2898
+ // Skip dot-dirs and cap depth so a spool-inside-spool cannot wedge the watcher.
2899
+ if (entry.startsWith('.')) continue;
2884
2900
  const fullPath = path.join(dir, entry);
2885
2901
  let stat;
2886
2902
  try { stat = fs.statSync(fullPath); } catch (_) { continue; }
2887
2903
  if (stat.isFile()) {
2888
2904
  files.push(fullPath);
2889
- } else if (stat.isDirectory()) {
2890
- files.push(...walkDir(fullPath));
2905
+ } else if (stat.isDirectory() && depth < 2) {
2906
+ files.push(...walkDir(fullPath, depth + 1));
2891
2907
  }
2892
2908
  }
2893
2909
  } catch (e) {
@@ -3329,6 +3345,10 @@ async function runSpoolWatcher(instance, spoolDir) {
3329
3345
  watch(inDir, { recursive: true }, (eventType, filename) => {
3330
3346
  if (!filename) return;
3331
3347
  if (/\.tmp\.\d+(\.|$)/.test(filename)) return;
3348
+ // Skip any path with a dot-prefixed segment (e.g. a stray nested
3349
+ // prd-resolve/.gm/exec-spool/…): it is not a real verb dispatch and walking it
3350
+ // derives a bogus verb that dispatch-errors on every tick. Matches walkDir's guard.
3351
+ if (filename.split(/[\\/]/).some(seg => seg.startsWith('.'))) return;
3332
3352
  const fullPath = path.join(inDir, filename);
3333
3353
  markActivity('watch');
3334
3354