raggrep 0.10.1 → 0.10.4

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/dist/index.js CHANGED
@@ -11395,6 +11395,11 @@ import { watch } from "chokidar";
11395
11395
  init_config2();
11396
11396
 
11397
11397
  // src/app/indexer/index.ts
11398
+ var FRESHNESS_CACHE_TTL_MS = 5000;
11399
+ var freshnessCache = null;
11400
+ function clearFreshnessCache() {
11401
+ freshnessCache = null;
11402
+ }
11398
11403
  function computeContentHash(content) {
11399
11404
  return crypto2.createHash("sha256").update(content, "utf-8").digest("hex");
11400
11405
  }
@@ -11436,10 +11441,12 @@ function getOptimalConcurrency() {
11436
11441
  return optimal;
11437
11442
  }
11438
11443
  var DEFAULT_CONCURRENCY = getOptimalConcurrency();
11444
+ var STAT_CONCURRENCY = Math.max(32, getOptimalConcurrency() * 4);
11439
11445
  async function indexDirectory(rootDir, options = {}) {
11440
11446
  const verbose = options.verbose ?? false;
11441
11447
  const quiet = options.quiet ?? false;
11442
11448
  const concurrency = options.concurrency ?? DEFAULT_CONCURRENCY;
11449
+ clearFreshnessCache();
11443
11450
  const logger = options.logger ? options.logger : quiet ? createSilentLogger() : createLogger({ verbose });
11444
11451
  rootDir = path21.resolve(rootDir);
11445
11452
  const location = getIndexLocation(rootDir);
@@ -11538,6 +11545,7 @@ async function deleteIndex(rootDir) {
11538
11545
  }
11539
11546
  async function resetIndex(rootDir) {
11540
11547
  rootDir = path21.resolve(rootDir);
11548
+ clearFreshnessCache();
11541
11549
  const status = await getIndexStatus(rootDir);
11542
11550
  if (!status.exists) {
11543
11551
  throw new Error(`No index found for ${rootDir}`);
@@ -11551,10 +11559,20 @@ async function resetIndex(rootDir) {
11551
11559
  async function ensureIndexFresh(rootDir, options = {}) {
11552
11560
  const verbose = options.verbose ?? false;
11553
11561
  const quiet = options.quiet ?? false;
11562
+ const showTiming = options.timing ?? false;
11563
+ const startTime = Date.now();
11564
+ let fileDiscoveryMs = 0;
11565
+ let statCheckMs = 0;
11566
+ let indexingMs = 0;
11567
+ let cleanupMs = 0;
11568
+ let filesDiscovered = 0;
11569
+ let filesStatChecked = 0;
11570
+ let filesIndexed = 0;
11554
11571
  const logger = options.logger ? options.logger : quiet ? createSilentLogger() : createLogger({ verbose });
11555
11572
  rootDir = path21.resolve(rootDir);
11556
11573
  const status = await getIndexStatus(rootDir);
11557
11574
  if (!status.exists) {
11575
+ clearFreshnessCache();
11558
11576
  logger.info(`No index found. Creating index...
11559
11577
  `);
11560
11578
  const results = await indexDirectory(rootDir, { ...options, logger });
@@ -11563,6 +11581,7 @@ async function ensureIndexFresh(rootDir, options = {}) {
11563
11581
  }
11564
11582
  const versionCompatible = await isIndexVersionCompatible(rootDir);
11565
11583
  if (!versionCompatible) {
11584
+ clearFreshnessCache();
11566
11585
  logger.info(`Index version incompatible. Rebuilding...
11567
11586
  `);
11568
11587
  await deleteIndex(rootDir);
@@ -11571,14 +11590,44 @@ async function ensureIndexFresh(rootDir, options = {}) {
11571
11590
  return { indexed: totalIndexed2, removed: 0, unchanged: 0 };
11572
11591
  }
11573
11592
  const config = await loadConfig(rootDir);
11593
+ const globalManifestPath = getGlobalManifestPath(rootDir, config);
11594
+ let currentManifestMtime = 0;
11595
+ try {
11596
+ const manifestStats = await fs8.stat(globalManifestPath);
11597
+ currentManifestMtime = manifestStats.mtimeMs;
11598
+ } catch {}
11599
+ const now = Date.now();
11600
+ if (freshnessCache && freshnessCache.rootDir === rootDir && now - freshnessCache.timestamp < FRESHNESS_CACHE_TTL_MS && freshnessCache.manifestMtime === currentManifestMtime) {
11601
+ logger.debug("Using cached freshness check result");
11602
+ const cachedResult = { ...freshnessCache.result };
11603
+ if (showTiming) {
11604
+ cachedResult.timing = {
11605
+ totalMs: Date.now() - startTime,
11606
+ fileDiscoveryMs: 0,
11607
+ statCheckMs: 0,
11608
+ indexingMs: 0,
11609
+ cleanupMs: 0,
11610
+ filesDiscovered: 0,
11611
+ filesStatChecked: 0,
11612
+ filesIndexed: 0,
11613
+ fromCache: true
11614
+ };
11615
+ }
11616
+ return cachedResult;
11617
+ }
11574
11618
  await registerBuiltInModules();
11575
11619
  const enabledModules = registry.getEnabled(config);
11576
11620
  if (enabledModules.length === 0) {
11577
11621
  return { indexed: 0, removed: 0, unchanged: 0 };
11578
11622
  }
11623
+ const fileDiscoveryStart = Date.now();
11579
11624
  const introspection = new IntrospectionIndex(rootDir);
11580
- await introspection.initialize();
11581
- const currentFiles = await findFiles(rootDir, config);
11625
+ const [, currentFiles] = await Promise.all([
11626
+ introspection.initialize(),
11627
+ findFiles(rootDir, config)
11628
+ ]);
11629
+ fileDiscoveryMs = Date.now() - fileDiscoveryStart;
11630
+ filesDiscovered = currentFiles.length;
11582
11631
  const currentFileSet = new Set(currentFiles.map((f) => path21.relative(rootDir, f)));
11583
11632
  let totalIndexed = 0;
11584
11633
  let totalRemoved = 0;
@@ -11607,20 +11656,21 @@ async function ensureIndexFresh(rootDir, options = {}) {
11607
11656
  filesToRemove.push(filepath);
11608
11657
  }
11609
11658
  }
11659
+ const cleanupStart = Date.now();
11610
11660
  const removedFilepaths = [];
11611
- for (const filepath of filesToRemove) {
11612
- logger.debug(` Removing stale: ${filepath}`);
11613
- const indexFilePath = path21.join(indexPath, filepath.replace(/\.[^.]+$/, ".json"));
11614
- try {
11615
- await fs8.unlink(indexFilePath);
11616
- } catch {}
11617
- const symbolicFilePath = path21.join(indexPath, "symbolic", filepath.replace(/\.[^.]+$/, ".json"));
11618
- try {
11619
- await fs8.unlink(symbolicFilePath);
11620
- } catch {}
11621
- delete manifest.files[filepath];
11622
- removedFilepaths.push(filepath);
11623
- totalRemoved++;
11661
+ if (filesToRemove.length > 0) {
11662
+ await Promise.all(filesToRemove.map(async (filepath) => {
11663
+ logger.debug(` Removing stale: ${filepath}`);
11664
+ const indexFilePath = path21.join(indexPath, filepath.replace(/\.[^.]+$/, ".json"));
11665
+ const symbolicFilePath = path21.join(indexPath, "symbolic", filepath.replace(/\.[^.]+$/, ".json"));
11666
+ await Promise.all([
11667
+ fs8.unlink(indexFilePath).catch(() => {}),
11668
+ fs8.unlink(symbolicFilePath).catch(() => {})
11669
+ ]);
11670
+ delete manifest.files[filepath];
11671
+ removedFilepaths.push(filepath);
11672
+ }));
11673
+ totalRemoved += removedFilepaths.length;
11624
11674
  }
11625
11675
  if (removedFilepaths.length > 0) {
11626
11676
  try {
@@ -11634,6 +11684,7 @@ async function ensureIndexFresh(rootDir, options = {}) {
11634
11684
  await literalIndex.save();
11635
11685
  } catch {}
11636
11686
  }
11687
+ cleanupMs += Date.now() - cleanupStart;
11637
11688
  const ctx = {
11638
11689
  rootDir,
11639
11690
  config,
@@ -11648,21 +11699,51 @@ async function ensureIndexFresh(rootDir, options = {}) {
11648
11699
  },
11649
11700
  getIntrospection: (filepath) => introspection.getFile(filepath)
11650
11701
  };
11651
- const totalFiles = currentFiles.length;
11652
- let completedCount = 0;
11653
- const processIncrementalFile = async (filepath) => {
11702
+ const statCheck = async (filepath) => {
11654
11703
  const relativePath = path21.relative(rootDir, filepath);
11655
11704
  try {
11656
11705
  const stats = await fs8.stat(filepath);
11657
11706
  const lastModified = stats.mtime.toISOString();
11658
11707
  const existingEntry = manifest.files[relativePath];
11659
- if (existingEntry && existingEntry.lastModified === lastModified) {
11660
- completedCount++;
11661
- return { relativePath, status: "unchanged" };
11708
+ if (!existingEntry) {
11709
+ return { filepath, relativePath, lastModified, needsCheck: true, isNew: true };
11710
+ }
11711
+ if (existingEntry.lastModified === lastModified) {
11712
+ return { filepath, relativePath, lastModified, needsCheck: false, isNew: false };
11662
11713
  }
11714
+ return { filepath, relativePath, lastModified, needsCheck: true, isNew: false };
11715
+ } catch {
11716
+ return null;
11717
+ }
11718
+ };
11719
+ const statCheckStart = Date.now();
11720
+ const statResults = await parallelMap(currentFiles, statCheck, STAT_CONCURRENCY);
11721
+ statCheckMs += Date.now() - statCheckStart;
11722
+ filesStatChecked += currentFiles.length;
11723
+ const filesToProcess = [];
11724
+ let unchangedCount = 0;
11725
+ for (const result2 of statResults) {
11726
+ if (!result2.success || !result2.value)
11727
+ continue;
11728
+ if (result2.value.needsCheck) {
11729
+ filesToProcess.push(result2.value);
11730
+ } else {
11731
+ unchangedCount++;
11732
+ }
11733
+ }
11734
+ if (filesToProcess.length === 0) {
11735
+ totalUnchanged += unchangedCount;
11736
+ continue;
11737
+ }
11738
+ let completedCount = 0;
11739
+ const totalToProcess = filesToProcess.length;
11740
+ const processChangedFile = async (statResult) => {
11741
+ const { filepath, relativePath, lastModified, isNew } = statResult;
11742
+ try {
11663
11743
  const content = await fs8.readFile(filepath, "utf-8");
11664
11744
  const contentHash = computeContentHash(content);
11665
- if (existingEntry?.contentHash && existingEntry.contentHash === contentHash) {
11745
+ const existingEntry = manifest.files[relativePath];
11746
+ if (!isNew && existingEntry?.contentHash && existingEntry.contentHash === contentHash) {
11666
11747
  completedCount++;
11667
11748
  return {
11668
11749
  relativePath,
@@ -11672,7 +11753,7 @@ async function ensureIndexFresh(rootDir, options = {}) {
11672
11753
  };
11673
11754
  }
11674
11755
  completedCount++;
11675
- logger.progress(` [${completedCount}/${totalFiles}] Indexing: ${relativePath}`);
11756
+ logger.progress(` [${completedCount}/${totalToProcess}] Indexing: ${relativePath}`);
11676
11757
  introspection.addFile(relativePath, content);
11677
11758
  const fileIndex = await module2.indexFile(relativePath, content, ctx);
11678
11759
  if (!fileIndex) {
@@ -11691,8 +11772,12 @@ async function ensureIndexFresh(rootDir, options = {}) {
11691
11772
  return { relativePath, status: "error", error };
11692
11773
  }
11693
11774
  };
11775
+ const indexingStart = Date.now();
11694
11776
  const concurrency = options.concurrency ?? DEFAULT_CONCURRENCY;
11695
- const results = await parallelMap(currentFiles, processIncrementalFile, concurrency);
11777
+ const results = await parallelMap(filesToProcess, processChangedFile, concurrency);
11778
+ indexingMs += Date.now() - indexingStart;
11779
+ filesIndexed += filesToProcess.length;
11780
+ totalUnchanged += unchangedCount;
11696
11781
  logger.clearProgress();
11697
11782
  let mtimeUpdates = 0;
11698
11783
  for (const item of results) {
@@ -11746,12 +11831,38 @@ async function ensureIndexFresh(rootDir, options = {}) {
11746
11831
  }
11747
11832
  if (totalIndexed > 0 || totalRemoved > 0) {
11748
11833
  await updateGlobalManifest(rootDir, enabledModules, config);
11834
+ clearFreshnessCache();
11749
11835
  }
11750
- return {
11836
+ const result = {
11751
11837
  indexed: totalIndexed,
11752
11838
  removed: totalRemoved,
11753
11839
  unchanged: totalUnchanged
11754
11840
  };
11841
+ if (showTiming) {
11842
+ result.timing = {
11843
+ totalMs: Date.now() - startTime,
11844
+ fileDiscoveryMs,
11845
+ statCheckMs,
11846
+ indexingMs,
11847
+ cleanupMs,
11848
+ filesDiscovered,
11849
+ filesStatChecked,
11850
+ filesIndexed,
11851
+ fromCache: false
11852
+ };
11853
+ }
11854
+ let finalManifestMtime = currentManifestMtime;
11855
+ try {
11856
+ const manifestStats = await fs8.stat(globalManifestPath);
11857
+ finalManifestMtime = manifestStats.mtimeMs;
11858
+ } catch {}
11859
+ freshnessCache = {
11860
+ rootDir,
11861
+ result: { indexed: totalIndexed, removed: totalRemoved, unchanged: totalUnchanged },
11862
+ timestamp: Date.now(),
11863
+ manifestMtime: finalManifestMtime
11864
+ };
11865
+ return result;
11755
11866
  }
11756
11867
  async function indexWithModule(rootDir, files, module2, config, verbose, introspection, logger, concurrency = DEFAULT_CONCURRENCY) {
11757
11868
  const result = {
@@ -11889,16 +12000,13 @@ async function indexWithModule(rootDir, files, module2, config, verbose, introsp
11889
12000
  async function findFiles(rootDir, config) {
11890
12001
  const patterns = config.extensions.map((ext) => `**/*${ext}`);
11891
12002
  const ignorePatterns = config.ignorePaths.map((p) => `**/${p}/**`);
11892
- const files = [];
11893
- for (const pattern of patterns) {
11894
- const matches = await glob(pattern, {
11895
- cwd: rootDir,
11896
- absolute: true,
11897
- ignore: ignorePatterns
11898
- });
11899
- files.push(...matches);
11900
- }
11901
- return [...new Set(files)];
12003
+ const results = await Promise.all(patterns.map((pattern) => glob(pattern, {
12004
+ cwd: rootDir,
12005
+ absolute: true,
12006
+ ignore: ignorePatterns
12007
+ })));
12008
+ const allFiles = results.flat();
12009
+ return [...new Set(allFiles)];
11902
12010
  }
11903
12011
  async function loadModuleManifest(rootDir, moduleId, config) {
11904
12012
  const manifestPath = getModuleManifestPath(rootDir, moduleId, config);
@@ -13476,4 +13584,4 @@ export {
13476
13584
  ConsoleLogger
13477
13585
  };
13478
13586
 
13479
- //# debugId=7E760B022D4CA40A64756E2164756E21
13587
+ //# debugId=EA9D4B791B6DE73764756E2164756E21