raggrep 0.10.2 → 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/app/indexer/index.d.ts +25 -0
- package/dist/cli/main.js +137 -40
- package/dist/cli/main.js.map +4 -4
- package/dist/index.js +112 -37
- package/dist/index.js.map +3 -3
- package/package.json +1 -1
|
@@ -23,6 +23,29 @@ export interface IndexOptions {
|
|
|
23
23
|
logger?: Logger;
|
|
24
24
|
/** Number of files to process in parallel (default: auto based on CPU cores) */
|
|
25
25
|
concurrency?: number;
|
|
26
|
+
/** Show timing information for each stage */
|
|
27
|
+
timing?: boolean;
|
|
28
|
+
}
|
|
29
|
+
/** Timing information for performance profiling */
|
|
30
|
+
export interface TimingInfo {
|
|
31
|
+
/** Total time in milliseconds */
|
|
32
|
+
totalMs: number;
|
|
33
|
+
/** Time spent on file discovery (glob) */
|
|
34
|
+
fileDiscoveryMs: number;
|
|
35
|
+
/** Time spent on stat checks */
|
|
36
|
+
statCheckMs: number;
|
|
37
|
+
/** Time spent on indexing changed files */
|
|
38
|
+
indexingMs: number;
|
|
39
|
+
/** Time spent on cleanup operations */
|
|
40
|
+
cleanupMs: number;
|
|
41
|
+
/** Number of files discovered */
|
|
42
|
+
filesDiscovered: number;
|
|
43
|
+
/** Number of files that needed stat check */
|
|
44
|
+
filesStatChecked: number;
|
|
45
|
+
/** Number of files that needed indexing */
|
|
46
|
+
filesIndexed: number;
|
|
47
|
+
/** Whether result was from cache */
|
|
48
|
+
fromCache: boolean;
|
|
26
49
|
}
|
|
27
50
|
export interface EnsureFreshResult {
|
|
28
51
|
/** Number of files indexed (new or modified) */
|
|
@@ -31,6 +54,8 @@ export interface EnsureFreshResult {
|
|
|
31
54
|
removed: number;
|
|
32
55
|
/** Number of files unchanged (used cache) */
|
|
33
56
|
unchanged: number;
|
|
57
|
+
/** Timing information (only present if timing option was enabled) */
|
|
58
|
+
timing?: TimingInfo;
|
|
34
59
|
}
|
|
35
60
|
export interface CleanupResult {
|
|
36
61
|
moduleId: string;
|
package/dist/cli/main.js
CHANGED
|
@@ -11545,6 +11545,15 @@ async function resetIndex(rootDir) {
|
|
|
11545
11545
|
async function ensureIndexFresh(rootDir, options = {}) {
|
|
11546
11546
|
const verbose = options.verbose ?? false;
|
|
11547
11547
|
const quiet = options.quiet ?? false;
|
|
11548
|
+
const showTiming = options.timing ?? false;
|
|
11549
|
+
const startTime = Date.now();
|
|
11550
|
+
let fileDiscoveryMs = 0;
|
|
11551
|
+
let statCheckMs = 0;
|
|
11552
|
+
let indexingMs = 0;
|
|
11553
|
+
let cleanupMs = 0;
|
|
11554
|
+
let filesDiscovered = 0;
|
|
11555
|
+
let filesStatChecked = 0;
|
|
11556
|
+
let filesIndexed = 0;
|
|
11548
11557
|
const logger = options.logger ? options.logger : quiet ? createSilentLogger() : createLogger({ verbose });
|
|
11549
11558
|
rootDir = path22.resolve(rootDir);
|
|
11550
11559
|
const status = await getIndexStatus(rootDir);
|
|
@@ -11576,16 +11585,35 @@ async function ensureIndexFresh(rootDir, options = {}) {
|
|
|
11576
11585
|
const now = Date.now();
|
|
11577
11586
|
if (freshnessCache && freshnessCache.rootDir === rootDir && now - freshnessCache.timestamp < FRESHNESS_CACHE_TTL_MS && freshnessCache.manifestMtime === currentManifestMtime) {
|
|
11578
11587
|
logger.debug("Using cached freshness check result");
|
|
11579
|
-
|
|
11588
|
+
const cachedResult = { ...freshnessCache.result };
|
|
11589
|
+
if (showTiming) {
|
|
11590
|
+
cachedResult.timing = {
|
|
11591
|
+
totalMs: Date.now() - startTime,
|
|
11592
|
+
fileDiscoveryMs: 0,
|
|
11593
|
+
statCheckMs: 0,
|
|
11594
|
+
indexingMs: 0,
|
|
11595
|
+
cleanupMs: 0,
|
|
11596
|
+
filesDiscovered: 0,
|
|
11597
|
+
filesStatChecked: 0,
|
|
11598
|
+
filesIndexed: 0,
|
|
11599
|
+
fromCache: true
|
|
11600
|
+
};
|
|
11601
|
+
}
|
|
11602
|
+
return cachedResult;
|
|
11580
11603
|
}
|
|
11581
11604
|
await registerBuiltInModules();
|
|
11582
11605
|
const enabledModules = registry.getEnabled(config);
|
|
11583
11606
|
if (enabledModules.length === 0) {
|
|
11584
11607
|
return { indexed: 0, removed: 0, unchanged: 0 };
|
|
11585
11608
|
}
|
|
11609
|
+
const fileDiscoveryStart = Date.now();
|
|
11586
11610
|
const introspection = new IntrospectionIndex(rootDir);
|
|
11587
|
-
await
|
|
11588
|
-
|
|
11611
|
+
const [, currentFiles] = await Promise.all([
|
|
11612
|
+
introspection.initialize(),
|
|
11613
|
+
findFiles(rootDir, config)
|
|
11614
|
+
]);
|
|
11615
|
+
fileDiscoveryMs = Date.now() - fileDiscoveryStart;
|
|
11616
|
+
filesDiscovered = currentFiles.length;
|
|
11589
11617
|
const currentFileSet = new Set(currentFiles.map((f) => path22.relative(rootDir, f)));
|
|
11590
11618
|
let totalIndexed = 0;
|
|
11591
11619
|
let totalRemoved = 0;
|
|
@@ -11614,20 +11642,21 @@ async function ensureIndexFresh(rootDir, options = {}) {
|
|
|
11614
11642
|
filesToRemove.push(filepath);
|
|
11615
11643
|
}
|
|
11616
11644
|
}
|
|
11645
|
+
const cleanupStart = Date.now();
|
|
11617
11646
|
const removedFilepaths = [];
|
|
11618
|
-
|
|
11619
|
-
|
|
11620
|
-
|
|
11621
|
-
|
|
11622
|
-
|
|
11623
|
-
|
|
11624
|
-
|
|
11625
|
-
|
|
11626
|
-
|
|
11627
|
-
|
|
11628
|
-
|
|
11629
|
-
|
|
11630
|
-
totalRemoved
|
|
11647
|
+
if (filesToRemove.length > 0) {
|
|
11648
|
+
await Promise.all(filesToRemove.map(async (filepath) => {
|
|
11649
|
+
logger.debug(` Removing stale: ${filepath}`);
|
|
11650
|
+
const indexFilePath = path22.join(indexPath, filepath.replace(/\.[^.]+$/, ".json"));
|
|
11651
|
+
const symbolicFilePath = path22.join(indexPath, "symbolic", filepath.replace(/\.[^.]+$/, ".json"));
|
|
11652
|
+
await Promise.all([
|
|
11653
|
+
fs8.unlink(indexFilePath).catch(() => {}),
|
|
11654
|
+
fs8.unlink(symbolicFilePath).catch(() => {})
|
|
11655
|
+
]);
|
|
11656
|
+
delete manifest.files[filepath];
|
|
11657
|
+
removedFilepaths.push(filepath);
|
|
11658
|
+
}));
|
|
11659
|
+
totalRemoved += removedFilepaths.length;
|
|
11631
11660
|
}
|
|
11632
11661
|
if (removedFilepaths.length > 0) {
|
|
11633
11662
|
try {
|
|
@@ -11641,6 +11670,7 @@ async function ensureIndexFresh(rootDir, options = {}) {
|
|
|
11641
11670
|
await literalIndex.save();
|
|
11642
11671
|
} catch {}
|
|
11643
11672
|
}
|
|
11673
|
+
cleanupMs += Date.now() - cleanupStart;
|
|
11644
11674
|
const ctx = {
|
|
11645
11675
|
rootDir,
|
|
11646
11676
|
config,
|
|
@@ -11655,21 +11685,51 @@ async function ensureIndexFresh(rootDir, options = {}) {
|
|
|
11655
11685
|
},
|
|
11656
11686
|
getIntrospection: (filepath) => introspection.getFile(filepath)
|
|
11657
11687
|
};
|
|
11658
|
-
const
|
|
11659
|
-
let completedCount = 0;
|
|
11660
|
-
const processIncrementalFile = async (filepath) => {
|
|
11688
|
+
const statCheck = async (filepath) => {
|
|
11661
11689
|
const relativePath = path22.relative(rootDir, filepath);
|
|
11662
11690
|
try {
|
|
11663
11691
|
const stats = await fs8.stat(filepath);
|
|
11664
11692
|
const lastModified = stats.mtime.toISOString();
|
|
11665
11693
|
const existingEntry = manifest.files[relativePath];
|
|
11666
|
-
if (existingEntry
|
|
11667
|
-
|
|
11668
|
-
return { relativePath, status: "unchanged" };
|
|
11694
|
+
if (!existingEntry) {
|
|
11695
|
+
return { filepath, relativePath, lastModified, needsCheck: true, isNew: true };
|
|
11669
11696
|
}
|
|
11697
|
+
if (existingEntry.lastModified === lastModified) {
|
|
11698
|
+
return { filepath, relativePath, lastModified, needsCheck: false, isNew: false };
|
|
11699
|
+
}
|
|
11700
|
+
return { filepath, relativePath, lastModified, needsCheck: true, isNew: false };
|
|
11701
|
+
} catch {
|
|
11702
|
+
return null;
|
|
11703
|
+
}
|
|
11704
|
+
};
|
|
11705
|
+
const statCheckStart = Date.now();
|
|
11706
|
+
const statResults = await parallelMap(currentFiles, statCheck, STAT_CONCURRENCY);
|
|
11707
|
+
statCheckMs += Date.now() - statCheckStart;
|
|
11708
|
+
filesStatChecked += currentFiles.length;
|
|
11709
|
+
const filesToProcess = [];
|
|
11710
|
+
let unchangedCount = 0;
|
|
11711
|
+
for (const result2 of statResults) {
|
|
11712
|
+
if (!result2.success || !result2.value)
|
|
11713
|
+
continue;
|
|
11714
|
+
if (result2.value.needsCheck) {
|
|
11715
|
+
filesToProcess.push(result2.value);
|
|
11716
|
+
} else {
|
|
11717
|
+
unchangedCount++;
|
|
11718
|
+
}
|
|
11719
|
+
}
|
|
11720
|
+
if (filesToProcess.length === 0) {
|
|
11721
|
+
totalUnchanged += unchangedCount;
|
|
11722
|
+
continue;
|
|
11723
|
+
}
|
|
11724
|
+
let completedCount = 0;
|
|
11725
|
+
const totalToProcess = filesToProcess.length;
|
|
11726
|
+
const processChangedFile = async (statResult) => {
|
|
11727
|
+
const { filepath, relativePath, lastModified, isNew } = statResult;
|
|
11728
|
+
try {
|
|
11670
11729
|
const content = await fs8.readFile(filepath, "utf-8");
|
|
11671
11730
|
const contentHash = computeContentHash(content);
|
|
11672
|
-
|
|
11731
|
+
const existingEntry = manifest.files[relativePath];
|
|
11732
|
+
if (!isNew && existingEntry?.contentHash && existingEntry.contentHash === contentHash) {
|
|
11673
11733
|
completedCount++;
|
|
11674
11734
|
return {
|
|
11675
11735
|
relativePath,
|
|
@@ -11679,7 +11739,7 @@ async function ensureIndexFresh(rootDir, options = {}) {
|
|
|
11679
11739
|
};
|
|
11680
11740
|
}
|
|
11681
11741
|
completedCount++;
|
|
11682
|
-
logger.progress(` [${completedCount}/${
|
|
11742
|
+
logger.progress(` [${completedCount}/${totalToProcess}] Indexing: ${relativePath}`);
|
|
11683
11743
|
introspection.addFile(relativePath, content);
|
|
11684
11744
|
const fileIndex = await module2.indexFile(relativePath, content, ctx);
|
|
11685
11745
|
if (!fileIndex) {
|
|
@@ -11698,8 +11758,12 @@ async function ensureIndexFresh(rootDir, options = {}) {
|
|
|
11698
11758
|
return { relativePath, status: "error", error };
|
|
11699
11759
|
}
|
|
11700
11760
|
};
|
|
11761
|
+
const indexingStart = Date.now();
|
|
11701
11762
|
const concurrency = options.concurrency ?? DEFAULT_CONCURRENCY;
|
|
11702
|
-
const results = await parallelMap(
|
|
11763
|
+
const results = await parallelMap(filesToProcess, processChangedFile, concurrency);
|
|
11764
|
+
indexingMs += Date.now() - indexingStart;
|
|
11765
|
+
filesIndexed += filesToProcess.length;
|
|
11766
|
+
totalUnchanged += unchangedCount;
|
|
11703
11767
|
logger.clearProgress();
|
|
11704
11768
|
let mtimeUpdates = 0;
|
|
11705
11769
|
for (const item of results) {
|
|
@@ -11760,6 +11824,19 @@ async function ensureIndexFresh(rootDir, options = {}) {
|
|
|
11760
11824
|
removed: totalRemoved,
|
|
11761
11825
|
unchanged: totalUnchanged
|
|
11762
11826
|
};
|
|
11827
|
+
if (showTiming) {
|
|
11828
|
+
result.timing = {
|
|
11829
|
+
totalMs: Date.now() - startTime,
|
|
11830
|
+
fileDiscoveryMs,
|
|
11831
|
+
statCheckMs,
|
|
11832
|
+
indexingMs,
|
|
11833
|
+
cleanupMs,
|
|
11834
|
+
filesDiscovered,
|
|
11835
|
+
filesStatChecked,
|
|
11836
|
+
filesIndexed,
|
|
11837
|
+
fromCache: false
|
|
11838
|
+
};
|
|
11839
|
+
}
|
|
11763
11840
|
let finalManifestMtime = currentManifestMtime;
|
|
11764
11841
|
try {
|
|
11765
11842
|
const manifestStats = await fs8.stat(globalManifestPath);
|
|
@@ -11767,7 +11844,7 @@ async function ensureIndexFresh(rootDir, options = {}) {
|
|
|
11767
11844
|
} catch {}
|
|
11768
11845
|
freshnessCache = {
|
|
11769
11846
|
rootDir,
|
|
11770
|
-
result,
|
|
11847
|
+
result: { indexed: totalIndexed, removed: totalRemoved, unchanged: totalUnchanged },
|
|
11771
11848
|
timestamp: Date.now(),
|
|
11772
11849
|
manifestMtime: finalManifestMtime
|
|
11773
11850
|
};
|
|
@@ -11909,16 +11986,13 @@ async function indexWithModule(rootDir, files, module2, config, verbose, introsp
|
|
|
11909
11986
|
async function findFiles(rootDir, config) {
|
|
11910
11987
|
const patterns = config.extensions.map((ext) => `**/*${ext}`);
|
|
11911
11988
|
const ignorePatterns = config.ignorePaths.map((p) => `**/${p}/**`);
|
|
11912
|
-
const
|
|
11913
|
-
|
|
11914
|
-
|
|
11915
|
-
|
|
11916
|
-
|
|
11917
|
-
|
|
11918
|
-
|
|
11919
|
-
files.push(...matches);
|
|
11920
|
-
}
|
|
11921
|
-
return [...new Set(files)];
|
|
11989
|
+
const results = await Promise.all(patterns.map((pattern) => glob(pattern, {
|
|
11990
|
+
cwd: rootDir,
|
|
11991
|
+
absolute: true,
|
|
11992
|
+
ignore: ignorePatterns
|
|
11993
|
+
})));
|
|
11994
|
+
const allFiles = results.flat();
|
|
11995
|
+
return [...new Set(allFiles)];
|
|
11922
11996
|
}
|
|
11923
11997
|
async function loadModuleManifest(rootDir, moduleId, config) {
|
|
11924
11998
|
const manifestPath = getModuleManifestPath(rootDir, moduleId, config);
|
|
@@ -12087,7 +12161,7 @@ async function getIndexStatus(rootDir) {
|
|
|
12087
12161
|
}
|
|
12088
12162
|
return status;
|
|
12089
12163
|
}
|
|
12090
|
-
var FRESHNESS_CACHE_TTL_MS = 5000, freshnessCache = null, INDEX_SCHEMA_VERSION = "2.0.0", DEFAULT_CONCURRENCY;
|
|
12164
|
+
var FRESHNESS_CACHE_TTL_MS = 5000, freshnessCache = null, INDEX_SCHEMA_VERSION = "2.0.0", DEFAULT_CONCURRENCY, STAT_CONCURRENCY;
|
|
12091
12165
|
var init_indexer = __esm(() => {
|
|
12092
12166
|
init_config2();
|
|
12093
12167
|
init_registry();
|
|
@@ -12095,6 +12169,7 @@ var init_indexer = __esm(() => {
|
|
|
12095
12169
|
init_logger();
|
|
12096
12170
|
init_watcher();
|
|
12097
12171
|
DEFAULT_CONCURRENCY = getOptimalConcurrency();
|
|
12172
|
+
STAT_CONCURRENCY = Math.max(32, getOptimalConcurrency() * 4);
|
|
12098
12173
|
});
|
|
12099
12174
|
|
|
12100
12175
|
// node_modules/balanced-match/index.js
|
|
@@ -13668,7 +13743,7 @@ init_logger();
|
|
|
13668
13743
|
// package.json
|
|
13669
13744
|
var package_default = {
|
|
13670
13745
|
name: "raggrep",
|
|
13671
|
-
version: "0.10.
|
|
13746
|
+
version: "0.10.4",
|
|
13672
13747
|
description: "Local filesystem-based RAG system for codebases - semantic search using local embeddings",
|
|
13673
13748
|
type: "module",
|
|
13674
13749
|
main: "./dist/index.js",
|
|
@@ -13765,6 +13840,7 @@ function parseFlags(args3) {
|
|
|
13765
13840
|
help: false,
|
|
13766
13841
|
verbose: false,
|
|
13767
13842
|
watch: false,
|
|
13843
|
+
timing: false,
|
|
13768
13844
|
remaining: []
|
|
13769
13845
|
};
|
|
13770
13846
|
for (let i2 = 0;i2 < args3.length; i2++) {
|
|
@@ -13775,6 +13851,8 @@ function parseFlags(args3) {
|
|
|
13775
13851
|
flags2.verbose = true;
|
|
13776
13852
|
} else if (arg === "--watch" || arg === "-w") {
|
|
13777
13853
|
flags2.watch = true;
|
|
13854
|
+
} else if (arg === "--timing" || arg === "-T") {
|
|
13855
|
+
flags2.timing = true;
|
|
13778
13856
|
} else if (arg === "--model" || arg === "-m") {
|
|
13779
13857
|
const modelName = args3[++i2];
|
|
13780
13858
|
if (modelName && modelName in EMBEDDING_MODELS) {
|
|
@@ -13933,6 +14011,7 @@ Options:
|
|
|
13933
14011
|
-s, --min-score <n> Minimum similarity score 0-1 (default: 0.15)
|
|
13934
14012
|
-t, --type <ext> Filter by file extension (e.g., ts, tsx, js)
|
|
13935
14013
|
-f, --filter <path> Filter by path or glob pattern (can be used multiple times)
|
|
14014
|
+
-T, --timing Show timing breakdown for performance profiling
|
|
13936
14015
|
-h, --help Show this help message
|
|
13937
14016
|
|
|
13938
14017
|
Note:
|
|
@@ -13986,7 +14065,8 @@ Examples:
|
|
|
13986
14065
|
const freshStats = await ensureIndexFresh2(process.cwd(), {
|
|
13987
14066
|
model: flags2.model,
|
|
13988
14067
|
quiet: true,
|
|
13989
|
-
logger: silentLogger
|
|
14068
|
+
logger: silentLogger,
|
|
14069
|
+
timing: flags2.timing
|
|
13990
14070
|
});
|
|
13991
14071
|
console.log("RAGgrep Search");
|
|
13992
14072
|
console.log(`==============
|
|
@@ -14003,6 +14083,23 @@ Examples:
|
|
|
14003
14083
|
`);
|
|
14004
14084
|
} else {
|
|
14005
14085
|
console.log(`Using cached index (no changes detected).
|
|
14086
|
+
`);
|
|
14087
|
+
}
|
|
14088
|
+
if (flags2.timing && freshStats.timing) {
|
|
14089
|
+
const t = freshStats.timing;
|
|
14090
|
+
console.log("┌─ Timing ─────────────────────────────────────┐");
|
|
14091
|
+
if (t.fromCache) {
|
|
14092
|
+
console.log(`│ Cache hit (TTL-based) │`);
|
|
14093
|
+
console.log(`│ Total: ${t.totalMs.toFixed(0).padStart(6)}ms │`);
|
|
14094
|
+
} else {
|
|
14095
|
+
console.log(`│ File discovery: ${t.fileDiscoveryMs.toFixed(0).padStart(6)}ms (${t.filesDiscovered} files)`.padEnd(47) + "│");
|
|
14096
|
+
console.log(`│ Stat checks: ${t.statCheckMs.toFixed(0).padStart(6)}ms (${t.filesStatChecked} files)`.padEnd(47) + "│");
|
|
14097
|
+
console.log(`│ Indexing: ${t.indexingMs.toFixed(0).padStart(6)}ms (${t.filesIndexed} files)`.padEnd(47) + "│");
|
|
14098
|
+
console.log(`│ Cleanup: ${t.cleanupMs.toFixed(0).padStart(6)}ms`.padEnd(47) + "│");
|
|
14099
|
+
console.log(`│ ─────────────────────────────────────────── │`);
|
|
14100
|
+
console.log(`│ Total: ${t.totalMs.toFixed(0).padStart(6)}ms`.padEnd(47) + "│");
|
|
14101
|
+
}
|
|
14102
|
+
console.log(`└──────────────────────────────────────────────┘
|
|
14006
14103
|
`);
|
|
14007
14104
|
}
|
|
14008
14105
|
const filePatterns = flags2.fileType ? [`*.${flags2.fileType}`] : undefined;
|
|
@@ -14262,4 +14359,4 @@ Run 'raggrep <command> --help' for more information.
|
|
|
14262
14359
|
}
|
|
14263
14360
|
main();
|
|
14264
14361
|
|
|
14265
|
-
//# debugId=
|
|
14362
|
+
//# debugId=5A4116C9AF3188E264756E2164756E21
|