grepmax 0.26.63 → 0.26.64

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.
@@ -10,7 +10,7 @@
10
10
  "name": "grepmax",
11
11
  "source": "./plugins/grepmax",
12
12
  "description": "Semantic code search for Claude Code. Automatically indexes your project and provides intelligent search capabilities.",
13
- "version": "0.26.63",
13
+ "version": "0.26.64",
14
14
  "author": {
15
15
  "name": "Robert Owens",
16
16
  "email": "robowens@me.com"
package/README.md CHANGED
@@ -240,7 +240,7 @@ gmax status # See all projects + watcher status
240
240
 
241
241
  Adding or indexing a project can start the daemon automatically. MCP acquires primary-project watch leases lazily when an index-reading tool is used; discovery and catalog listing start no background work. It shuts down after 4 hours of inactivity, and hands off to a fresh daemon after 24 hours or once its memory footprint passes 2.5 GB. File-change batches are processed on up to four worker processes by default, added only when work backs up, with one kept free for searches; full-table compaction and new FTS/ANN index builds are disabled by containment. Existing indexes remain readable. Host safety stops persist across restart and block heavy operations.
242
242
 
243
- `gmax watch status` reports failed files, native watcher recovery or polling, dropped-event counts, and the last complete filesystem reconciliation. Polling scans run every five minutes, so recent edits can lag. Search and MCP responses retain health warnings even after the file queue drains. A complete reconciliation means the filesystem scan completed; queued embedding work can still be pending.
243
+ `gmax watch status` reports failed files, native watcher recovery or polling, dropped-event counts, and the last complete filesystem reconciliation. FSEvents dropped-event warnings keep the native stream attached and preserve the accompanying events. A reconciliation covers the gap; repeated warnings coalesce into one later scan, with a 30-second scan interval. Recovery stays visible until a complete scan covers the latest gap. Other backend errors still trigger subscription recovery; repeated terminal failures fall back to five-minute polling, where recent edits can lag. Search and MCP responses retain health warnings even after the file queue drains. A complete reconciliation means the filesystem scan completed; queued embedding work can still be pending.
244
244
 
245
245
  Live filesystem edits take priority over background catchup and cleanup. Background batches dispatch one file at a time, with at most four catchup files or 50 cleanup paths. They yield between files when a live edit arrives or the two-second dispatch window is reached; an active file or store commit finishes before yielding. Catchup and cleanup alternate, and one background file is admitted after three consecutive live batches so cleanup continues during sustained editing. Existing retry backoff and worker limits remain in effect.
246
246
 
@@ -57,6 +57,7 @@ const cache_coherence_1 = require("../index/cache-coherence");
57
57
  const file_policy_1 = require("../index/file-policy");
58
58
  const walker_1 = require("../index/walker");
59
59
  const watcher_1 = require("../index/watcher");
60
+ const watcher_errors_1 = require("../index/watcher-errors");
60
61
  const watcher_ignore_1 = require("../index/watcher-ignore");
61
62
  const file_utils_1 = require("../utils/file-utils");
62
63
  const logger_1 = require("../utils/logger");
@@ -68,7 +69,7 @@ const watcher_store_1 = require("../utils/watcher-store");
68
69
  // overflows has passed. Probe often; a failed probe just drops back to polling.
69
70
  const FSEVENTS_RECOVERY_INTERVAL_MS = 15 * 60 * 1000;
70
71
  const FSEVENTS_HEALTH_WINDOW_MS = 5 * 60 * 1000; // 5 min of quiet = "healthy"
71
- // Overflows arrive in bursts (a build, a checkout, a venv install). Every
72
+ // Terminal subscription failures can arrive in bursts. Every
72
73
  // recovery inside this window folds into one deferred catchup scan instead of
73
74
  // each rescanning the project (~25s on a 26k-file tree) or skipping outright
74
75
  // and leaving its drop window uncovered.
@@ -104,18 +105,21 @@ class WatcherManager {
104
105
  this.pollIntervals = new Map();
105
106
  this.pollRecoveryTimers = new Map();
106
107
  this.recoveryTimeouts = new Map();
107
- this.lastOverflowMs = new Map();
108
+ this.lastWatcherFailureMs = new Map();
108
109
  this.lastWatcherErrorLogMs = new Map();
109
110
  this.overflowCounts = new Map();
110
111
  this.reconciledAt = new Map();
111
112
  this.catchupDurations = new Map();
112
113
  this.lastCatchupEndMs = new Map();
114
+ this.lastCatchupStartMs = new Map();
115
+ this.overflowPendingRoots = new Set();
113
116
  this.deferredCatchups = new Map();
114
117
  this.catchups = new Map();
115
118
  this.degradedRoots = new Set();
116
119
  this.terminalFailures = new Map();
117
120
  this.watchLifecycles = new Map();
118
121
  this.subscriptionUpdates = new Map();
122
+ this.watcherGenerations = new Map();
119
123
  }
120
124
  health(root) {
121
125
  var _a;
@@ -126,7 +130,8 @@ class WatcherManager {
126
130
  watcherMode: this.pollIntervals.has(root)
127
131
  ? "polling"
128
132
  : this.pendingOps.has(`recover:${root}`) ||
129
- this.deferredCatchups.has(root)
133
+ this.deferredCatchups.has(root) ||
134
+ this.overflowPendingRoots.has(root)
130
135
  ? "recovering"
131
136
  : "native",
132
137
  catchupRunning: this.catchups.has(root),
@@ -250,7 +255,7 @@ class WatcherManager {
250
255
  const name = path.basename(root);
251
256
  console.error(`[daemon:${name}] Subscribe failed at startup (${err instanceof Error ? err.message : err}) — switching to poll mode`);
252
257
  this.watcherFailCount.set(root, 1000); // > MAX_WATCHER_RETRIES
253
- this.lastOverflowMs.set(root, Date.now());
258
+ this.lastWatcherFailureMs.set(root, Date.now());
254
259
  this.recoverWatcher(root, processor);
255
260
  }
256
261
  if (!ownsLifecycle())
@@ -311,6 +316,8 @@ class WatcherManager {
311
316
  if (this.deps.processors.get(root) !== processor ||
312
317
  ((_b = (_a = this.deps).getShuttingDown) === null || _b === void 0 ? void 0 : _b.call(_a)))
313
318
  return;
319
+ const generation = Symbol(root);
320
+ this.watcherGenerations.set(root, generation);
314
321
  // Unsubscribe existing watcher if any (e.g. during recovery)
315
322
  const existingSub = this.deps.subscriptions.get(root);
316
323
  if (existingSub) {
@@ -322,21 +329,30 @@ class WatcherManager {
322
329
  }
323
330
  const sub = yield watcher.subscribe(root, (err, events) => {
324
331
  var _a, _b;
325
- if (this.deps.processors.get(root) !== processor)
332
+ var _c, _d;
333
+ if (this.deps.processors.get(root) !== processor ||
334
+ this.watcherGenerations.get(root) !== generation ||
335
+ ((_b = (_a = this.deps).getShuttingDown) === null || _b === void 0 ? void 0 : _b.call(_a)))
326
336
  return;
327
337
  if (err) {
328
- this.overflowCounts.set(root, ((_a = this.overflowCounts.get(root)) !== null && _a !== void 0 ? _a : 0) + 1);
338
+ this.overflowCounts.set(root, ((_c = this.overflowCounts.get(root)) !== null && _c !== void 0 ? _c : 0) + 1);
329
339
  const now = Date.now();
330
340
  if (!this.lastWatcherErrorLogMs.has(root) ||
331
341
  now - this.lastWatcherErrorLogMs.get(root) >= 60000) {
332
342
  this.lastWatcherErrorLogMs.set(root, now);
333
343
  console.error(`[daemon:${name}] Watcher error (total=${this.overflowCounts.get(root)}):`, err);
334
344
  }
335
- this.recoverWatcher(root, processor);
336
- return;
345
+ if ((0, watcher_errors_1.isFSEventsGap)(err)) {
346
+ this.overflowPendingRoots.add(root);
347
+ this.requestOverflowCatchup(root, processor);
348
+ }
349
+ else {
350
+ this.recoverWatcher(root, processor);
351
+ }
337
352
  }
338
- // Only reset fail counter after sustained health (5min since last overflow)
339
- const lastOverflow = (_b = this.lastOverflowMs.get(root)) !== null && _b !== void 0 ? _b : 0;
353
+ // Gaps do not kill Parcel's stream. Only a terminal failure should
354
+ // reset the subscription health window or prevent leaving poll mode.
355
+ const lastOverflow = (_d = this.lastWatcherFailureMs.get(root)) !== null && _d !== void 0 ? _d : 0;
340
356
  if (Date.now() - lastOverflow > 5 * 60 * 1000) {
341
357
  this.watcherFailCount.delete(root);
342
358
  }
@@ -350,13 +366,30 @@ class WatcherManager {
350
366
  ...(yield (0, watcher_ignore_1.readProjectWatcherIgnores)(root)),
351
367
  ],
352
368
  });
353
- if (this.deps.processors.get(root) !== processor) {
369
+ if (this.deps.processors.get(root) !== processor ||
370
+ this.watcherGenerations.get(root) !== generation) {
354
371
  yield sub.unsubscribe();
355
372
  return;
356
373
  }
357
374
  this.deps.subscriptions.set(root, sub);
358
375
  });
359
376
  }
377
+ requestOverflowCatchup(root, processor) {
378
+ const started = this.lastCatchupStartMs.get(root);
379
+ const remaining = started === undefined
380
+ ? 0
381
+ : watcher_errors_1.FSEVENTS_GAP_SCAN_INTERVAL_MS - (Date.now() - started);
382
+ // A gap during a scan may concern a path already visited. Keep one later
383
+ // scan rather than treating the current walk as coverage of that gap.
384
+ if (this.catchups.has(root) || remaining > 0) {
385
+ this.deferCatchup(root, processor, Math.max(remaining, watcher_errors_1.FSEVENTS_GAP_SCAN_INTERVAL_MS));
386
+ return;
387
+ }
388
+ this.cancelDeferredCatchup(root);
389
+ this.runCatchup(root, processor).catch((err) => {
390
+ console.error(`[daemon:${path.basename(root)}] Overflow catchup failed:`, err);
391
+ });
392
+ }
360
393
  recoverWatcher(root, processor) {
361
394
  var _a;
362
395
  const name = path.basename(root);
@@ -370,11 +403,11 @@ class WatcherManager {
370
403
  this.pendingOps.add(recoveryKey);
371
404
  const fails = ((_a = this.watcherFailCount.get(root)) !== null && _a !== void 0 ? _a : 0) + 1;
372
405
  this.watcherFailCount.set(root, fails);
373
- this.lastOverflowMs.set(root, Date.now());
406
+ this.lastWatcherFailureMs.set(root, Date.now());
374
407
  const MAX_WATCHER_RETRIES = 3;
375
408
  const POLL_INTERVAL_MS = 5 * 60 * 1000; // 5 minutes
376
409
  if (fails > MAX_WATCHER_RETRIES) {
377
- // FSEvents can't handle this project — degrade to periodic catchup scans
410
+ // Repeated terminal subscription failures require periodic catchup scans.
378
411
  // Always tear down the broken sub, even if poll mode is already active —
379
412
  // this can happen if a recovery attempt resubscribed successfully then
380
413
  // re-overflowed during the 5-min health window.
@@ -384,7 +417,7 @@ class WatcherManager {
384
417
  this.deps.subscriptions.delete(root);
385
418
  }
386
419
  if (!this.pollIntervals.has(root)) {
387
- console.error(`[daemon:${name}] FSEvents unreliable after ${fails} failures — switching to poll mode (${POLL_INTERVAL_MS / 60000}min interval)`);
420
+ console.error(`[daemon:${name}] Native watcher failed after ${fails} terminal errors — switching to poll mode (${POLL_INTERVAL_MS / 60000}min interval)`);
388
421
  // Run an immediate catchup, then schedule periodic ones
389
422
  this.runCatchup(root, processor).catch((err) => {
390
423
  console.error(`[daemon:${name}] Poll catchup failed:`, err);
@@ -416,7 +449,7 @@ class WatcherManager {
416
449
  }
417
450
  // Backoff: wait before re-subscribing (3s, 6s, 12s)
418
451
  const delayMs = 3000 * Math.pow(2, (fails - 1));
419
- console.error(`[daemon:${name}] Recovering watcher (attempt ${fails}/${MAX_WATCHER_RETRIES}, backoff ${delayMs}ms)...`);
452
+ console.error(`[daemon:${name}] Recovering failed watcher (attempt ${fails}/${MAX_WATCHER_RETRIES}, backoff ${delayMs}ms)...`);
420
453
  const timeout = setTimeout(() => {
421
454
  this.recoveryTimeouts.delete(root);
422
455
  if (this.deps.getShuttingDown() ||
@@ -520,14 +553,14 @@ class WatcherManager {
520
553
  if (this.deps.processors.get(root) !== processor)
521
554
  return;
522
555
  // Wait one health window — if the new subscription survives without
523
- // another overflow, we consider it recovered and tear down poll mode.
556
+ // another terminal failure, we consider it recovered and tear down poll mode.
524
557
  yield abortableDelay(FSEVENTS_HEALTH_WINDOW_MS, lifecycle.signal);
525
558
  if (this.deps.getShuttingDown() ||
526
559
  this.deps.processors.get(root) !== processor)
527
560
  return;
528
- const lastOverflow = (_a = this.lastOverflowMs.get(root)) !== null && _a !== void 0 ? _a : 0;
561
+ const lastOverflow = (_a = this.lastWatcherFailureMs.get(root)) !== null && _a !== void 0 ? _a : 0;
529
562
  if (Date.now() - lastOverflow < FSEVENTS_HEALTH_WINDOW_MS) {
530
- console.log(`[daemon:${name}] FSEvents recovery aborted — fresh overflow within health window, staying in poll mode`);
563
+ console.log(`[daemon:${name}] FSEvents recovery aborted — terminal failure within health window, staying in poll mode`);
531
564
  return; // recoverWatcher will have re-armed poll mode if needed
532
565
  }
533
566
  // Healthy — drop poll mode.
@@ -555,8 +588,9 @@ class WatcherManager {
555
588
  return __awaiter(this, void 0, void 0, function* () {
556
589
  var _a, e_1, _b, _c;
557
590
  var _d;
558
- var _e;
591
+ var _e, _f, _g;
559
592
  const scanStart = Date.now();
593
+ const overflowCountAtStart = (_e = this.overflowCounts.get(root)) !== null && _e !== void 0 ? _e : 0;
560
594
  const { isFileCached } = yield Promise.resolve().then(() => __importStar(require("../utils/cache-check")));
561
595
  const metaCache = this.deps.getMetaCache();
562
596
  const vectorDb = this.deps.getVectorDb();
@@ -573,12 +607,12 @@ class WatcherManager {
573
607
  let skipped = 0;
574
608
  let debugSamples = 0;
575
609
  try {
576
- for (var _f = true, _g = __asyncValues((0, walker_1.walk)(root, {
610
+ for (var _h = true, _j = __asyncValues((0, walker_1.walk)(root, {
577
611
  policy: processor.filePolicy,
578
612
  state: walkState,
579
- })), _h; _h = yield _g.next(), _a = _h.done, !_a; _f = true) {
580
- _c = _h.value;
581
- _f = false;
613
+ })), _k; _k = yield _j.next(), _a = _k.done, !_a; _h = true) {
614
+ _c = _k.value;
615
+ _h = false;
582
616
  const relPath = _c;
583
617
  if (signal.aborted)
584
618
  return false;
@@ -668,7 +702,7 @@ class WatcherManager {
668
702
  catch (e_1_1) { e_1 = { error: e_1_1 }; }
669
703
  finally {
670
704
  try {
671
- if (!_f && !_a && (_b = _g.return)) yield _b.call(_g);
705
+ if (!_h && !_a && (_b = _j.return)) yield _b.call(_j);
672
706
  }
673
707
  finally { if (e_1) throw e_1.error; }
674
708
  }
@@ -701,7 +735,7 @@ class WatcherManager {
701
735
  }
702
736
  else {
703
737
  this.degradedRoots.delete(root);
704
- const failedFiles = (_e = (_d = this.terminalFailures.get(root)) === null || _d === void 0 ? void 0 : _d.size) !== null && _e !== void 0 ? _e : 0;
738
+ const failedFiles = (_f = (_d = this.terminalFailures.get(root)) === null || _d === void 0 ? void 0 : _d.size) !== null && _f !== void 0 ? _f : 0;
705
739
  (0, watcher_store_1.registerWatcher)(Object.assign({ pid: process.pid, projectRoot: root, startTime: Date.now(), status: this.isRootDegraded(root) ? "degraded" : "watching", lastHeartbeat: Date.now() }, (failedFiles > 0
706
740
  ? { lastError: `${failedFiles} file(s) exhausted automatic retries` }
707
741
  : {})));
@@ -717,8 +751,12 @@ class WatcherManager {
717
751
  const ended = Date.now();
718
752
  this.lastCatchupEndMs.set(root, ended);
719
753
  this.catchupDurations.set(root, ended - scanStart);
720
- if (complete)
754
+ if (complete) {
721
755
  this.reconciledAt.set(root, ended);
756
+ // A later gap still needs its deferred scan, even if this walk succeeded.
757
+ if (((_g = this.overflowCounts.get(root)) !== null && _g !== void 0 ? _g : 0) === overflowCountAtStart)
758
+ this.overflowPendingRoots.delete(root);
759
+ }
722
760
  return complete;
723
761
  });
724
762
  }
@@ -737,6 +775,7 @@ class WatcherManager {
737
775
  let incompleteRetries = 0;
738
776
  do {
739
777
  active.dirty = false;
778
+ this.lastCatchupStartMs.set(root, Date.now());
740
779
  const complete = yield this.catchupScan(root, processor, signal);
741
780
  if (!complete && !signal.aborted && incompleteRetries < 3) {
742
781
  incompleteRetries++;
@@ -775,6 +814,7 @@ class WatcherManager {
775
814
  // independently of the processor, so clear them even on the early return.
776
815
  (_a = this.watchLifecycles.get(root)) === null || _a === void 0 ? void 0 : _a.abort();
777
816
  this.watchLifecycles.delete(root);
817
+ this.watcherGenerations.delete(root);
778
818
  const pollInterval = this.pollIntervals.get(root);
779
819
  if (pollInterval) {
780
820
  clearInterval(pollInterval);
@@ -804,8 +844,10 @@ class WatcherManager {
804
844
  this.deps.subscriptions.delete(root);
805
845
  }
806
846
  this.deps.evictSearcher(root);
807
- this.lastOverflowMs.delete(root);
847
+ this.lastWatcherFailureMs.delete(root);
808
848
  this.lastCatchupEndMs.delete(root);
849
+ this.lastCatchupStartMs.delete(root);
850
+ this.overflowPendingRoots.delete(root);
809
851
  this.degradedRoots.delete(root);
810
852
  this.terminalFailures.delete(root);
811
853
  (0, watcher_store_1.unregisterWatcherByRoot)(root);
@@ -0,0 +1,16 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.FSEVENTS_GAP_SCAN_INTERVAL_MS = void 0;
4
+ exports.isFSEventsGap = isFSEventsGap;
5
+ /** Parcel reports these gaps without closing its FSEvents stream. Other errors
6
+ * may clear the native callbacks and still require subscription recovery. */
7
+ function isFSEventsGap(error) {
8
+ return (error.message ===
9
+ "Events were dropped by the FSEvents client. File system must be re-scanned." ||
10
+ error.message ===
11
+ "Events were dropped by the kernel. File system must be re-scanned." ||
12
+ error.message === "Too many events. File system must be re-scanned.");
13
+ }
14
+ // Bound reconciliation under sustained churn without abandoning native edits
15
+ // for the five-minute polling fallback used by a failed subscription.
16
+ exports.FSEVENTS_GAP_SCAN_INTERVAL_MS = 30000;
@@ -58,6 +58,7 @@ const cache_coherence_1 = require("./cache-coherence");
58
58
  const file_policy_1 = require("./file-policy");
59
59
  const ignore_patterns_1 = require("./ignore-patterns");
60
60
  const walker_1 = require("./walker");
61
+ const watcher_errors_1 = require("./watcher-errors");
61
62
  const watcher_ignore_1 = require("./watcher-ignore");
62
63
  // Directory names ignored at ANY depth. @parcel/watcher treats a non-glob
63
64
  // ignore entry as a literal path resolved against the watch root, so a bare
@@ -125,6 +126,11 @@ function startWatcher(opts) {
125
126
  let subscription = null;
126
127
  let subscriptionUpdate = Promise.resolve();
127
128
  let subscriptionPolicy = "";
129
+ let subscriptionFailed = false;
130
+ let subscriptionGeneration = 0;
131
+ let gapScanTimer;
132
+ let lastReconcileStart;
133
+ let gapGeneration = 0;
128
134
  const updateSubscription = () => {
129
135
  const update = subscriptionUpdate
130
136
  .catch(() => { })
@@ -134,16 +140,31 @@ function startWatcher(opts) {
134
140
  ...(yield (0, watcher_ignore_1.readProjectWatcherIgnores)(projectRoot)),
135
141
  ];
136
142
  const policy = JSON.stringify(ignores);
137
- if (closing || (subscription && subscriptionPolicy === policy))
143
+ if (closing ||
144
+ (subscription && !subscriptionFailed && subscriptionPolicy === policy))
138
145
  return;
146
+ const generation = ++subscriptionGeneration;
147
+ subscriptionFailed = false;
139
148
  yield subscription === null || subscription === void 0 ? void 0 : subscription.unsubscribe();
140
149
  subscription = null;
141
150
  if (closing)
142
151
  return;
143
152
  const next = yield watcher.subscribe(projectRoot, (err, events) => {
153
+ var _a;
154
+ if (closing || generation !== subscriptionGeneration)
155
+ return;
144
156
  if (err) {
145
157
  console.error(`[${wtag}] Watcher error:`, err);
146
- return;
158
+ scanHealthy = false;
159
+ (_a = opts.onHealthChange) === null || _a === void 0 ? void 0 : _a.call(opts, false, 1);
160
+ gapGeneration++;
161
+ if ((0, watcher_errors_1.isFSEventsGap)(err))
162
+ requestGapScan();
163
+ else {
164
+ // Terminal backend errors can clear Parcel's callbacks.
165
+ subscriptionFailed = true;
166
+ reconcile();
167
+ }
147
168
  }
148
169
  for (const event of events)
149
170
  processor.handleFileEvent(event.type === "delete" ? "unlink" : "change", event.path);
@@ -180,6 +201,8 @@ function startWatcher(opts) {
180
201
  let incompleteRetries = 0;
181
202
  do {
182
203
  reconcileRequested = false;
204
+ lastReconcileStart = Date.now();
205
+ const observedGapGeneration = gapGeneration;
183
206
  filePolicy.invalidateIgnoreCache();
184
207
  yield updateSubscription();
185
208
  if (closing)
@@ -243,7 +266,7 @@ function startWatcher(opts) {
243
266
  }
244
267
  }
245
268
  else {
246
- scanHealthy = true;
269
+ scanHealthy = observedGapGeneration === gapGeneration;
247
270
  if (ingestionDegraded && processor.progress.pendingFiles > 0) {
248
271
  degradedRepairQueued = true;
249
272
  }
@@ -257,6 +280,21 @@ function startWatcher(opts) {
257
280
  reconciliation = null;
258
281
  });
259
282
  };
283
+ const requestGapScan = () => {
284
+ if (closing || gapScanTimer)
285
+ return;
286
+ const remaining = lastReconcileStart === undefined
287
+ ? 0
288
+ : watcher_errors_1.FSEVENTS_GAP_SCAN_INTERVAL_MS - (Date.now() - lastReconcileStart);
289
+ if (reconciliation || remaining > 0) {
290
+ gapScanTimer = setTimeout(() => {
291
+ gapScanTimer = undefined;
292
+ reconcile();
293
+ }, Math.max(remaining, watcher_errors_1.FSEVENTS_GAP_SCAN_INTERVAL_MS));
294
+ return;
295
+ }
296
+ reconcile();
297
+ };
260
298
  processor = new batch_processor_1.ProjectBatchProcessor(Object.assign(Object.assign({}, opts), { filePolicy, onPolicyChange: reconcile, onReindex: (files, durationMs) => {
261
299
  var _a;
262
300
  (_a = opts.onReindex) === null || _a === void 0 ? void 0 : _a.call(opts, files, durationMs);
@@ -284,6 +322,8 @@ function startWatcher(opts) {
284
322
  },
285
323
  close: () => __awaiter(this, void 0, void 0, function* () {
286
324
  closing = true;
325
+ subscriptionGeneration++;
326
+ clearTimeout(gapScanTimer);
287
327
  yield subscriptionUpdate.catch(() => { });
288
328
  yield subscription === null || subscription === void 0 ? void 0 : subscription.unsubscribe();
289
329
  yield reconciliation;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "grepmax",
3
- "version": "0.26.63",
3
+ "version": "0.26.64",
4
4
  "author": "Robert Owens <78518764+reowens@users.noreply.github.com>",
5
5
  "homepage": "https://github.com/reowens/grepmax",
6
6
  "bugs": {
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "grepmax",
3
- "version": "0.26.63",
3
+ "version": "0.26.64",
4
4
  "description": "Semantic code search for Claude Code. Automatically indexes your project and provides intelligent search capabilities.",
5
5
  "author": {
6
6
  "name": "Robert Owens",