raggrep 0.6.1 → 0.7.1
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/README.md +2 -0
- package/dist/cli/main.js +718 -123
- package/dist/cli/main.js.map +12 -8
- package/dist/domain/entities/index.d.ts +2 -0
- package/dist/domain/entities/literal.d.ts +101 -0
- package/dist/domain/services/index.d.ts +3 -0
- package/dist/domain/services/literalExtractor.d.ts +35 -0
- package/dist/domain/services/literalScorer.d.ts +93 -0
- package/dist/domain/services/queryLiteralParser.d.ts +20 -0
- package/dist/domain/services/queryLiteralParser.test.d.ts +7 -0
- package/dist/index.js +713 -118
- package/dist/index.js.map +12 -8
- package/dist/infrastructure/storage/index.d.ts +1 -0
- package/dist/infrastructure/storage/literalIndex.d.ts +111 -0
- package/dist/modules/language/typescript/index.d.ts +8 -4
- package/package.json +1 -1
package/dist/cli/main.js
CHANGED
|
@@ -430,10 +430,14 @@ var init_config = __esm(() => {
|
|
|
430
430
|
];
|
|
431
431
|
});
|
|
432
432
|
|
|
433
|
+
// src/domain/entities/literal.ts
|
|
434
|
+
var init_literal = () => {};
|
|
435
|
+
|
|
433
436
|
// src/domain/entities/index.ts
|
|
434
437
|
var init_entities = __esm(() => {
|
|
435
438
|
init_searchResult();
|
|
436
439
|
init_config();
|
|
440
|
+
init_literal();
|
|
437
441
|
});
|
|
438
442
|
|
|
439
443
|
// src/infrastructure/config/configLoader.ts
|
|
@@ -2660,10 +2664,299 @@ function generateChunkId(filepath, startLine, endLine) {
|
|
|
2660
2664
|
}
|
|
2661
2665
|
var DEFAULT_CHUNK_SIZE = 30, DEFAULT_OVERLAP = 5;
|
|
2662
2666
|
|
|
2667
|
+
// src/domain/services/queryLiteralParser.ts
|
|
2668
|
+
function parseQueryLiterals(query) {
|
|
2669
|
+
if (!query || query.trim() === "") {
|
|
2670
|
+
return { literals: [], remainingQuery: "" };
|
|
2671
|
+
}
|
|
2672
|
+
const literals = [];
|
|
2673
|
+
let remainingQuery = query;
|
|
2674
|
+
const matchedPositions = new Set;
|
|
2675
|
+
const backtickResult = extractExplicitLiterals(remainingQuery, /`([^`]+)`/g, "explicit-backtick", matchedPositions);
|
|
2676
|
+
literals.push(...backtickResult.literals);
|
|
2677
|
+
remainingQuery = backtickResult.remainingQuery;
|
|
2678
|
+
const quoteResult = extractExplicitLiterals(remainingQuery, /"([^"]+)"/g, "explicit-quote", matchedPositions);
|
|
2679
|
+
literals.push(...quoteResult.literals);
|
|
2680
|
+
remainingQuery = quoteResult.remainingQuery;
|
|
2681
|
+
const implicitLiterals = extractImplicitLiterals(query, matchedPositions);
|
|
2682
|
+
literals.push(...implicitLiterals);
|
|
2683
|
+
return {
|
|
2684
|
+
literals,
|
|
2685
|
+
remainingQuery: remainingQuery.trim()
|
|
2686
|
+
};
|
|
2687
|
+
}
|
|
2688
|
+
function extractExplicitLiterals(query, pattern, method, matchedPositions) {
|
|
2689
|
+
const literals = [];
|
|
2690
|
+
let remainingQuery = query;
|
|
2691
|
+
pattern.lastIndex = 0;
|
|
2692
|
+
let match;
|
|
2693
|
+
const replacements = [];
|
|
2694
|
+
while ((match = pattern.exec(query)) !== null) {
|
|
2695
|
+
const value = match[1];
|
|
2696
|
+
const rawValue = match[0];
|
|
2697
|
+
if (!value || value.trim() === "") {
|
|
2698
|
+
continue;
|
|
2699
|
+
}
|
|
2700
|
+
const posKey = `${match.index}:${match.index + rawValue.length}`;
|
|
2701
|
+
matchedPositions.add(posKey);
|
|
2702
|
+
matchedPositions.add(`value:${value.toLowerCase()}`);
|
|
2703
|
+
literals.push({
|
|
2704
|
+
value,
|
|
2705
|
+
rawValue,
|
|
2706
|
+
confidence: "high",
|
|
2707
|
+
detectionMethod: method,
|
|
2708
|
+
inferredType: inferTypeFromValue(value)
|
|
2709
|
+
});
|
|
2710
|
+
replacements.push({
|
|
2711
|
+
start: match.index,
|
|
2712
|
+
end: match.index + rawValue.length,
|
|
2713
|
+
text: ""
|
|
2714
|
+
});
|
|
2715
|
+
}
|
|
2716
|
+
replacements.sort((a, b) => b.start - a.start).forEach((r) => {
|
|
2717
|
+
remainingQuery = remainingQuery.slice(0, r.start) + r.text + remainingQuery.slice(r.end);
|
|
2718
|
+
});
|
|
2719
|
+
return { literals, remainingQuery };
|
|
2720
|
+
}
|
|
2721
|
+
function extractImplicitLiterals(query, matchedPositions) {
|
|
2722
|
+
const literals = [];
|
|
2723
|
+
const seenValues = new Set;
|
|
2724
|
+
for (const patternDef of IMPLICIT_PATTERNS) {
|
|
2725
|
+
patternDef.pattern.lastIndex = 0;
|
|
2726
|
+
let match;
|
|
2727
|
+
while ((match = patternDef.pattern.exec(query)) !== null) {
|
|
2728
|
+
const value = match[1];
|
|
2729
|
+
if (patternDef.minLength && value.length < patternDef.minLength) {
|
|
2730
|
+
continue;
|
|
2731
|
+
}
|
|
2732
|
+
const posKey = `${match.index}:${match.index + value.length}`;
|
|
2733
|
+
if (matchedPositions.has(posKey)) {
|
|
2734
|
+
continue;
|
|
2735
|
+
}
|
|
2736
|
+
if (matchedPositions.has(`value:${value.toLowerCase()}`)) {
|
|
2737
|
+
continue;
|
|
2738
|
+
}
|
|
2739
|
+
const lowerValue = value.toLowerCase();
|
|
2740
|
+
if (seenValues.has(lowerValue)) {
|
|
2741
|
+
continue;
|
|
2742
|
+
}
|
|
2743
|
+
seenValues.add(lowerValue);
|
|
2744
|
+
if (isCommonWord(value)) {
|
|
2745
|
+
continue;
|
|
2746
|
+
}
|
|
2747
|
+
literals.push({
|
|
2748
|
+
value,
|
|
2749
|
+
rawValue: value,
|
|
2750
|
+
confidence: patternDef.confidence,
|
|
2751
|
+
detectionMethod: "implicit-casing",
|
|
2752
|
+
inferredType: patternDef.inferredType
|
|
2753
|
+
});
|
|
2754
|
+
}
|
|
2755
|
+
}
|
|
2756
|
+
return literals;
|
|
2757
|
+
}
|
|
2758
|
+
function inferTypeFromValue(value) {
|
|
2759
|
+
if (/^[A-Z][a-z]+(?:[A-Z][a-z0-9]*)+$/.test(value)) {
|
|
2760
|
+
return "className";
|
|
2761
|
+
}
|
|
2762
|
+
if (/^[a-z][a-z0-9]*(?:[A-Z][a-zA-Z0-9]*)+$/.test(value)) {
|
|
2763
|
+
return "functionName";
|
|
2764
|
+
}
|
|
2765
|
+
if (/^[A-Z][A-Z0-9]*(?:_[A-Z0-9]+)+$/.test(value)) {
|
|
2766
|
+
return "variableName";
|
|
2767
|
+
}
|
|
2768
|
+
if (/^[a-z][a-z0-9]*(?:_[a-z0-9]+)+$/.test(value)) {
|
|
2769
|
+
return "identifier";
|
|
2770
|
+
}
|
|
2771
|
+
if (/^[a-z][a-z0-9]*(?:-[a-z0-9]+)+$/.test(value)) {
|
|
2772
|
+
return "packageName";
|
|
2773
|
+
}
|
|
2774
|
+
return;
|
|
2775
|
+
}
|
|
2776
|
+
function isCommonWord(word) {
|
|
2777
|
+
const commonWords = new Set([
|
|
2778
|
+
"find",
|
|
2779
|
+
"the",
|
|
2780
|
+
"a",
|
|
2781
|
+
"an",
|
|
2782
|
+
"is",
|
|
2783
|
+
"are",
|
|
2784
|
+
"was",
|
|
2785
|
+
"were",
|
|
2786
|
+
"what",
|
|
2787
|
+
"where",
|
|
2788
|
+
"when",
|
|
2789
|
+
"how",
|
|
2790
|
+
"why",
|
|
2791
|
+
"which",
|
|
2792
|
+
"who",
|
|
2793
|
+
"this",
|
|
2794
|
+
"that",
|
|
2795
|
+
"these",
|
|
2796
|
+
"those",
|
|
2797
|
+
"and",
|
|
2798
|
+
"or",
|
|
2799
|
+
"but",
|
|
2800
|
+
"for",
|
|
2801
|
+
"with",
|
|
2802
|
+
"from",
|
|
2803
|
+
"to",
|
|
2804
|
+
"in",
|
|
2805
|
+
"on",
|
|
2806
|
+
"at",
|
|
2807
|
+
"by",
|
|
2808
|
+
"of",
|
|
2809
|
+
"all",
|
|
2810
|
+
"any",
|
|
2811
|
+
"some",
|
|
2812
|
+
"get",
|
|
2813
|
+
"set",
|
|
2814
|
+
"new",
|
|
2815
|
+
"class",
|
|
2816
|
+
"function",
|
|
2817
|
+
"const",
|
|
2818
|
+
"let",
|
|
2819
|
+
"var",
|
|
2820
|
+
"type",
|
|
2821
|
+
"interface",
|
|
2822
|
+
"import",
|
|
2823
|
+
"export",
|
|
2824
|
+
"default",
|
|
2825
|
+
"return",
|
|
2826
|
+
"async",
|
|
2827
|
+
"await",
|
|
2828
|
+
"null",
|
|
2829
|
+
"undefined",
|
|
2830
|
+
"true",
|
|
2831
|
+
"false"
|
|
2832
|
+
]);
|
|
2833
|
+
return commonWords.has(word.toLowerCase());
|
|
2834
|
+
}
|
|
2835
|
+
var IMPLICIT_PATTERNS;
|
|
2836
|
+
var init_queryLiteralParser = __esm(() => {
|
|
2837
|
+
IMPLICIT_PATTERNS = [
|
|
2838
|
+
{
|
|
2839
|
+
pattern: /\b([A-Z][a-z]+(?:[A-Z][a-z0-9]*)+)\b/g,
|
|
2840
|
+
confidence: "medium",
|
|
2841
|
+
inferredType: "className",
|
|
2842
|
+
minLength: 3
|
|
2843
|
+
},
|
|
2844
|
+
{
|
|
2845
|
+
pattern: /\b([a-z][a-z0-9]*(?:[A-Z][a-zA-Z0-9]*)+)\b/g,
|
|
2846
|
+
confidence: "medium",
|
|
2847
|
+
inferredType: "functionName",
|
|
2848
|
+
minLength: 3
|
|
2849
|
+
},
|
|
2850
|
+
{
|
|
2851
|
+
pattern: /\b([A-Z][A-Z0-9]*(?:_[A-Z0-9]+)+)\b/g,
|
|
2852
|
+
confidence: "medium",
|
|
2853
|
+
inferredType: "variableName",
|
|
2854
|
+
minLength: 3
|
|
2855
|
+
},
|
|
2856
|
+
{
|
|
2857
|
+
pattern: /\b([a-z][a-z0-9]*(?:_[a-z0-9]+)+)\b/g,
|
|
2858
|
+
confidence: "low",
|
|
2859
|
+
inferredType: "identifier",
|
|
2860
|
+
minLength: 3
|
|
2861
|
+
},
|
|
2862
|
+
{
|
|
2863
|
+
pattern: /(?<![/:.])\b([a-z][a-z0-9]*(?:-[a-z0-9]+)+)\b(?![/:])/g,
|
|
2864
|
+
confidence: "low",
|
|
2865
|
+
inferredType: "packageName",
|
|
2866
|
+
minLength: 3
|
|
2867
|
+
}
|
|
2868
|
+
];
|
|
2869
|
+
});
|
|
2870
|
+
|
|
2871
|
+
// src/domain/services/literalExtractor.ts
|
|
2872
|
+
function extractLiterals(chunk) {
|
|
2873
|
+
const literals = [];
|
|
2874
|
+
if (chunk.name) {
|
|
2875
|
+
const literalType = CHUNK_TYPE_TO_LITERAL_TYPE[chunk.type] || "identifier";
|
|
2876
|
+
literals.push({
|
|
2877
|
+
value: chunk.name,
|
|
2878
|
+
type: literalType,
|
|
2879
|
+
matchType: "definition"
|
|
2880
|
+
});
|
|
2881
|
+
}
|
|
2882
|
+
return literals;
|
|
2883
|
+
}
|
|
2884
|
+
var CHUNK_TYPE_TO_LITERAL_TYPE;
|
|
2885
|
+
var init_literalExtractor = __esm(() => {
|
|
2886
|
+
CHUNK_TYPE_TO_LITERAL_TYPE = {
|
|
2887
|
+
class: "className",
|
|
2888
|
+
function: "functionName",
|
|
2889
|
+
interface: "interfaceName",
|
|
2890
|
+
type: "typeName",
|
|
2891
|
+
enum: "enumName",
|
|
2892
|
+
variable: "variableName"
|
|
2893
|
+
};
|
|
2894
|
+
});
|
|
2895
|
+
|
|
2896
|
+
// src/domain/services/literalScorer.ts
|
|
2897
|
+
function calculateLiteralMultiplier(matchType, confidence) {
|
|
2898
|
+
return LITERAL_SCORING_CONSTANTS.MULTIPLIERS[matchType][confidence];
|
|
2899
|
+
}
|
|
2900
|
+
function calculateMaxMultiplier(matches) {
|
|
2901
|
+
if (!matches || matches.length === 0) {
|
|
2902
|
+
return 1;
|
|
2903
|
+
}
|
|
2904
|
+
return Math.max(...matches.map((m) => calculateLiteralMultiplier(m.indexedLiteral.matchType, m.queryLiteral.confidence)));
|
|
2905
|
+
}
|
|
2906
|
+
function calculateLiteralContribution(matches, hasSemanticOrBm25) {
|
|
2907
|
+
if (!matches || matches.length === 0) {
|
|
2908
|
+
return {
|
|
2909
|
+
multiplier: 1,
|
|
2910
|
+
literalOnly: false,
|
|
2911
|
+
matchCount: 0
|
|
2912
|
+
};
|
|
2913
|
+
}
|
|
2914
|
+
let bestMatch = null;
|
|
2915
|
+
let bestMultiplier = 0;
|
|
2916
|
+
for (const match of matches) {
|
|
2917
|
+
const mult = calculateLiteralMultiplier(match.indexedLiteral.matchType, match.queryLiteral.confidence);
|
|
2918
|
+
if (mult > bestMultiplier) {
|
|
2919
|
+
bestMultiplier = mult;
|
|
2920
|
+
bestMatch = match;
|
|
2921
|
+
}
|
|
2922
|
+
}
|
|
2923
|
+
return {
|
|
2924
|
+
multiplier: bestMultiplier,
|
|
2925
|
+
literalOnly: !hasSemanticOrBm25,
|
|
2926
|
+
bestMatchType: bestMatch?.indexedLiteral.matchType,
|
|
2927
|
+
bestConfidence: bestMatch?.queryLiteral.confidence,
|
|
2928
|
+
matchCount: matches.length
|
|
2929
|
+
};
|
|
2930
|
+
}
|
|
2931
|
+
function applyLiteralBoost(baseScore, matches, hasSemanticOrBm25) {
|
|
2932
|
+
if (!matches || matches.length === 0) {
|
|
2933
|
+
return baseScore;
|
|
2934
|
+
}
|
|
2935
|
+
const multiplier = calculateMaxMultiplier(matches);
|
|
2936
|
+
if (!hasSemanticOrBm25) {
|
|
2937
|
+
return LITERAL_SCORING_CONSTANTS.BASE_SCORE * multiplier;
|
|
2938
|
+
}
|
|
2939
|
+
return baseScore * multiplier;
|
|
2940
|
+
}
|
|
2941
|
+
var LITERAL_SCORING_CONSTANTS;
|
|
2942
|
+
var init_literalScorer = __esm(() => {
|
|
2943
|
+
LITERAL_SCORING_CONSTANTS = {
|
|
2944
|
+
BASE_SCORE: 0.5,
|
|
2945
|
+
MULTIPLIERS: {
|
|
2946
|
+
definition: { high: 2.5, medium: 2, low: 1.5 },
|
|
2947
|
+
reference: { high: 2, medium: 1.5, low: 1.3 },
|
|
2948
|
+
import: { high: 1.5, medium: 1.3, low: 1.1 }
|
|
2949
|
+
}
|
|
2950
|
+
};
|
|
2951
|
+
});
|
|
2952
|
+
|
|
2663
2953
|
// src/domain/services/index.ts
|
|
2664
2954
|
var init_services = __esm(() => {
|
|
2665
2955
|
init_keywords();
|
|
2666
2956
|
init_queryIntent();
|
|
2957
|
+
init_queryLiteralParser();
|
|
2958
|
+
init_literalExtractor();
|
|
2959
|
+
init_literalScorer();
|
|
2667
2960
|
});
|
|
2668
2961
|
|
|
2669
2962
|
// src/modules/language/typescript/parseCode.ts
|
|
@@ -2983,10 +3276,182 @@ var init_symbolicIndex = __esm(() => {
|
|
|
2983
3276
|
init_keywords();
|
|
2984
3277
|
});
|
|
2985
3278
|
|
|
3279
|
+
// src/infrastructure/storage/literalIndex.ts
|
|
3280
|
+
var exports_literalIndex = {};
|
|
3281
|
+
__export(exports_literalIndex, {
|
|
3282
|
+
getLiteralIndexPath: () => getLiteralIndexPath,
|
|
3283
|
+
LiteralIndex: () => LiteralIndex
|
|
3284
|
+
});
|
|
3285
|
+
import * as fs4 from "fs/promises";
|
|
3286
|
+
import * as path9 from "path";
|
|
3287
|
+
|
|
3288
|
+
class LiteralIndex {
|
|
3289
|
+
indexPath;
|
|
3290
|
+
moduleId;
|
|
3291
|
+
entries = new Map;
|
|
3292
|
+
static VERSION = "1.0.0";
|
|
3293
|
+
constructor(indexDir, moduleId) {
|
|
3294
|
+
this.indexPath = path9.join(indexDir, "index", moduleId, "literals");
|
|
3295
|
+
this.moduleId = moduleId;
|
|
3296
|
+
}
|
|
3297
|
+
async initialize() {
|
|
3298
|
+
try {
|
|
3299
|
+
await this.load();
|
|
3300
|
+
} catch {
|
|
3301
|
+
this.entries = new Map;
|
|
3302
|
+
}
|
|
3303
|
+
}
|
|
3304
|
+
addLiterals(chunkId, filepath, literals) {
|
|
3305
|
+
for (const literal of literals) {
|
|
3306
|
+
const key = literal.value.toLowerCase();
|
|
3307
|
+
const existingEntries = this.entries.get(key) || [];
|
|
3308
|
+
const existingIndex = existingEntries.findIndex((e) => e.chunkId === chunkId);
|
|
3309
|
+
const newEntry = {
|
|
3310
|
+
chunkId,
|
|
3311
|
+
filepath,
|
|
3312
|
+
originalCasing: literal.value,
|
|
3313
|
+
type: literal.type,
|
|
3314
|
+
matchType: literal.matchType
|
|
3315
|
+
};
|
|
3316
|
+
if (existingIndex >= 0) {
|
|
3317
|
+
const existing = existingEntries[existingIndex];
|
|
3318
|
+
if (shouldReplaceMatchType(existing.matchType, literal.matchType)) {
|
|
3319
|
+
existingEntries[existingIndex] = newEntry;
|
|
3320
|
+
}
|
|
3321
|
+
} else {
|
|
3322
|
+
existingEntries.push(newEntry);
|
|
3323
|
+
}
|
|
3324
|
+
this.entries.set(key, existingEntries);
|
|
3325
|
+
}
|
|
3326
|
+
}
|
|
3327
|
+
removeChunk(chunkId) {
|
|
3328
|
+
for (const [key, entries] of this.entries) {
|
|
3329
|
+
const filtered = entries.filter((e) => e.chunkId !== chunkId);
|
|
3330
|
+
if (filtered.length === 0) {
|
|
3331
|
+
this.entries.delete(key);
|
|
3332
|
+
} else if (filtered.length !== entries.length) {
|
|
3333
|
+
this.entries.set(key, filtered);
|
|
3334
|
+
}
|
|
3335
|
+
}
|
|
3336
|
+
}
|
|
3337
|
+
removeFile(filepath) {
|
|
3338
|
+
let removed = 0;
|
|
3339
|
+
for (const [key, entries] of this.entries) {
|
|
3340
|
+
const filtered = entries.filter((e) => e.filepath !== filepath);
|
|
3341
|
+
const removedCount = entries.length - filtered.length;
|
|
3342
|
+
if (removedCount > 0) {
|
|
3343
|
+
removed += removedCount;
|
|
3344
|
+
if (filtered.length === 0) {
|
|
3345
|
+
this.entries.delete(key);
|
|
3346
|
+
} else {
|
|
3347
|
+
this.entries.set(key, filtered);
|
|
3348
|
+
}
|
|
3349
|
+
}
|
|
3350
|
+
}
|
|
3351
|
+
return removed;
|
|
3352
|
+
}
|
|
3353
|
+
findMatches(queryLiterals) {
|
|
3354
|
+
const matches = [];
|
|
3355
|
+
for (const queryLiteral of queryLiterals) {
|
|
3356
|
+
const key = queryLiteral.value.toLowerCase();
|
|
3357
|
+
const entries = this.entries.get(key);
|
|
3358
|
+
if (!entries) {
|
|
3359
|
+
continue;
|
|
3360
|
+
}
|
|
3361
|
+
for (const entry of entries) {
|
|
3362
|
+
const exactMatch = entry.originalCasing === queryLiteral.value;
|
|
3363
|
+
matches.push({
|
|
3364
|
+
queryLiteral,
|
|
3365
|
+
indexedLiteral: {
|
|
3366
|
+
value: entry.originalCasing,
|
|
3367
|
+
type: entry.type,
|
|
3368
|
+
matchType: entry.matchType
|
|
3369
|
+
},
|
|
3370
|
+
chunkId: entry.chunkId,
|
|
3371
|
+
filepath: entry.filepath,
|
|
3372
|
+
exactMatch
|
|
3373
|
+
});
|
|
3374
|
+
}
|
|
3375
|
+
}
|
|
3376
|
+
return matches;
|
|
3377
|
+
}
|
|
3378
|
+
getChunksForLiteral(literal) {
|
|
3379
|
+
const key = literal.toLowerCase();
|
|
3380
|
+
const entries = this.entries.get(key);
|
|
3381
|
+
return entries ? entries.map((e) => e.chunkId) : [];
|
|
3382
|
+
}
|
|
3383
|
+
async save() {
|
|
3384
|
+
await fs4.mkdir(this.indexPath, { recursive: true });
|
|
3385
|
+
const data = {
|
|
3386
|
+
version: LiteralIndex.VERSION,
|
|
3387
|
+
entries: Object.fromEntries(this.entries)
|
|
3388
|
+
};
|
|
3389
|
+
const indexFile = path9.join(this.indexPath, "_index.json");
|
|
3390
|
+
await fs4.writeFile(indexFile, JSON.stringify(data, null, 2));
|
|
3391
|
+
}
|
|
3392
|
+
async load() {
|
|
3393
|
+
const indexFile = path9.join(this.indexPath, "_index.json");
|
|
3394
|
+
const content = await fs4.readFile(indexFile, "utf-8");
|
|
3395
|
+
const data = JSON.parse(content);
|
|
3396
|
+
if (data.version !== LiteralIndex.VERSION) {
|
|
3397
|
+
console.warn(`Literal index version mismatch: expected ${LiteralIndex.VERSION}, got ${data.version}`);
|
|
3398
|
+
}
|
|
3399
|
+
this.entries = new Map(Object.entries(data.entries));
|
|
3400
|
+
}
|
|
3401
|
+
async exists() {
|
|
3402
|
+
try {
|
|
3403
|
+
const indexFile = path9.join(this.indexPath, "_index.json");
|
|
3404
|
+
await fs4.access(indexFile);
|
|
3405
|
+
return true;
|
|
3406
|
+
} catch {
|
|
3407
|
+
return false;
|
|
3408
|
+
}
|
|
3409
|
+
}
|
|
3410
|
+
clear() {
|
|
3411
|
+
this.entries.clear();
|
|
3412
|
+
}
|
|
3413
|
+
get size() {
|
|
3414
|
+
return this.entries.size;
|
|
3415
|
+
}
|
|
3416
|
+
get totalMappings() {
|
|
3417
|
+
let count = 0;
|
|
3418
|
+
for (const entries of this.entries.values()) {
|
|
3419
|
+
count += entries.length;
|
|
3420
|
+
}
|
|
3421
|
+
return count;
|
|
3422
|
+
}
|
|
3423
|
+
getAllLiterals() {
|
|
3424
|
+
return Array.from(this.entries.keys());
|
|
3425
|
+
}
|
|
3426
|
+
buildMatchMap(queryLiterals) {
|
|
3427
|
+
const matches = this.findMatches(queryLiterals);
|
|
3428
|
+
const matchMap = new Map;
|
|
3429
|
+
for (const match of matches) {
|
|
3430
|
+
const existing = matchMap.get(match.chunkId) || [];
|
|
3431
|
+
existing.push(match);
|
|
3432
|
+
matchMap.set(match.chunkId, existing);
|
|
3433
|
+
}
|
|
3434
|
+
return matchMap;
|
|
3435
|
+
}
|
|
3436
|
+
}
|
|
3437
|
+
function shouldReplaceMatchType(existing, incoming) {
|
|
3438
|
+
const priority = {
|
|
3439
|
+
definition: 3,
|
|
3440
|
+
reference: 2,
|
|
3441
|
+
import: 1
|
|
3442
|
+
};
|
|
3443
|
+
return priority[incoming] > priority[existing];
|
|
3444
|
+
}
|
|
3445
|
+
function getLiteralIndexPath(rootDir, moduleId, indexDir = ".raggrep") {
|
|
3446
|
+
return path9.join(rootDir, indexDir, "index", moduleId, "literals");
|
|
3447
|
+
}
|
|
3448
|
+
var init_literalIndex = () => {};
|
|
3449
|
+
|
|
2986
3450
|
// src/infrastructure/storage/index.ts
|
|
2987
3451
|
var init_storage = __esm(() => {
|
|
2988
3452
|
init_fileIndexStorage();
|
|
2989
3453
|
init_symbolicIndex();
|
|
3454
|
+
init_literalIndex();
|
|
2990
3455
|
});
|
|
2991
3456
|
|
|
2992
3457
|
// src/modules/language/typescript/index.ts
|
|
@@ -2999,9 +3464,9 @@ __export(exports_typescript, {
|
|
|
2999
3464
|
DEFAULT_TOP_K: () => DEFAULT_TOP_K2,
|
|
3000
3465
|
DEFAULT_MIN_SCORE: () => DEFAULT_MIN_SCORE2
|
|
3001
3466
|
});
|
|
3002
|
-
import * as
|
|
3467
|
+
import * as path10 from "path";
|
|
3003
3468
|
function isTypeScriptFile(filepath) {
|
|
3004
|
-
const ext =
|
|
3469
|
+
const ext = path10.extname(filepath).toLowerCase();
|
|
3005
3470
|
return TYPESCRIPT_EXTENSIONS.includes(ext);
|
|
3006
3471
|
}
|
|
3007
3472
|
function calculateChunkTypeBoost(chunk) {
|
|
@@ -3036,7 +3501,9 @@ class TypeScriptModule {
|
|
|
3036
3501
|
}
|
|
3037
3502
|
embeddingConfig = null;
|
|
3038
3503
|
symbolicIndex = null;
|
|
3504
|
+
literalIndex = null;
|
|
3039
3505
|
pendingSummaries = new Map;
|
|
3506
|
+
pendingLiterals = new Map;
|
|
3040
3507
|
rootDir = "";
|
|
3041
3508
|
logger = undefined;
|
|
3042
3509
|
async initialize(config) {
|
|
@@ -3050,6 +3517,7 @@ class TypeScriptModule {
|
|
|
3050
3517
|
}
|
|
3051
3518
|
configureEmbeddings(this.embeddingConfig);
|
|
3052
3519
|
this.pendingSummaries.clear();
|
|
3520
|
+
this.pendingLiterals.clear();
|
|
3053
3521
|
}
|
|
3054
3522
|
async indexFile(filepath, content, ctx) {
|
|
3055
3523
|
if (!isTypeScriptFile(filepath)) {
|
|
@@ -3109,6 +3577,17 @@ class TypeScriptModule {
|
|
|
3109
3577
|
}
|
|
3110
3578
|
};
|
|
3111
3579
|
this.pendingSummaries.set(filepath, fileSummary);
|
|
3580
|
+
for (const chunk of chunks) {
|
|
3581
|
+
const literals = extractLiterals(chunk);
|
|
3582
|
+
if (literals.length > 0) {
|
|
3583
|
+
const existing = this.pendingLiterals.get(chunk.id);
|
|
3584
|
+
if (existing) {
|
|
3585
|
+
existing.literals.push(...literals);
|
|
3586
|
+
} else {
|
|
3587
|
+
this.pendingLiterals.set(chunk.id, { filepath, literals });
|
|
3588
|
+
}
|
|
3589
|
+
}
|
|
3590
|
+
}
|
|
3112
3591
|
return {
|
|
3113
3592
|
filepath,
|
|
3114
3593
|
lastModified: stats.lastModified,
|
|
@@ -3126,7 +3605,24 @@ class TypeScriptModule {
|
|
|
3126
3605
|
}
|
|
3127
3606
|
this.symbolicIndex.buildBM25Index();
|
|
3128
3607
|
await this.symbolicIndex.save();
|
|
3608
|
+
this.literalIndex = new LiteralIndex(indexDir, this.id);
|
|
3609
|
+
await this.literalIndex.initialize();
|
|
3610
|
+
const indexedFilepaths = new Set;
|
|
3611
|
+
for (const filepath of this.pendingSummaries.keys()) {
|
|
3612
|
+
indexedFilepaths.add(filepath);
|
|
3613
|
+
}
|
|
3614
|
+
for (const { filepath } of this.pendingLiterals.values()) {
|
|
3615
|
+
indexedFilepaths.add(filepath);
|
|
3616
|
+
}
|
|
3617
|
+
for (const filepath of indexedFilepaths) {
|
|
3618
|
+
this.literalIndex.removeFile(filepath);
|
|
3619
|
+
}
|
|
3620
|
+
for (const [chunkId, { filepath, literals }] of this.pendingLiterals) {
|
|
3621
|
+
this.literalIndex.addLiterals(chunkId, filepath, literals);
|
|
3622
|
+
}
|
|
3623
|
+
await this.literalIndex.save();
|
|
3129
3624
|
this.pendingSummaries.clear();
|
|
3625
|
+
this.pendingLiterals.clear();
|
|
3130
3626
|
}
|
|
3131
3627
|
async search(query, ctx, options = {}) {
|
|
3132
3628
|
const {
|
|
@@ -3134,8 +3630,15 @@ class TypeScriptModule {
|
|
|
3134
3630
|
minScore = DEFAULT_MIN_SCORE2,
|
|
3135
3631
|
filePatterns
|
|
3136
3632
|
} = options;
|
|
3633
|
+
const { literals: queryLiterals, remainingQuery } = parseQueryLiterals(query);
|
|
3137
3634
|
const indexDir = getRaggrepDir(ctx.rootDir, ctx.config);
|
|
3138
3635
|
const symbolicIndex = new SymbolicIndex(indexDir, this.id);
|
|
3636
|
+
const literalIndex = new LiteralIndex(indexDir, this.id);
|
|
3637
|
+
let literalMatchMap = new Map;
|
|
3638
|
+
try {
|
|
3639
|
+
await literalIndex.initialize();
|
|
3640
|
+
literalMatchMap = literalIndex.buildMatchMap(queryLiterals);
|
|
3641
|
+
} catch {}
|
|
3139
3642
|
let allFiles;
|
|
3140
3643
|
try {
|
|
3141
3644
|
await symbolicIndex.initialize();
|
|
@@ -3155,7 +3658,8 @@ class TypeScriptModule {
|
|
|
3155
3658
|
});
|
|
3156
3659
|
});
|
|
3157
3660
|
}
|
|
3158
|
-
const
|
|
3661
|
+
const semanticQuery = remainingQuery.trim() || query;
|
|
3662
|
+
const queryEmbedding = await getEmbedding(semanticQuery);
|
|
3159
3663
|
const bm25Index = new BM25Index;
|
|
3160
3664
|
const allChunksData = [];
|
|
3161
3665
|
for (const filepath of filesToSearch) {
|
|
@@ -3189,14 +3693,14 @@ class TypeScriptModule {
|
|
|
3189
3693
|
const summary = symbolicIndex.getFileSummary(filepath);
|
|
3190
3694
|
if (summary?.pathContext) {
|
|
3191
3695
|
let boost = 0;
|
|
3192
|
-
const
|
|
3193
|
-
if (
|
|
3696
|
+
const pathCtx = summary.pathContext;
|
|
3697
|
+
if (pathCtx.domain && queryTerms.some((t) => pathCtx.domain.includes(t) || t.includes(pathCtx.domain))) {
|
|
3194
3698
|
boost += 0.1;
|
|
3195
3699
|
}
|
|
3196
|
-
if (
|
|
3700
|
+
if (pathCtx.layer && queryTerms.some((t) => pathCtx.layer.includes(t) || t.includes(pathCtx.layer))) {
|
|
3197
3701
|
boost += 0.05;
|
|
3198
3702
|
}
|
|
3199
|
-
const segmentMatch =
|
|
3703
|
+
const segmentMatch = pathCtx.segments.some((seg) => queryTerms.some((t) => seg.toLowerCase().includes(t) || t.includes(seg.toLowerCase())));
|
|
3200
3704
|
if (segmentMatch) {
|
|
3201
3705
|
boost += 0.05;
|
|
3202
3706
|
}
|
|
@@ -3204,6 +3708,7 @@ class TypeScriptModule {
|
|
|
3204
3708
|
}
|
|
3205
3709
|
}
|
|
3206
3710
|
const results = [];
|
|
3711
|
+
const processedChunkIds = new Set;
|
|
3207
3712
|
for (const { filepath, chunk, embedding } of allChunksData) {
|
|
3208
3713
|
const semanticScore = cosineSimilarity(queryEmbedding, embedding);
|
|
3209
3714
|
const bm25Score = bm25Scores.get(chunk.id) || 0;
|
|
@@ -3211,13 +3716,18 @@ class TypeScriptModule {
|
|
|
3211
3716
|
const fileTypeBoost = calculateFileTypeBoost(filepath, queryTerms);
|
|
3212
3717
|
const chunkTypeBoost = calculateChunkTypeBoost(chunk);
|
|
3213
3718
|
const exportBoost = calculateExportBoost(chunk);
|
|
3214
|
-
const
|
|
3215
|
-
const
|
|
3216
|
-
|
|
3719
|
+
const additiveBoost = pathBoost + fileTypeBoost + chunkTypeBoost + exportBoost;
|
|
3720
|
+
const baseScore = SEMANTIC_WEIGHT * semanticScore + BM25_WEIGHT * bm25Score;
|
|
3721
|
+
const literalMatches = literalMatchMap.get(chunk.id) || [];
|
|
3722
|
+
const literalContribution = calculateLiteralContribution(literalMatches, true);
|
|
3723
|
+
const boostedScore = applyLiteralBoost(baseScore, literalMatches, true);
|
|
3724
|
+
const finalScore = boostedScore + additiveBoost;
|
|
3725
|
+
processedChunkIds.add(chunk.id);
|
|
3726
|
+
if (finalScore >= minScore || bm25Score > 0.3 || literalMatches.length > 0) {
|
|
3217
3727
|
results.push({
|
|
3218
3728
|
filepath,
|
|
3219
3729
|
chunk,
|
|
3220
|
-
score:
|
|
3730
|
+
score: finalScore,
|
|
3221
3731
|
moduleId: this.id,
|
|
3222
3732
|
context: {
|
|
3223
3733
|
semanticScore,
|
|
@@ -3225,7 +3735,78 @@ class TypeScriptModule {
|
|
|
3225
3735
|
pathBoost,
|
|
3226
3736
|
fileTypeBoost,
|
|
3227
3737
|
chunkTypeBoost,
|
|
3228
|
-
exportBoost
|
|
3738
|
+
exportBoost,
|
|
3739
|
+
literalMultiplier: literalContribution.multiplier,
|
|
3740
|
+
literalMatchType: literalContribution.bestMatchType,
|
|
3741
|
+
literalConfidence: literalContribution.bestConfidence,
|
|
3742
|
+
literalMatchCount: literalContribution.matchCount
|
|
3743
|
+
}
|
|
3744
|
+
});
|
|
3745
|
+
}
|
|
3746
|
+
}
|
|
3747
|
+
const literalOnlyFiles = new Map;
|
|
3748
|
+
for (const [chunkId, matches] of literalMatchMap) {
|
|
3749
|
+
if (processedChunkIds.has(chunkId)) {
|
|
3750
|
+
continue;
|
|
3751
|
+
}
|
|
3752
|
+
const filepath = matches[0]?.filepath;
|
|
3753
|
+
if (!filepath)
|
|
3754
|
+
continue;
|
|
3755
|
+
const existing = literalOnlyFiles.get(filepath) || [];
|
|
3756
|
+
existing.push(...matches);
|
|
3757
|
+
literalOnlyFiles.set(filepath, existing);
|
|
3758
|
+
}
|
|
3759
|
+
for (const [filepath, matches] of literalOnlyFiles) {
|
|
3760
|
+
const fileIndex = await ctx.loadFileIndex(filepath);
|
|
3761
|
+
if (!fileIndex)
|
|
3762
|
+
continue;
|
|
3763
|
+
const moduleData = fileIndex.moduleData;
|
|
3764
|
+
const chunkMatches = new Map;
|
|
3765
|
+
for (const match of matches) {
|
|
3766
|
+
const existing = chunkMatches.get(match.chunkId) || [];
|
|
3767
|
+
existing.push(match);
|
|
3768
|
+
chunkMatches.set(match.chunkId, existing);
|
|
3769
|
+
}
|
|
3770
|
+
for (const [chunkId, chunkLiteralMatches] of chunkMatches) {
|
|
3771
|
+
if (processedChunkIds.has(chunkId))
|
|
3772
|
+
continue;
|
|
3773
|
+
const chunkIndex = fileIndex.chunks.findIndex((c) => c.id === chunkId);
|
|
3774
|
+
if (chunkIndex === -1)
|
|
3775
|
+
continue;
|
|
3776
|
+
const chunk = fileIndex.chunks[chunkIndex];
|
|
3777
|
+
const embedding = moduleData?.embeddings?.[chunkIndex];
|
|
3778
|
+
let semanticScore = 0;
|
|
3779
|
+
if (embedding) {
|
|
3780
|
+
semanticScore = cosineSimilarity(queryEmbedding, embedding);
|
|
3781
|
+
}
|
|
3782
|
+
const bm25Score = bm25Scores.get(chunkId) || 0;
|
|
3783
|
+
const pathBoost = pathBoosts.get(filepath) || 0;
|
|
3784
|
+
const fileTypeBoost = calculateFileTypeBoost(filepath, queryTerms);
|
|
3785
|
+
const chunkTypeBoost = calculateChunkTypeBoost(chunk);
|
|
3786
|
+
const exportBoost = calculateExportBoost(chunk);
|
|
3787
|
+
const additiveBoost = pathBoost + fileTypeBoost + chunkTypeBoost + exportBoost;
|
|
3788
|
+
const literalContribution = calculateLiteralContribution(chunkLiteralMatches, false);
|
|
3789
|
+
const baseScore = semanticScore > 0 ? SEMANTIC_WEIGHT * semanticScore + BM25_WEIGHT * bm25Score : LITERAL_SCORING_CONSTANTS.BASE_SCORE;
|
|
3790
|
+
const boostedScore = applyLiteralBoost(baseScore, chunkLiteralMatches, semanticScore > 0);
|
|
3791
|
+
const finalScore = boostedScore + additiveBoost;
|
|
3792
|
+
processedChunkIds.add(chunkId);
|
|
3793
|
+
results.push({
|
|
3794
|
+
filepath,
|
|
3795
|
+
chunk,
|
|
3796
|
+
score: finalScore,
|
|
3797
|
+
moduleId: this.id,
|
|
3798
|
+
context: {
|
|
3799
|
+
semanticScore,
|
|
3800
|
+
bm25Score,
|
|
3801
|
+
pathBoost,
|
|
3802
|
+
fileTypeBoost,
|
|
3803
|
+
chunkTypeBoost,
|
|
3804
|
+
exportBoost,
|
|
3805
|
+
literalMultiplier: literalContribution.multiplier,
|
|
3806
|
+
literalMatchType: literalContribution.bestMatchType,
|
|
3807
|
+
literalConfidence: literalContribution.bestConfidence,
|
|
3808
|
+
literalMatchCount: literalContribution.matchCount,
|
|
3809
|
+
literalOnly: true
|
|
3229
3810
|
}
|
|
3230
3811
|
});
|
|
3231
3812
|
}
|
|
@@ -3241,16 +3822,16 @@ class TypeScriptModule {
|
|
|
3241
3822
|
while ((match = importRegex.exec(content)) !== null) {
|
|
3242
3823
|
const importPath = match[1];
|
|
3243
3824
|
if (importPath.startsWith(".")) {
|
|
3244
|
-
const dir =
|
|
3245
|
-
const resolved =
|
|
3825
|
+
const dir = path10.dirname(filepath);
|
|
3826
|
+
const resolved = path10.normalize(path10.join(dir, importPath));
|
|
3246
3827
|
references.push(resolved);
|
|
3247
3828
|
}
|
|
3248
3829
|
}
|
|
3249
3830
|
while ((match = requireRegex.exec(content)) !== null) {
|
|
3250
3831
|
const importPath = match[1];
|
|
3251
3832
|
if (importPath.startsWith(".")) {
|
|
3252
|
-
const dir =
|
|
3253
|
-
const resolved =
|
|
3833
|
+
const dir = path10.dirname(filepath);
|
|
3834
|
+
const resolved = path10.normalize(path10.join(dir, importPath));
|
|
3254
3835
|
references.push(resolved);
|
|
3255
3836
|
}
|
|
3256
3837
|
}
|
|
@@ -3287,9 +3868,9 @@ __export(exports_json, {
|
|
|
3287
3868
|
DEFAULT_TOP_K: () => DEFAULT_TOP_K3,
|
|
3288
3869
|
DEFAULT_MIN_SCORE: () => DEFAULT_MIN_SCORE3
|
|
3289
3870
|
});
|
|
3290
|
-
import * as
|
|
3871
|
+
import * as path11 from "path";
|
|
3291
3872
|
function isJsonFile(filepath) {
|
|
3292
|
-
const ext =
|
|
3873
|
+
const ext = path11.extname(filepath).toLowerCase();
|
|
3293
3874
|
return JSON_EXTENSIONS.includes(ext);
|
|
3294
3875
|
}
|
|
3295
3876
|
function extractJsonKeys(obj, prefix = "") {
|
|
@@ -3370,7 +3951,7 @@ class JsonModule {
|
|
|
3370
3951
|
return null;
|
|
3371
3952
|
}
|
|
3372
3953
|
const chunkContents = textChunks.map((c) => {
|
|
3373
|
-
const filename =
|
|
3954
|
+
const filename = path11.basename(filepath);
|
|
3374
3955
|
return `${filename}: ${c.content}`;
|
|
3375
3956
|
});
|
|
3376
3957
|
const embeddings = await getEmbeddings(chunkContents);
|
|
@@ -3521,9 +4102,9 @@ __export(exports_markdown, {
|
|
|
3521
4102
|
DEFAULT_TOP_K: () => DEFAULT_TOP_K4,
|
|
3522
4103
|
DEFAULT_MIN_SCORE: () => DEFAULT_MIN_SCORE4
|
|
3523
4104
|
});
|
|
3524
|
-
import * as
|
|
4105
|
+
import * as path12 from "path";
|
|
3525
4106
|
function isMarkdownFile(filepath) {
|
|
3526
|
-
const ext =
|
|
4107
|
+
const ext = path12.extname(filepath).toLowerCase();
|
|
3527
4108
|
return MARKDOWN_EXTENSIONS.includes(ext);
|
|
3528
4109
|
}
|
|
3529
4110
|
function parseMarkdownSections(content) {
|
|
@@ -3650,7 +4231,7 @@ class MarkdownModule {
|
|
|
3650
4231
|
return null;
|
|
3651
4232
|
}
|
|
3652
4233
|
const chunkContents = sections.map((s) => {
|
|
3653
|
-
const filename =
|
|
4234
|
+
const filename = path12.basename(filepath);
|
|
3654
4235
|
const headingContext = s.heading ? `${s.heading}: ` : "";
|
|
3655
4236
|
return `${filename} ${headingContext}${s.content}`;
|
|
3656
4237
|
});
|
|
@@ -3837,15 +4418,15 @@ var init_registry = __esm(() => {
|
|
|
3837
4418
|
});
|
|
3838
4419
|
|
|
3839
4420
|
// src/infrastructure/introspection/projectDetector.ts
|
|
3840
|
-
import * as
|
|
3841
|
-
import * as
|
|
4421
|
+
import * as path13 from "path";
|
|
4422
|
+
import * as fs5 from "fs/promises";
|
|
3842
4423
|
async function scanForPackageJsons(rootDir, currentDir = "", depth = 0) {
|
|
3843
4424
|
if (depth > MAX_SCAN_DEPTH)
|
|
3844
4425
|
return [];
|
|
3845
4426
|
const results = [];
|
|
3846
|
-
const fullDir = currentDir ?
|
|
4427
|
+
const fullDir = currentDir ? path13.join(rootDir, currentDir) : rootDir;
|
|
3847
4428
|
try {
|
|
3848
|
-
const entries = await
|
|
4429
|
+
const entries = await fs5.readdir(fullDir, { withFileTypes: true });
|
|
3849
4430
|
const hasPackageJson = entries.some((e) => e.isFile() && e.name === "package.json");
|
|
3850
4431
|
if (hasPackageJson && currentDir) {
|
|
3851
4432
|
const info = await parsePackageJson(rootDir, currentDir);
|
|
@@ -3866,10 +4447,10 @@ async function scanForPackageJsons(rootDir, currentDir = "", depth = 0) {
|
|
|
3866
4447
|
}
|
|
3867
4448
|
async function parsePackageJson(rootDir, relativePath) {
|
|
3868
4449
|
try {
|
|
3869
|
-
const packageJsonPath =
|
|
3870
|
-
const content = await
|
|
4450
|
+
const packageJsonPath = path13.join(rootDir, relativePath, "package.json");
|
|
4451
|
+
const content = await fs5.readFile(packageJsonPath, "utf-8");
|
|
3871
4452
|
const pkg = JSON.parse(content);
|
|
3872
|
-
const name = pkg.name ||
|
|
4453
|
+
const name = pkg.name || path13.basename(relativePath);
|
|
3873
4454
|
const deps = { ...pkg.dependencies, ...pkg.devDependencies };
|
|
3874
4455
|
let type = "unknown";
|
|
3875
4456
|
if (deps["next"] || deps["react"] || deps["vue"] || deps["svelte"]) {
|
|
@@ -3905,7 +4486,7 @@ async function detectProjectStructure(rootDir) {
|
|
|
3905
4486
|
const projectMap = new Map;
|
|
3906
4487
|
let isMonorepo = false;
|
|
3907
4488
|
try {
|
|
3908
|
-
const entries = await
|
|
4489
|
+
const entries = await fs5.readdir(rootDir, { withFileTypes: true });
|
|
3909
4490
|
const dirNames = entries.filter((e) => e.isDirectory()).map((e) => e.name);
|
|
3910
4491
|
const monorepoPatterns = ["apps", "packages", "libs", "services"];
|
|
3911
4492
|
const hasMonorepoStructure = monorepoPatterns.some((p) => dirNames.includes(p));
|
|
@@ -3914,9 +4495,9 @@ async function detectProjectStructure(rootDir) {
|
|
|
3914
4495
|
for (const pattern of monorepoPatterns) {
|
|
3915
4496
|
if (!dirNames.includes(pattern))
|
|
3916
4497
|
continue;
|
|
3917
|
-
const patternDir =
|
|
4498
|
+
const patternDir = path13.join(rootDir, pattern);
|
|
3918
4499
|
try {
|
|
3919
|
-
const subDirs = await
|
|
4500
|
+
const subDirs = await fs5.readdir(patternDir, { withFileTypes: true });
|
|
3920
4501
|
for (const subDir of subDirs) {
|
|
3921
4502
|
if (!subDir.isDirectory())
|
|
3922
4503
|
continue;
|
|
@@ -3945,8 +4526,8 @@ async function detectProjectStructure(rootDir) {
|
|
|
3945
4526
|
}
|
|
3946
4527
|
let rootType = "unknown";
|
|
3947
4528
|
try {
|
|
3948
|
-
const rootPkgPath =
|
|
3949
|
-
const rootPkg = JSON.parse(await
|
|
4529
|
+
const rootPkgPath = path13.join(rootDir, "package.json");
|
|
4530
|
+
const rootPkg = JSON.parse(await fs5.readFile(rootPkgPath, "utf-8"));
|
|
3950
4531
|
if (rootPkg.workspaces)
|
|
3951
4532
|
isMonorepo = true;
|
|
3952
4533
|
const deps = { ...rootPkg.dependencies, ...rootPkg.devDependencies };
|
|
@@ -3985,8 +4566,8 @@ var init_projectDetector = __esm(() => {
|
|
|
3985
4566
|
});
|
|
3986
4567
|
|
|
3987
4568
|
// src/infrastructure/introspection/IntrospectionIndex.ts
|
|
3988
|
-
import * as
|
|
3989
|
-
import * as
|
|
4569
|
+
import * as path14 from "path";
|
|
4570
|
+
import * as fs6 from "fs/promises";
|
|
3990
4571
|
|
|
3991
4572
|
class IntrospectionIndex {
|
|
3992
4573
|
rootDir;
|
|
@@ -3999,8 +4580,8 @@ class IntrospectionIndex {
|
|
|
3999
4580
|
async initialize() {
|
|
4000
4581
|
this.structure = await detectProjectStructure(this.rootDir);
|
|
4001
4582
|
try {
|
|
4002
|
-
const configPath =
|
|
4003
|
-
const configContent = await
|
|
4583
|
+
const configPath = path14.join(this.rootDir, ".raggrep", "config.json");
|
|
4584
|
+
const configContent = await fs6.readFile(configPath, "utf-8");
|
|
4004
4585
|
const config = JSON.parse(configContent);
|
|
4005
4586
|
this.config = config.introspection || {};
|
|
4006
4587
|
} catch {}
|
|
@@ -4039,28 +4620,28 @@ class IntrospectionIndex {
|
|
|
4039
4620
|
}
|
|
4040
4621
|
}
|
|
4041
4622
|
async save(config) {
|
|
4042
|
-
const introDir =
|
|
4043
|
-
await
|
|
4044
|
-
const projectPath =
|
|
4045
|
-
await
|
|
4623
|
+
const introDir = path14.join(getRaggrepDir(this.rootDir, config), "introspection");
|
|
4624
|
+
await fs6.mkdir(introDir, { recursive: true });
|
|
4625
|
+
const projectPath = path14.join(introDir, "_project.json");
|
|
4626
|
+
await fs6.writeFile(projectPath, JSON.stringify({
|
|
4046
4627
|
version: "1.0.0",
|
|
4047
4628
|
lastUpdated: new Date().toISOString(),
|
|
4048
4629
|
structure: this.structure
|
|
4049
4630
|
}, null, 2));
|
|
4050
4631
|
for (const [filepath, intro] of this.files) {
|
|
4051
|
-
const introFilePath =
|
|
4052
|
-
await
|
|
4053
|
-
await
|
|
4632
|
+
const introFilePath = path14.join(introDir, "files", filepath.replace(/\.[^.]+$/, ".json"));
|
|
4633
|
+
await fs6.mkdir(path14.dirname(introFilePath), { recursive: true });
|
|
4634
|
+
await fs6.writeFile(introFilePath, JSON.stringify(intro, null, 2));
|
|
4054
4635
|
}
|
|
4055
4636
|
}
|
|
4056
4637
|
async load(config) {
|
|
4057
|
-
const introDir =
|
|
4638
|
+
const introDir = path14.join(getRaggrepDir(this.rootDir, config), "introspection");
|
|
4058
4639
|
try {
|
|
4059
|
-
const projectPath =
|
|
4060
|
-
const projectContent = await
|
|
4640
|
+
const projectPath = path14.join(introDir, "_project.json");
|
|
4641
|
+
const projectContent = await fs6.readFile(projectPath, "utf-8");
|
|
4061
4642
|
const projectData = JSON.parse(projectContent);
|
|
4062
4643
|
this.structure = projectData.structure;
|
|
4063
|
-
await this.loadFilesRecursive(
|
|
4644
|
+
await this.loadFilesRecursive(path14.join(introDir, "files"), "");
|
|
4064
4645
|
} catch {
|
|
4065
4646
|
this.structure = null;
|
|
4066
4647
|
this.files.clear();
|
|
@@ -4068,14 +4649,14 @@ class IntrospectionIndex {
|
|
|
4068
4649
|
}
|
|
4069
4650
|
async loadFilesRecursive(basePath, prefix) {
|
|
4070
4651
|
try {
|
|
4071
|
-
const entries = await
|
|
4652
|
+
const entries = await fs6.readdir(basePath, { withFileTypes: true });
|
|
4072
4653
|
for (const entry of entries) {
|
|
4073
|
-
const entryPath =
|
|
4654
|
+
const entryPath = path14.join(basePath, entry.name);
|
|
4074
4655
|
const relativePath = prefix ? `${prefix}/${entry.name}` : entry.name;
|
|
4075
4656
|
if (entry.isDirectory()) {
|
|
4076
4657
|
await this.loadFilesRecursive(entryPath, relativePath);
|
|
4077
4658
|
} else if (entry.name.endsWith(".json")) {
|
|
4078
|
-
const content = await
|
|
4659
|
+
const content = await fs6.readFile(entryPath, "utf-8");
|
|
4079
4660
|
const intro = JSON.parse(content);
|
|
4080
4661
|
this.files.set(intro.filepath, intro);
|
|
4081
4662
|
}
|
|
@@ -4101,7 +4682,7 @@ var init_introspection2 = __esm(() => {
|
|
|
4101
4682
|
|
|
4102
4683
|
// src/app/indexer/watcher.ts
|
|
4103
4684
|
import { watch } from "chokidar";
|
|
4104
|
-
import * as
|
|
4685
|
+
import * as path15 from "path";
|
|
4105
4686
|
async function watchDirectory(rootDir, options = {}) {
|
|
4106
4687
|
const {
|
|
4107
4688
|
debounceMs = DEFAULT_DEBOUNCE_MS,
|
|
@@ -4112,7 +4693,7 @@ async function watchDirectory(rootDir, options = {}) {
|
|
|
4112
4693
|
onFileChange,
|
|
4113
4694
|
onError
|
|
4114
4695
|
} = options;
|
|
4115
|
-
rootDir =
|
|
4696
|
+
rootDir = path15.resolve(rootDir);
|
|
4116
4697
|
const config = await loadConfig(rootDir);
|
|
4117
4698
|
const indexLocation = getIndexLocation(rootDir);
|
|
4118
4699
|
const validExtensions = new Set(config.extensions);
|
|
@@ -4122,7 +4703,7 @@ async function watchDirectory(rootDir, options = {}) {
|
|
|
4122
4703
|
"**/.git/**"
|
|
4123
4704
|
];
|
|
4124
4705
|
function shouldWatchFile(filepath) {
|
|
4125
|
-
const ext =
|
|
4706
|
+
const ext = path15.extname(filepath);
|
|
4126
4707
|
return validExtensions.has(ext);
|
|
4127
4708
|
}
|
|
4128
4709
|
let isRunning = true;
|
|
@@ -4204,7 +4785,7 @@ async function watchDirectory(rootDir, options = {}) {
|
|
|
4204
4785
|
function handleFileEvent(event, filepath) {
|
|
4205
4786
|
if (!isRunning)
|
|
4206
4787
|
return;
|
|
4207
|
-
const relativePath =
|
|
4788
|
+
const relativePath = path15.relative(rootDir, filepath);
|
|
4208
4789
|
if (!shouldWatchFile(filepath)) {
|
|
4209
4790
|
return;
|
|
4210
4791
|
}
|
|
@@ -4282,8 +4863,8 @@ __export(exports_indexer, {
|
|
|
4282
4863
|
cleanupIndex: () => cleanupIndex
|
|
4283
4864
|
});
|
|
4284
4865
|
import { glob } from "glob";
|
|
4285
|
-
import * as
|
|
4286
|
-
import * as
|
|
4866
|
+
import * as fs7 from "fs/promises";
|
|
4867
|
+
import * as path16 from "path";
|
|
4287
4868
|
import * as os3 from "os";
|
|
4288
4869
|
async function parallelMap(items, processor, concurrency) {
|
|
4289
4870
|
const results = new Array(items.length);
|
|
@@ -4326,7 +4907,7 @@ async function indexDirectory(rootDir, options = {}) {
|
|
|
4326
4907
|
const quiet = options.quiet ?? false;
|
|
4327
4908
|
const concurrency = options.concurrency ?? DEFAULT_CONCURRENCY;
|
|
4328
4909
|
const logger = options.logger ? options.logger : quiet ? createSilentLogger() : createLogger({ verbose });
|
|
4329
|
-
rootDir =
|
|
4910
|
+
rootDir = path16.resolve(rootDir);
|
|
4330
4911
|
const location = getIndexLocation(rootDir);
|
|
4331
4912
|
logger.info(`Indexing directory: ${rootDir}`);
|
|
4332
4913
|
logger.info(`Index location: ${location.indexDir}`);
|
|
@@ -4378,12 +4959,12 @@ async function indexDirectory(rootDir, options = {}) {
|
|
|
4378
4959
|
rootDir,
|
|
4379
4960
|
config,
|
|
4380
4961
|
readFile: async (filepath) => {
|
|
4381
|
-
const fullPath =
|
|
4382
|
-
return
|
|
4962
|
+
const fullPath = path16.isAbsolute(filepath) ? filepath : path16.join(rootDir, filepath);
|
|
4963
|
+
return fs7.readFile(fullPath, "utf-8");
|
|
4383
4964
|
},
|
|
4384
4965
|
getFileStats: async (filepath) => {
|
|
4385
|
-
const fullPath =
|
|
4386
|
-
const stats = await
|
|
4966
|
+
const fullPath = path16.isAbsolute(filepath) ? filepath : path16.join(rootDir, filepath);
|
|
4967
|
+
const stats = await fs7.stat(fullPath);
|
|
4387
4968
|
return { lastModified: stats.mtime.toISOString() };
|
|
4388
4969
|
}
|
|
4389
4970
|
};
|
|
@@ -4408,7 +4989,7 @@ async function isIndexVersionCompatible(rootDir) {
|
|
|
4408
4989
|
const config = await loadConfig(rootDir);
|
|
4409
4990
|
const globalManifestPath = getGlobalManifestPath(rootDir, config);
|
|
4410
4991
|
try {
|
|
4411
|
-
const content = await
|
|
4992
|
+
const content = await fs7.readFile(globalManifestPath, "utf-8");
|
|
4412
4993
|
const manifest = JSON.parse(content);
|
|
4413
4994
|
return manifest.version === INDEX_SCHEMA_VERSION;
|
|
4414
4995
|
} catch {
|
|
@@ -4418,11 +4999,11 @@ async function isIndexVersionCompatible(rootDir) {
|
|
|
4418
4999
|
async function deleteIndex(rootDir) {
|
|
4419
5000
|
const indexDir = getRaggrepDir(rootDir);
|
|
4420
5001
|
try {
|
|
4421
|
-
await
|
|
5002
|
+
await fs7.rm(indexDir, { recursive: true, force: true });
|
|
4422
5003
|
} catch {}
|
|
4423
5004
|
}
|
|
4424
5005
|
async function resetIndex(rootDir) {
|
|
4425
|
-
rootDir =
|
|
5006
|
+
rootDir = path16.resolve(rootDir);
|
|
4426
5007
|
const status = await getIndexStatus(rootDir);
|
|
4427
5008
|
if (!status.exists) {
|
|
4428
5009
|
throw new Error(`No index found for ${rootDir}`);
|
|
@@ -4437,7 +5018,7 @@ async function ensureIndexFresh(rootDir, options = {}) {
|
|
|
4437
5018
|
const verbose = options.verbose ?? false;
|
|
4438
5019
|
const quiet = options.quiet ?? false;
|
|
4439
5020
|
const logger = options.logger ? options.logger : quiet ? createSilentLogger() : createLogger({ verbose });
|
|
4440
|
-
rootDir =
|
|
5021
|
+
rootDir = path16.resolve(rootDir);
|
|
4441
5022
|
const status = await getIndexStatus(rootDir);
|
|
4442
5023
|
if (!status.exists) {
|
|
4443
5024
|
logger.info(`No index found. Creating index...
|
|
@@ -4464,7 +5045,7 @@ async function ensureIndexFresh(rootDir, options = {}) {
|
|
|
4464
5045
|
const introspection = new IntrospectionIndex(rootDir);
|
|
4465
5046
|
await introspection.initialize();
|
|
4466
5047
|
const currentFiles = await findFiles(rootDir, config);
|
|
4467
|
-
const currentFileSet = new Set(currentFiles.map((f) =>
|
|
5048
|
+
const currentFileSet = new Set(currentFiles.map((f) => path16.relative(rootDir, f)));
|
|
4468
5049
|
let totalIndexed = 0;
|
|
4469
5050
|
let totalRemoved = 0;
|
|
4470
5051
|
let totalUnchanged = 0;
|
|
@@ -4492,29 +5073,43 @@ async function ensureIndexFresh(rootDir, options = {}) {
|
|
|
4492
5073
|
filesToRemove.push(filepath);
|
|
4493
5074
|
}
|
|
4494
5075
|
}
|
|
5076
|
+
const removedFilepaths = [];
|
|
4495
5077
|
for (const filepath of filesToRemove) {
|
|
4496
5078
|
logger.debug(` Removing stale: ${filepath}`);
|
|
4497
|
-
const indexFilePath =
|
|
5079
|
+
const indexFilePath = path16.join(indexPath, filepath.replace(/\.[^.]+$/, ".json"));
|
|
4498
5080
|
try {
|
|
4499
|
-
await
|
|
5081
|
+
await fs7.unlink(indexFilePath);
|
|
4500
5082
|
} catch {}
|
|
4501
|
-
const symbolicFilePath =
|
|
5083
|
+
const symbolicFilePath = path16.join(indexPath, "symbolic", filepath.replace(/\.[^.]+$/, ".json"));
|
|
4502
5084
|
try {
|
|
4503
|
-
await
|
|
5085
|
+
await fs7.unlink(symbolicFilePath);
|
|
4504
5086
|
} catch {}
|
|
4505
5087
|
delete manifest.files[filepath];
|
|
5088
|
+
removedFilepaths.push(filepath);
|
|
4506
5089
|
totalRemoved++;
|
|
4507
5090
|
}
|
|
5091
|
+
if (removedFilepaths.length > 0) {
|
|
5092
|
+
try {
|
|
5093
|
+
const { LiteralIndex: LiteralIndex2 } = await Promise.resolve().then(() => (init_literalIndex(), exports_literalIndex));
|
|
5094
|
+
const raggrepDir = getRaggrepDir(rootDir, config);
|
|
5095
|
+
const literalIndex = new LiteralIndex2(raggrepDir, module.id);
|
|
5096
|
+
await literalIndex.initialize();
|
|
5097
|
+
for (const filepath of removedFilepaths) {
|
|
5098
|
+
literalIndex.removeFile(filepath);
|
|
5099
|
+
}
|
|
5100
|
+
await literalIndex.save();
|
|
5101
|
+
} catch {}
|
|
5102
|
+
}
|
|
4508
5103
|
const ctx = {
|
|
4509
5104
|
rootDir,
|
|
4510
5105
|
config,
|
|
4511
5106
|
readFile: async (filepath) => {
|
|
4512
|
-
const fullPath =
|
|
4513
|
-
return
|
|
5107
|
+
const fullPath = path16.isAbsolute(filepath) ? filepath : path16.join(rootDir, filepath);
|
|
5108
|
+
return fs7.readFile(fullPath, "utf-8");
|
|
4514
5109
|
},
|
|
4515
5110
|
getFileStats: async (filepath) => {
|
|
4516
|
-
const fullPath =
|
|
4517
|
-
const stats = await
|
|
5111
|
+
const fullPath = path16.isAbsolute(filepath) ? filepath : path16.join(rootDir, filepath);
|
|
5112
|
+
const stats = await fs7.stat(fullPath);
|
|
4518
5113
|
return { lastModified: stats.mtime.toISOString() };
|
|
4519
5114
|
},
|
|
4520
5115
|
getIntrospection: (filepath) => introspection.getFile(filepath)
|
|
@@ -4522,10 +5117,10 @@ async function ensureIndexFresh(rootDir, options = {}) {
|
|
|
4522
5117
|
const totalFiles = currentFiles.length;
|
|
4523
5118
|
for (let i = 0;i < currentFiles.length; i++) {
|
|
4524
5119
|
const filepath = currentFiles[i];
|
|
4525
|
-
const relativePath =
|
|
5120
|
+
const relativePath = path16.relative(rootDir, filepath);
|
|
4526
5121
|
const progress = `[${i + 1}/${totalFiles}]`;
|
|
4527
5122
|
try {
|
|
4528
|
-
const stats = await
|
|
5123
|
+
const stats = await fs7.stat(filepath);
|
|
4529
5124
|
const lastModified = stats.mtime.toISOString();
|
|
4530
5125
|
const existingEntry = manifest.files[relativePath];
|
|
4531
5126
|
if (existingEntry && existingEntry.lastModified === lastModified) {
|
|
@@ -4533,7 +5128,7 @@ async function ensureIndexFresh(rootDir, options = {}) {
|
|
|
4533
5128
|
continue;
|
|
4534
5129
|
}
|
|
4535
5130
|
logger.progress(` ${progress} Indexing: ${relativePath}`);
|
|
4536
|
-
const content = await
|
|
5131
|
+
const content = await fs7.readFile(filepath, "utf-8");
|
|
4537
5132
|
introspection.addFile(relativePath, content);
|
|
4538
5133
|
const fileIndex = await module.indexFile(relativePath, content, ctx);
|
|
4539
5134
|
if (fileIndex) {
|
|
@@ -4582,7 +5177,7 @@ async function indexWithModule(rootDir, files, module, config, verbose, introspe
|
|
|
4582
5177
|
};
|
|
4583
5178
|
const manifest = await loadModuleManifest(rootDir, module.id, config);
|
|
4584
5179
|
const indexPath = getModuleIndexPath(rootDir, module.id, config);
|
|
4585
|
-
const currentFileSet = new Set(files.map((f) =>
|
|
5180
|
+
const currentFileSet = new Set(files.map((f) => path16.relative(rootDir, f)));
|
|
4586
5181
|
const filesToRemove = [];
|
|
4587
5182
|
for (const filepath of Object.keys(manifest.files)) {
|
|
4588
5183
|
if (!currentFileSet.has(filepath)) {
|
|
@@ -4593,13 +5188,13 @@ async function indexWithModule(rootDir, files, module, config, verbose, introspe
|
|
|
4593
5188
|
logger.info(` Removing ${filesToRemove.length} stale entries...`);
|
|
4594
5189
|
for (const filepath of filesToRemove) {
|
|
4595
5190
|
logger.debug(` Removing: ${filepath}`);
|
|
4596
|
-
const indexFilePath =
|
|
5191
|
+
const indexFilePath = path16.join(indexPath, filepath.replace(/\.[^.]+$/, ".json"));
|
|
4597
5192
|
try {
|
|
4598
|
-
await
|
|
5193
|
+
await fs7.unlink(indexFilePath);
|
|
4599
5194
|
} catch {}
|
|
4600
|
-
const symbolicFilePath =
|
|
5195
|
+
const symbolicFilePath = path16.join(indexPath, "symbolic", filepath.replace(/\.[^.]+$/, ".json"));
|
|
4601
5196
|
try {
|
|
4602
|
-
await
|
|
5197
|
+
await fs7.unlink(symbolicFilePath);
|
|
4603
5198
|
} catch {}
|
|
4604
5199
|
delete manifest.files[filepath];
|
|
4605
5200
|
}
|
|
@@ -4609,12 +5204,12 @@ async function indexWithModule(rootDir, files, module, config, verbose, introspe
|
|
|
4609
5204
|
rootDir,
|
|
4610
5205
|
config,
|
|
4611
5206
|
readFile: async (filepath) => {
|
|
4612
|
-
const fullPath =
|
|
4613
|
-
return
|
|
5207
|
+
const fullPath = path16.isAbsolute(filepath) ? filepath : path16.join(rootDir, filepath);
|
|
5208
|
+
return fs7.readFile(fullPath, "utf-8");
|
|
4614
5209
|
},
|
|
4615
5210
|
getFileStats: async (filepath) => {
|
|
4616
|
-
const fullPath =
|
|
4617
|
-
const stats = await
|
|
5211
|
+
const fullPath = path16.isAbsolute(filepath) ? filepath : path16.join(rootDir, filepath);
|
|
5212
|
+
const stats = await fs7.stat(fullPath);
|
|
4618
5213
|
return { lastModified: stats.mtime.toISOString() };
|
|
4619
5214
|
},
|
|
4620
5215
|
getIntrospection: (filepath) => introspection.getFile(filepath)
|
|
@@ -4622,9 +5217,9 @@ async function indexWithModule(rootDir, files, module, config, verbose, introspe
|
|
|
4622
5217
|
const totalFiles = files.length;
|
|
4623
5218
|
let completedCount = 0;
|
|
4624
5219
|
const processFile = async (filepath, _index) => {
|
|
4625
|
-
const relativePath =
|
|
5220
|
+
const relativePath = path16.relative(rootDir, filepath);
|
|
4626
5221
|
try {
|
|
4627
|
-
const stats = await
|
|
5222
|
+
const stats = await fs7.stat(filepath);
|
|
4628
5223
|
const lastModified = stats.mtime.toISOString();
|
|
4629
5224
|
const existingEntry = manifest.files[relativePath];
|
|
4630
5225
|
if (existingEntry && existingEntry.lastModified === lastModified) {
|
|
@@ -4632,7 +5227,7 @@ async function indexWithModule(rootDir, files, module, config, verbose, introspe
|
|
|
4632
5227
|
logger.debug(` [${completedCount}/${totalFiles}] Skipped ${relativePath} (unchanged)`);
|
|
4633
5228
|
return { relativePath, status: "skipped" };
|
|
4634
5229
|
}
|
|
4635
|
-
const content = await
|
|
5230
|
+
const content = await fs7.readFile(filepath, "utf-8");
|
|
4636
5231
|
introspection.addFile(relativePath, content);
|
|
4637
5232
|
completedCount++;
|
|
4638
5233
|
logger.progress(` [${completedCount}/${totalFiles}] Processing: ${relativePath}`);
|
|
@@ -4700,7 +5295,7 @@ async function findFiles(rootDir, config) {
|
|
|
4700
5295
|
async function loadModuleManifest(rootDir, moduleId, config) {
|
|
4701
5296
|
const manifestPath = getModuleManifestPath(rootDir, moduleId, config);
|
|
4702
5297
|
try {
|
|
4703
|
-
const content = await
|
|
5298
|
+
const content = await fs7.readFile(manifestPath, "utf-8");
|
|
4704
5299
|
return JSON.parse(content);
|
|
4705
5300
|
} catch {
|
|
4706
5301
|
return {
|
|
@@ -4713,14 +5308,14 @@ async function loadModuleManifest(rootDir, moduleId, config) {
|
|
|
4713
5308
|
}
|
|
4714
5309
|
async function writeModuleManifest(rootDir, moduleId, manifest, config) {
|
|
4715
5310
|
const manifestPath = getModuleManifestPath(rootDir, moduleId, config);
|
|
4716
|
-
await
|
|
4717
|
-
await
|
|
5311
|
+
await fs7.mkdir(path16.dirname(manifestPath), { recursive: true });
|
|
5312
|
+
await fs7.writeFile(manifestPath, JSON.stringify(manifest, null, 2));
|
|
4718
5313
|
}
|
|
4719
5314
|
async function writeFileIndex(rootDir, moduleId, filepath, fileIndex, config) {
|
|
4720
5315
|
const indexPath = getModuleIndexPath(rootDir, moduleId, config);
|
|
4721
|
-
const indexFilePath =
|
|
4722
|
-
await
|
|
4723
|
-
await
|
|
5316
|
+
const indexFilePath = path16.join(indexPath, filepath.replace(/\.[^.]+$/, ".json"));
|
|
5317
|
+
await fs7.mkdir(path16.dirname(indexFilePath), { recursive: true });
|
|
5318
|
+
await fs7.writeFile(indexFilePath, JSON.stringify(fileIndex, null, 2));
|
|
4724
5319
|
}
|
|
4725
5320
|
async function updateGlobalManifest(rootDir, modules, config) {
|
|
4726
5321
|
const manifestPath = getGlobalManifestPath(rootDir, config);
|
|
@@ -4729,13 +5324,13 @@ async function updateGlobalManifest(rootDir, modules, config) {
|
|
|
4729
5324
|
lastUpdated: new Date().toISOString(),
|
|
4730
5325
|
modules: modules.map((m) => m.id)
|
|
4731
5326
|
};
|
|
4732
|
-
await
|
|
4733
|
-
await
|
|
5327
|
+
await fs7.mkdir(path16.dirname(manifestPath), { recursive: true });
|
|
5328
|
+
await fs7.writeFile(manifestPath, JSON.stringify(manifest, null, 2));
|
|
4734
5329
|
}
|
|
4735
5330
|
async function cleanupIndex(rootDir, options = {}) {
|
|
4736
5331
|
const verbose = options.verbose ?? false;
|
|
4737
5332
|
const logger = options.logger ?? createLogger({ verbose });
|
|
4738
|
-
rootDir =
|
|
5333
|
+
rootDir = path16.resolve(rootDir);
|
|
4739
5334
|
logger.info(`Cleaning up index in: ${rootDir}`);
|
|
4740
5335
|
const config = await loadConfig(rootDir);
|
|
4741
5336
|
await registerBuiltInModules();
|
|
@@ -4765,9 +5360,9 @@ async function cleanupModuleIndex(rootDir, moduleId, config, logger) {
|
|
|
4765
5360
|
const filesToRemove = [];
|
|
4766
5361
|
const updatedFiles = {};
|
|
4767
5362
|
for (const [filepath, entry] of Object.entries(manifest.files)) {
|
|
4768
|
-
const fullPath =
|
|
5363
|
+
const fullPath = path16.join(rootDir, filepath);
|
|
4769
5364
|
try {
|
|
4770
|
-
await
|
|
5365
|
+
await fs7.access(fullPath);
|
|
4771
5366
|
updatedFiles[filepath] = entry;
|
|
4772
5367
|
result.kept++;
|
|
4773
5368
|
} catch {
|
|
@@ -4777,9 +5372,9 @@ async function cleanupModuleIndex(rootDir, moduleId, config, logger) {
|
|
|
4777
5372
|
}
|
|
4778
5373
|
}
|
|
4779
5374
|
for (const filepath of filesToRemove) {
|
|
4780
|
-
const indexFilePath =
|
|
5375
|
+
const indexFilePath = path16.join(indexPath, filepath.replace(/\.[^.]+$/, ".json"));
|
|
4781
5376
|
try {
|
|
4782
|
-
await
|
|
5377
|
+
await fs7.unlink(indexFilePath);
|
|
4783
5378
|
} catch {}
|
|
4784
5379
|
}
|
|
4785
5380
|
manifest.files = updatedFiles;
|
|
@@ -4790,16 +5385,16 @@ async function cleanupModuleIndex(rootDir, moduleId, config, logger) {
|
|
|
4790
5385
|
}
|
|
4791
5386
|
async function cleanupEmptyDirectories(dir) {
|
|
4792
5387
|
try {
|
|
4793
|
-
const entries = await
|
|
5388
|
+
const entries = await fs7.readdir(dir, { withFileTypes: true });
|
|
4794
5389
|
for (const entry of entries) {
|
|
4795
5390
|
if (entry.isDirectory()) {
|
|
4796
|
-
const subDir =
|
|
5391
|
+
const subDir = path16.join(dir, entry.name);
|
|
4797
5392
|
await cleanupEmptyDirectories(subDir);
|
|
4798
5393
|
}
|
|
4799
5394
|
}
|
|
4800
|
-
const remainingEntries = await
|
|
5395
|
+
const remainingEntries = await fs7.readdir(dir);
|
|
4801
5396
|
if (remainingEntries.length === 0) {
|
|
4802
|
-
await
|
|
5397
|
+
await fs7.rmdir(dir);
|
|
4803
5398
|
return true;
|
|
4804
5399
|
}
|
|
4805
5400
|
return false;
|
|
@@ -4808,7 +5403,7 @@ async function cleanupEmptyDirectories(dir) {
|
|
|
4808
5403
|
}
|
|
4809
5404
|
}
|
|
4810
5405
|
async function getIndexStatus(rootDir) {
|
|
4811
|
-
rootDir =
|
|
5406
|
+
rootDir = path16.resolve(rootDir);
|
|
4812
5407
|
const config = await loadConfig(rootDir);
|
|
4813
5408
|
const location = getIndexLocation(rootDir);
|
|
4814
5409
|
const indexDir = location.indexDir;
|
|
@@ -4820,13 +5415,13 @@ async function getIndexStatus(rootDir) {
|
|
|
4820
5415
|
totalFiles: 0
|
|
4821
5416
|
};
|
|
4822
5417
|
try {
|
|
4823
|
-
await
|
|
5418
|
+
await fs7.access(indexDir);
|
|
4824
5419
|
} catch {
|
|
4825
5420
|
return status;
|
|
4826
5421
|
}
|
|
4827
5422
|
try {
|
|
4828
5423
|
const globalManifestPath = getGlobalManifestPath(rootDir, config);
|
|
4829
|
-
const content = await
|
|
5424
|
+
const content = await fs7.readFile(globalManifestPath, "utf-8");
|
|
4830
5425
|
const globalManifest = JSON.parse(content);
|
|
4831
5426
|
status.exists = true;
|
|
4832
5427
|
status.lastUpdated = globalManifest.lastUpdated;
|
|
@@ -4844,7 +5439,7 @@ async function getIndexStatus(rootDir) {
|
|
|
4844
5439
|
}
|
|
4845
5440
|
} catch {
|
|
4846
5441
|
try {
|
|
4847
|
-
const entries = await
|
|
5442
|
+
const entries = await fs7.readdir(path16.join(indexDir, "index"));
|
|
4848
5443
|
if (entries.length > 0) {
|
|
4849
5444
|
status.exists = true;
|
|
4850
5445
|
for (const entry of entries) {
|
|
@@ -4885,10 +5480,10 @@ __export(exports_search, {
|
|
|
4885
5480
|
search: () => search,
|
|
4886
5481
|
formatSearchResults: () => formatSearchResults
|
|
4887
5482
|
});
|
|
4888
|
-
import * as
|
|
4889
|
-
import * as
|
|
5483
|
+
import * as fs8 from "fs/promises";
|
|
5484
|
+
import * as path17 from "path";
|
|
4890
5485
|
async function search(rootDir, query, options = {}) {
|
|
4891
|
-
rootDir =
|
|
5486
|
+
rootDir = path17.resolve(rootDir);
|
|
4892
5487
|
const ensureFresh = options.ensureFresh ?? DEFAULT_SEARCH_OPTIONS.ensureFresh;
|
|
4893
5488
|
if (ensureFresh) {
|
|
4894
5489
|
await ensureIndexFresh(rootDir, { quiet: true });
|
|
@@ -4941,9 +5536,9 @@ function createSearchContext(rootDir, moduleId, config) {
|
|
|
4941
5536
|
config,
|
|
4942
5537
|
loadFileIndex: async (filepath) => {
|
|
4943
5538
|
const hasExtension = /\.[^./]+$/.test(filepath);
|
|
4944
|
-
const indexFilePath = hasExtension ?
|
|
5539
|
+
const indexFilePath = hasExtension ? path17.join(indexPath, filepath.replace(/\.[^.]+$/, ".json")) : path17.join(indexPath, filepath + ".json");
|
|
4945
5540
|
try {
|
|
4946
|
-
const content = await
|
|
5541
|
+
const content = await fs8.readFile(indexFilePath, "utf-8");
|
|
4947
5542
|
return JSON.parse(content);
|
|
4948
5543
|
} catch {
|
|
4949
5544
|
return null;
|
|
@@ -4953,7 +5548,7 @@ function createSearchContext(rootDir, moduleId, config) {
|
|
|
4953
5548
|
const files = [];
|
|
4954
5549
|
await traverseDirectory(indexPath, files, indexPath);
|
|
4955
5550
|
return files.filter((f) => f.endsWith(".json") && !f.endsWith("manifest.json")).map((f) => {
|
|
4956
|
-
const relative4 =
|
|
5551
|
+
const relative4 = path17.relative(indexPath, f);
|
|
4957
5552
|
return relative4.replace(/\.json$/, "");
|
|
4958
5553
|
});
|
|
4959
5554
|
}
|
|
@@ -4961,9 +5556,9 @@ function createSearchContext(rootDir, moduleId, config) {
|
|
|
4961
5556
|
}
|
|
4962
5557
|
async function traverseDirectory(dir, files, basePath) {
|
|
4963
5558
|
try {
|
|
4964
|
-
const entries = await
|
|
5559
|
+
const entries = await fs8.readdir(dir, { withFileTypes: true });
|
|
4965
5560
|
for (const entry of entries) {
|
|
4966
|
-
const fullPath =
|
|
5561
|
+
const fullPath = path17.join(dir, entry.name);
|
|
4967
5562
|
if (entry.isDirectory()) {
|
|
4968
5563
|
await traverseDirectory(fullPath, files, basePath);
|
|
4969
5564
|
} else if (entry.isFile()) {
|
|
@@ -4975,7 +5570,7 @@ async function traverseDirectory(dir, files, basePath) {
|
|
|
4975
5570
|
async function loadGlobalManifest(rootDir, config) {
|
|
4976
5571
|
const manifestPath = getGlobalManifestPath(rootDir, config);
|
|
4977
5572
|
try {
|
|
4978
|
-
const content = await
|
|
5573
|
+
const content = await fs8.readFile(manifestPath, "utf-8");
|
|
4979
5574
|
return JSON.parse(content);
|
|
4980
5575
|
} catch {
|
|
4981
5576
|
return null;
|
|
@@ -5041,7 +5636,7 @@ init_logger();
|
|
|
5041
5636
|
// package.json
|
|
5042
5637
|
var package_default = {
|
|
5043
5638
|
name: "raggrep",
|
|
5044
|
-
version: "0.
|
|
5639
|
+
version: "0.7.1",
|
|
5045
5640
|
description: "Local filesystem-based RAG system for codebases - semantic search using local embeddings",
|
|
5046
5641
|
type: "module",
|
|
5047
5642
|
main: "./dist/index.js",
|
|
@@ -5502,4 +6097,4 @@ Run 'raggrep <command> --help' for more information.
|
|
|
5502
6097
|
}
|
|
5503
6098
|
main();
|
|
5504
6099
|
|
|
5505
|
-
//# debugId=
|
|
6100
|
+
//# debugId=D5C2A5C0F122D20164756E2164756E21
|