raggrep 0.1.4 → 0.1.6
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 +23 -9
- package/dist/cli/main.js +2550 -1631
- package/dist/cli/main.js.map +19 -13
- package/dist/domain/entities/chunk.d.ts +1 -1
- package/dist/domain/entities/fileIndex.d.ts +1 -1
- package/dist/domain/ports/embedding.d.ts +1 -1
- package/dist/index.js +2588 -1733
- package/dist/index.js.map +18 -12
- package/dist/infrastructure/config/configLoader.d.ts +22 -3
- package/dist/infrastructure/config/index.d.ts +1 -1
- package/dist/introspection/conventions/configFiles.d.ts +10 -0
- package/dist/introspection/conventions/conventions.test.d.ts +4 -0
- package/dist/introspection/conventions/entryPoints.d.ts +10 -0
- package/dist/introspection/conventions/frameworks/convex.d.ts +11 -0
- package/dist/introspection/conventions/frameworks/index.d.ts +22 -0
- package/dist/introspection/conventions/frameworks/nextjs.d.ts +10 -0
- package/dist/introspection/conventions/index.d.ts +39 -0
- package/dist/introspection/conventions/types.d.ts +62 -0
- package/dist/tests/integration.test.d.ts +9 -0
- package/package.json +1 -1
package/dist/cli/main.js
CHANGED
|
@@ -235,7 +235,8 @@ var init_config = __esm(() => {
|
|
|
235
235
|
".go",
|
|
236
236
|
".rs",
|
|
237
237
|
".java",
|
|
238
|
-
".md"
|
|
238
|
+
".md",
|
|
239
|
+
".txt"
|
|
239
240
|
];
|
|
240
241
|
});
|
|
241
242
|
|
|
@@ -248,20 +249,40 @@ var init_entities = __esm(() => {
|
|
|
248
249
|
// src/infrastructure/config/configLoader.ts
|
|
249
250
|
import * as path2 from "path";
|
|
250
251
|
import * as fs from "fs/promises";
|
|
251
|
-
|
|
252
|
-
|
|
252
|
+
import * as os2 from "os";
|
|
253
|
+
import * as crypto from "crypto";
|
|
254
|
+
function hashPath(inputPath) {
|
|
255
|
+
return crypto.createHash("sha256").update(inputPath).digest("hex").slice(0, 12);
|
|
256
|
+
}
|
|
257
|
+
function getRaggrepDir(rootDir, _config = DEFAULT_CONFIG) {
|
|
258
|
+
const absoluteRoot = path2.resolve(rootDir);
|
|
259
|
+
const projectHash = hashPath(absoluteRoot);
|
|
260
|
+
return path2.join(RAGGREP_TEMP_BASE, projectHash);
|
|
261
|
+
}
|
|
262
|
+
function getIndexLocation(rootDir) {
|
|
263
|
+
const absoluteRoot = path2.resolve(rootDir);
|
|
264
|
+
const projectHash = hashPath(absoluteRoot);
|
|
265
|
+
return {
|
|
266
|
+
indexDir: path2.join(RAGGREP_TEMP_BASE, projectHash),
|
|
267
|
+
projectRoot: absoluteRoot,
|
|
268
|
+
projectHash
|
|
269
|
+
};
|
|
253
270
|
}
|
|
254
271
|
function getModuleIndexPath(rootDir, moduleId, config = DEFAULT_CONFIG) {
|
|
255
|
-
|
|
272
|
+
const indexDir = getRaggrepDir(rootDir, config);
|
|
273
|
+
return path2.join(indexDir, "index", moduleId);
|
|
256
274
|
}
|
|
257
275
|
function getModuleManifestPath(rootDir, moduleId, config = DEFAULT_CONFIG) {
|
|
258
|
-
|
|
276
|
+
const indexDir = getRaggrepDir(rootDir, config);
|
|
277
|
+
return path2.join(indexDir, "index", moduleId, "manifest.json");
|
|
259
278
|
}
|
|
260
279
|
function getGlobalManifestPath(rootDir, config = DEFAULT_CONFIG) {
|
|
261
|
-
|
|
280
|
+
const indexDir = getRaggrepDir(rootDir, config);
|
|
281
|
+
return path2.join(indexDir, "manifest.json");
|
|
262
282
|
}
|
|
263
283
|
function getConfigPath(rootDir, config = DEFAULT_CONFIG) {
|
|
264
|
-
|
|
284
|
+
const indexDir = getRaggrepDir(rootDir, config);
|
|
285
|
+
return path2.join(indexDir, "config.json");
|
|
265
286
|
}
|
|
266
287
|
async function loadConfig(rootDir) {
|
|
267
288
|
const configPath = getConfigPath(rootDir, DEFAULT_CONFIG);
|
|
@@ -288,10 +309,11 @@ function getEmbeddingConfigFromModule(moduleConfig) {
|
|
|
288
309
|
showProgress: options.showProgress !== false
|
|
289
310
|
};
|
|
290
311
|
}
|
|
291
|
-
var DEFAULT_CONFIG, EMBEDDING_MODELS2;
|
|
312
|
+
var DEFAULT_CONFIG, RAGGREP_TEMP_BASE, EMBEDDING_MODELS2;
|
|
292
313
|
var init_configLoader = __esm(() => {
|
|
293
314
|
init_entities();
|
|
294
315
|
DEFAULT_CONFIG = createDefaultConfig();
|
|
316
|
+
RAGGREP_TEMP_BASE = path2.join(os2.tmpdir(), "raggrep-indexes");
|
|
295
317
|
EMBEDDING_MODELS2 = {
|
|
296
318
|
"all-MiniLM-L6-v2": "Xenova/all-MiniLM-L6-v2",
|
|
297
319
|
"all-MiniLM-L12-v2": "Xenova/all-MiniLM-L12-v2",
|
|
@@ -407,1788 +429,2606 @@ function normalizeScore(score, midpoint = 5) {
|
|
|
407
429
|
}
|
|
408
430
|
var BM25_K1 = 1.5, BM25_B = 0.75;
|
|
409
431
|
|
|
410
|
-
// src/
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
const
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
if (seenSymbols.has(symbolKey))
|
|
423
|
-
continue;
|
|
424
|
-
seenSymbols.add(symbolKey);
|
|
425
|
-
const beforeMatch = content.substring(0, match.index);
|
|
426
|
-
const line = beforeMatch.split(`
|
|
427
|
-
`).length;
|
|
428
|
-
symbols.push({
|
|
429
|
-
name,
|
|
430
|
-
type,
|
|
431
|
-
line,
|
|
432
|
-
isExported: exported
|
|
433
|
-
});
|
|
432
|
+
// src/introspection/projectDetector.ts
|
|
433
|
+
import * as path3 from "path";
|
|
434
|
+
import * as fs2 from "fs/promises";
|
|
435
|
+
function detectScopeFromName(name) {
|
|
436
|
+
const nameLower = name.toLowerCase();
|
|
437
|
+
for (const [scope, keywords] of Object.entries(SCOPE_KEYWORDS)) {
|
|
438
|
+
if (scope === "unknown")
|
|
439
|
+
continue;
|
|
440
|
+
for (const keyword of keywords) {
|
|
441
|
+
if (nameLower.includes(keyword)) {
|
|
442
|
+
return scope;
|
|
443
|
+
}
|
|
434
444
|
}
|
|
435
445
|
}
|
|
436
|
-
return
|
|
446
|
+
return "unknown";
|
|
437
447
|
}
|
|
438
|
-
function
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
448
|
+
async function scanForPackageJsons(rootDir, currentDir = "", depth = 0) {
|
|
449
|
+
if (depth > MAX_SCAN_DEPTH)
|
|
450
|
+
return [];
|
|
451
|
+
const results = [];
|
|
452
|
+
const fullDir = currentDir ? path3.join(rootDir, currentDir) : rootDir;
|
|
453
|
+
try {
|
|
454
|
+
const entries = await fs2.readdir(fullDir, { withFileTypes: true });
|
|
455
|
+
const hasPackageJson = entries.some((e) => e.isFile() && e.name === "package.json");
|
|
456
|
+
if (hasPackageJson && currentDir) {
|
|
457
|
+
const info = await parsePackageJson(rootDir, currentDir);
|
|
458
|
+
if (info) {
|
|
459
|
+
results.push(info);
|
|
446
460
|
}
|
|
447
461
|
}
|
|
448
|
-
|
|
449
|
-
|
|
462
|
+
for (const entry of entries) {
|
|
463
|
+
if (!entry.isDirectory())
|
|
464
|
+
continue;
|
|
465
|
+
if (SKIP_DIRS.has(entry.name))
|
|
466
|
+
continue;
|
|
467
|
+
const subPath = currentDir ? `${currentDir}/${entry.name}` : entry.name;
|
|
468
|
+
const subResults = await scanForPackageJsons(rootDir, subPath, depth + 1);
|
|
469
|
+
results.push(...subResults);
|
|
470
|
+
}
|
|
471
|
+
} catch {}
|
|
472
|
+
return results;
|
|
450
473
|
}
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
{
|
|
460
|
-
type
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
}
|
|
464
|
-
|
|
465
|
-
type: "class",
|
|
466
|
-
pattern: /^export\s+(?:abstract\s+)?class\s+(\w+)/gm,
|
|
467
|
-
exported: true
|
|
468
|
-
},
|
|
469
|
-
{
|
|
470
|
-
type: "interface",
|
|
471
|
-
pattern: /^export\s+interface\s+(\w+)/gm,
|
|
472
|
-
exported: true
|
|
473
|
-
},
|
|
474
|
-
{
|
|
475
|
-
type: "type",
|
|
476
|
-
pattern: /^export\s+type\s+(\w+)/gm,
|
|
477
|
-
exported: true
|
|
478
|
-
},
|
|
479
|
-
{
|
|
480
|
-
type: "enum",
|
|
481
|
-
pattern: /^export\s+(?:const\s+)?enum\s+(\w+)/gm,
|
|
482
|
-
exported: true
|
|
483
|
-
},
|
|
484
|
-
{
|
|
485
|
-
type: "variable",
|
|
486
|
-
pattern: /^export\s+(?:const|let|var)\s+(\w+)\s*(?::|=)/gm,
|
|
487
|
-
exported: true
|
|
488
|
-
},
|
|
489
|
-
{
|
|
490
|
-
type: "function",
|
|
491
|
-
pattern: /^export\s+default\s+(?:async\s+)?function\s+(\w+)/gm,
|
|
492
|
-
exported: true
|
|
493
|
-
},
|
|
494
|
-
{
|
|
495
|
-
type: "class",
|
|
496
|
-
pattern: /^export\s+default\s+class\s+(\w+)/gm,
|
|
497
|
-
exported: true
|
|
498
|
-
},
|
|
499
|
-
{
|
|
500
|
-
type: "function",
|
|
501
|
-
pattern: /^(?:async\s+)?function\s+(\w+)/gm,
|
|
502
|
-
exported: false
|
|
503
|
-
},
|
|
504
|
-
{
|
|
505
|
-
type: "function",
|
|
506
|
-
pattern: /^(?:const|let)\s+(\w+)\s*=\s*(?:async\s*)?\(/gm,
|
|
507
|
-
exported: false
|
|
508
|
-
},
|
|
509
|
-
{
|
|
510
|
-
type: "class",
|
|
511
|
-
pattern: /^(?:abstract\s+)?class\s+(\w+)/gm,
|
|
512
|
-
exported: false
|
|
513
|
-
},
|
|
514
|
-
{
|
|
515
|
-
type: "interface",
|
|
516
|
-
pattern: /^interface\s+(\w+)/gm,
|
|
517
|
-
exported: false
|
|
518
|
-
},
|
|
519
|
-
{
|
|
520
|
-
type: "type",
|
|
521
|
-
pattern: /^type\s+(\w+)/gm,
|
|
522
|
-
exported: false
|
|
523
|
-
},
|
|
524
|
-
{
|
|
525
|
-
type: "enum",
|
|
526
|
-
pattern: /^(?:const\s+)?enum\s+(\w+)/gm,
|
|
527
|
-
exported: false
|
|
528
|
-
},
|
|
529
|
-
{
|
|
530
|
-
type: "function",
|
|
531
|
-
pattern: /^def\s+(\w+)\s*\(/gm,
|
|
532
|
-
exported: false
|
|
533
|
-
},
|
|
534
|
-
{
|
|
535
|
-
type: "class",
|
|
536
|
-
pattern: /^class\s+(\w+)(?:\s*\(|:)/gm,
|
|
537
|
-
exported: false
|
|
538
|
-
},
|
|
539
|
-
{
|
|
540
|
-
type: "function",
|
|
541
|
-
pattern: /^func\s+(?:\([^)]+\)\s+)?(\w+)\s*\(/gm,
|
|
542
|
-
exported: false
|
|
543
|
-
},
|
|
544
|
-
{
|
|
545
|
-
type: "type",
|
|
546
|
-
pattern: /^type\s+(\w+)\s+(?:struct|interface)/gm,
|
|
547
|
-
exported: false
|
|
548
|
-
},
|
|
549
|
-
{
|
|
550
|
-
type: "function",
|
|
551
|
-
pattern: /^(?:pub\s+)?(?:async\s+)?fn\s+(\w+)/gm,
|
|
552
|
-
exported: false
|
|
553
|
-
},
|
|
554
|
-
{
|
|
555
|
-
type: "type",
|
|
556
|
-
pattern: /^(?:pub\s+)?struct\s+(\w+)/gm,
|
|
557
|
-
exported: false
|
|
558
|
-
},
|
|
559
|
-
{
|
|
560
|
-
type: "enum",
|
|
561
|
-
pattern: /^(?:pub\s+)?enum\s+(\w+)/gm,
|
|
562
|
-
exported: false
|
|
563
|
-
},
|
|
564
|
-
{
|
|
565
|
-
type: "interface",
|
|
566
|
-
pattern: /^(?:pub\s+)?trait\s+(\w+)/gm,
|
|
567
|
-
exported: false
|
|
474
|
+
async function parsePackageJson(rootDir, relativePath) {
|
|
475
|
+
try {
|
|
476
|
+
const packageJsonPath = path3.join(rootDir, relativePath, "package.json");
|
|
477
|
+
const content = await fs2.readFile(packageJsonPath, "utf-8");
|
|
478
|
+
const pkg = JSON.parse(content);
|
|
479
|
+
const name = pkg.name || path3.basename(relativePath);
|
|
480
|
+
const deps = { ...pkg.dependencies, ...pkg.devDependencies };
|
|
481
|
+
let type = "unknown";
|
|
482
|
+
if (deps["next"] || deps["react"] || deps["vue"] || deps["svelte"]) {
|
|
483
|
+
type = "app";
|
|
484
|
+
} else if (deps["express"] || deps["fastify"] || deps["koa"] || deps["hono"]) {
|
|
485
|
+
type = "service";
|
|
486
|
+
} else if (pkg.main || pkg.exports) {
|
|
487
|
+
type = "library";
|
|
568
488
|
}
|
|
569
|
-
|
|
570
|
-
}
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
var exports_core = {};
|
|
574
|
-
__export(exports_core, {
|
|
575
|
-
CoreModule: () => CoreModule
|
|
576
|
-
});
|
|
577
|
-
import * as path3 from "path";
|
|
578
|
-
import * as fs2 from "fs/promises";
|
|
579
|
-
|
|
580
|
-
class CoreModule {
|
|
581
|
-
id = "core";
|
|
582
|
-
name = "Core Search";
|
|
583
|
-
description = "Language-agnostic text search with symbol extraction";
|
|
584
|
-
version = "1.0.0";
|
|
585
|
-
symbolIndex = new Map;
|
|
586
|
-
bm25Index = null;
|
|
587
|
-
rootDir = "";
|
|
588
|
-
async initialize(_config) {}
|
|
589
|
-
async indexFile(filepath, content, ctx) {
|
|
590
|
-
this.rootDir = ctx.rootDir;
|
|
591
|
-
const symbols = extractSymbols(content);
|
|
592
|
-
const symbolKeywords = symbolsToKeywords(symbols);
|
|
593
|
-
const contentTokens = tokenize(content);
|
|
594
|
-
const allTokens = [...new Set([...contentTokens, ...symbolKeywords])];
|
|
595
|
-
const chunks = this.createChunks(filepath, content, symbols);
|
|
596
|
-
const stats = await ctx.getFileStats(filepath);
|
|
597
|
-
this.symbolIndex.set(filepath, {
|
|
598
|
-
filepath,
|
|
599
|
-
symbols,
|
|
600
|
-
tokens: allTokens
|
|
601
|
-
});
|
|
602
|
-
const moduleData = {
|
|
603
|
-
symbols,
|
|
604
|
-
tokens: allTokens
|
|
605
|
-
};
|
|
606
|
-
return {
|
|
607
|
-
filepath,
|
|
608
|
-
lastModified: stats.lastModified,
|
|
609
|
-
chunks,
|
|
610
|
-
moduleData
|
|
611
|
-
};
|
|
489
|
+
const hasWorkspaces = Boolean(pkg.workspaces);
|
|
490
|
+
return { name, relativePath, type, hasWorkspaces };
|
|
491
|
+
} catch {
|
|
492
|
+
return null;
|
|
612
493
|
}
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
if (chunkSymbols.length > 0) {
|
|
627
|
-
const primarySymbol = chunkSymbols[0];
|
|
628
|
-
chunkType = this.symbolTypeToChunkType(primarySymbol.type);
|
|
629
|
-
chunkName = primarySymbol.name;
|
|
630
|
-
isExported = primarySymbol.isExported;
|
|
631
|
-
}
|
|
632
|
-
const chunkId = `${filepath}:${start + 1}-${end}`;
|
|
633
|
-
chunks.push({
|
|
634
|
-
id: chunkId,
|
|
635
|
-
content: chunkContent,
|
|
636
|
-
startLine: start + 1,
|
|
637
|
-
endLine: end,
|
|
638
|
-
type: chunkType,
|
|
639
|
-
name: chunkName,
|
|
640
|
-
isExported
|
|
641
|
-
});
|
|
642
|
-
if (end >= lines.length)
|
|
643
|
-
break;
|
|
644
|
-
}
|
|
645
|
-
return chunks;
|
|
646
|
-
}
|
|
647
|
-
symbolTypeToChunkType(symbolType) {
|
|
648
|
-
switch (symbolType) {
|
|
649
|
-
case "function":
|
|
650
|
-
case "method":
|
|
651
|
-
return "function";
|
|
652
|
-
case "class":
|
|
653
|
-
return "class";
|
|
654
|
-
case "interface":
|
|
655
|
-
return "interface";
|
|
656
|
-
case "type":
|
|
657
|
-
return "type";
|
|
658
|
-
case "enum":
|
|
659
|
-
return "enum";
|
|
660
|
-
case "variable":
|
|
661
|
-
return "variable";
|
|
662
|
-
default:
|
|
663
|
-
return "block";
|
|
664
|
-
}
|
|
665
|
-
}
|
|
666
|
-
async finalize(ctx) {
|
|
667
|
-
const config = ctx.config;
|
|
668
|
-
const coreDir = path3.join(getRaggrepDir(ctx.rootDir, config), "index", "core");
|
|
669
|
-
await fs2.mkdir(coreDir, { recursive: true });
|
|
670
|
-
this.bm25Index = new BM25Index;
|
|
671
|
-
for (const [filepath, entry] of this.symbolIndex) {
|
|
672
|
-
this.bm25Index.addDocument(filepath, entry.tokens);
|
|
673
|
-
}
|
|
674
|
-
const symbolIndexData = {
|
|
675
|
-
version: this.version,
|
|
676
|
-
lastUpdated: new Date().toISOString(),
|
|
677
|
-
files: Object.fromEntries(this.symbolIndex),
|
|
678
|
-
bm25Data: this.bm25Index.serialize()
|
|
679
|
-
};
|
|
680
|
-
await fs2.writeFile(path3.join(coreDir, "symbols.json"), JSON.stringify(symbolIndexData, null, 2));
|
|
681
|
-
console.log(` [Core] Symbol index built with ${this.symbolIndex.size} files`);
|
|
682
|
-
}
|
|
683
|
-
async search(query, ctx, options) {
|
|
684
|
-
const config = ctx.config;
|
|
685
|
-
const topK = options?.topK ?? DEFAULT_TOP_K;
|
|
686
|
-
const minScore = options?.minScore ?? DEFAULT_MIN_SCORE;
|
|
687
|
-
if (this.symbolIndex.size === 0) {
|
|
688
|
-
await this.loadSymbolIndex(ctx.rootDir, config);
|
|
689
|
-
}
|
|
690
|
-
if (!this.bm25Index || this.symbolIndex.size === 0) {
|
|
691
|
-
return [];
|
|
692
|
-
}
|
|
693
|
-
const queryTokens = tokenize(query);
|
|
694
|
-
const bm25Results = this.bm25Index.search(query, topK * 2);
|
|
695
|
-
const bm25Scores = new Map(bm25Results.map((r) => [r.id, r.score]));
|
|
696
|
-
const symbolMatches = this.findSymbolMatches(queryTokens);
|
|
697
|
-
const results = [];
|
|
698
|
-
for (const filepath of this.symbolIndex.keys()) {
|
|
699
|
-
const entry = this.symbolIndex.get(filepath);
|
|
700
|
-
const bm25Score = bm25Scores.get(filepath) ?? 0;
|
|
701
|
-
const symbolScore = symbolMatches.get(filepath) ?? 0;
|
|
702
|
-
if (bm25Score === 0 && symbolScore === 0)
|
|
703
|
-
continue;
|
|
704
|
-
const combinedScore = 0.6 * normalizeScore(bm25Score) + 0.4 * symbolScore;
|
|
705
|
-
if (combinedScore >= minScore) {
|
|
706
|
-
const fileIndex = await ctx.loadFileIndex(filepath);
|
|
707
|
-
if (!fileIndex)
|
|
494
|
+
}
|
|
495
|
+
async function detectProjectStructure(rootDir) {
|
|
496
|
+
const projectMap = new Map;
|
|
497
|
+
let isMonorepo = false;
|
|
498
|
+
try {
|
|
499
|
+
const entries = await fs2.readdir(rootDir, { withFileTypes: true });
|
|
500
|
+
const dirNames = entries.filter((e) => e.isDirectory()).map((e) => e.name);
|
|
501
|
+
const monorepoPatterns = ["apps", "packages", "libs", "services"];
|
|
502
|
+
const hasMonorepoStructure = monorepoPatterns.some((p) => dirNames.includes(p));
|
|
503
|
+
if (hasMonorepoStructure) {
|
|
504
|
+
isMonorepo = true;
|
|
505
|
+
for (const pattern of monorepoPatterns) {
|
|
506
|
+
if (!dirNames.includes(pattern))
|
|
708
507
|
continue;
|
|
709
|
-
const
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
return results.sort((a, b) => b.score - a.score).slice(0, topK);
|
|
723
|
-
}
|
|
724
|
-
findSymbolMatches(queryTokens) {
|
|
725
|
-
const matches = new Map;
|
|
726
|
-
for (const [filepath, entry] of this.symbolIndex) {
|
|
727
|
-
let matchScore = 0;
|
|
728
|
-
for (const symbol of entry.symbols) {
|
|
729
|
-
const symbolName = symbol.name.toLowerCase();
|
|
730
|
-
const symbolParts = symbolsToKeywords([symbol]);
|
|
731
|
-
for (const token of queryTokens) {
|
|
732
|
-
if (symbolName === token) {
|
|
733
|
-
matchScore += symbol.isExported ? 1 : 0.8;
|
|
734
|
-
} else if (symbolName.includes(token) || token.includes(symbolName)) {
|
|
735
|
-
matchScore += symbol.isExported ? 0.5 : 0.4;
|
|
736
|
-
} else if (symbolParts.some((p) => p === token)) {
|
|
737
|
-
matchScore += symbol.isExported ? 0.3 : 0.2;
|
|
508
|
+
const patternDir = path3.join(rootDir, pattern);
|
|
509
|
+
try {
|
|
510
|
+
const subDirs = await fs2.readdir(patternDir, { withFileTypes: true });
|
|
511
|
+
for (const subDir of subDirs) {
|
|
512
|
+
if (!subDir.isDirectory())
|
|
513
|
+
continue;
|
|
514
|
+
const projectRoot = `${pattern}/${subDir.name}`;
|
|
515
|
+
const type = getProjectType(pattern);
|
|
516
|
+
projectMap.set(projectRoot, {
|
|
517
|
+
name: subDir.name,
|
|
518
|
+
root: projectRoot,
|
|
519
|
+
type
|
|
520
|
+
});
|
|
738
521
|
}
|
|
739
|
-
}
|
|
740
|
-
}
|
|
741
|
-
if (matchScore > 0) {
|
|
742
|
-
matches.set(filepath, Math.min(1, matchScore / queryTokens.length));
|
|
522
|
+
} catch {}
|
|
743
523
|
}
|
|
744
524
|
}
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
let bestScore = 0;
|
|
750
|
-
for (const chunk of chunks) {
|
|
751
|
-
let score = 0;
|
|
752
|
-
const chunkContent = chunk.content.toLowerCase();
|
|
753
|
-
for (const token of queryTokens) {
|
|
754
|
-
if (chunkContent.includes(token)) {
|
|
755
|
-
score += 1;
|
|
756
|
-
}
|
|
757
|
-
}
|
|
758
|
-
if (chunk.name) {
|
|
759
|
-
const nameLower = chunk.name.toLowerCase();
|
|
760
|
-
for (const token of queryTokens) {
|
|
761
|
-
if (nameLower.includes(token)) {
|
|
762
|
-
score += 2;
|
|
763
|
-
}
|
|
764
|
-
}
|
|
765
|
-
}
|
|
766
|
-
if (chunk.isExported) {
|
|
767
|
-
score += 0.5;
|
|
525
|
+
const packageJsons = await scanForPackageJsons(rootDir);
|
|
526
|
+
for (const pkg of packageJsons) {
|
|
527
|
+
if (pkg.hasWorkspaces) {
|
|
528
|
+
isMonorepo = true;
|
|
768
529
|
}
|
|
769
|
-
if (
|
|
770
|
-
|
|
771
|
-
bestChunk = chunk;
|
|
530
|
+
if (packageJsons.length > 1) {
|
|
531
|
+
isMonorepo = true;
|
|
772
532
|
}
|
|
533
|
+
projectMap.set(pkg.relativePath, {
|
|
534
|
+
name: pkg.name,
|
|
535
|
+
root: pkg.relativePath,
|
|
536
|
+
type: pkg.type
|
|
537
|
+
});
|
|
773
538
|
}
|
|
774
|
-
|
|
775
|
-
}
|
|
776
|
-
async loadSymbolIndex(rootDir, config) {
|
|
777
|
-
const coreDir = path3.join(getRaggrepDir(rootDir, config), "index", "core");
|
|
778
|
-
const symbolsPath = path3.join(coreDir, "symbols.json");
|
|
539
|
+
let rootType = "unknown";
|
|
779
540
|
try {
|
|
780
|
-
const
|
|
781
|
-
const
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
this.bm25Index = BM25Index.deserialize(data.bm25Data);
|
|
541
|
+
const rootPkgPath = path3.join(rootDir, "package.json");
|
|
542
|
+
const rootPkg = JSON.parse(await fs2.readFile(rootPkgPath, "utf-8"));
|
|
543
|
+
if (rootPkg.workspaces) {
|
|
544
|
+
isMonorepo = true;
|
|
785
545
|
}
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
546
|
+
const deps = { ...rootPkg.dependencies, ...rootPkg.devDependencies };
|
|
547
|
+
if (deps["next"] || deps["react"] || deps["vue"]) {
|
|
548
|
+
rootType = "app";
|
|
549
|
+
} else if (deps["express"] || deps["fastify"] || deps["koa"]) {
|
|
550
|
+
rootType = "service";
|
|
551
|
+
}
|
|
552
|
+
} catch {}
|
|
553
|
+
const projects = Array.from(projectMap.values()).sort((a, b) => a.root.length - b.root.length);
|
|
554
|
+
return {
|
|
555
|
+
projects,
|
|
556
|
+
isMonorepo,
|
|
557
|
+
rootType: isMonorepo ? undefined : rootType
|
|
558
|
+
};
|
|
559
|
+
} catch {
|
|
560
|
+
return {
|
|
561
|
+
projects: [],
|
|
562
|
+
isMonorepo: false,
|
|
563
|
+
rootType: "unknown"
|
|
564
|
+
};
|
|
790
565
|
}
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
566
|
+
}
|
|
567
|
+
function getProjectType(patternDir) {
|
|
568
|
+
switch (patternDir) {
|
|
569
|
+
case "apps":
|
|
570
|
+
return "app";
|
|
571
|
+
case "packages":
|
|
572
|
+
case "libs":
|
|
573
|
+
return "library";
|
|
574
|
+
case "services":
|
|
575
|
+
return "service";
|
|
576
|
+
case "scripts":
|
|
577
|
+
case "tools":
|
|
578
|
+
return "script";
|
|
579
|
+
default:
|
|
580
|
+
return "unknown";
|
|
794
581
|
}
|
|
795
582
|
}
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
function cosineSimilarity(a, b) {
|
|
804
|
-
if (a.length !== b.length) {
|
|
805
|
-
throw new Error(`Vector length mismatch: ${a.length} vs ${b.length}`);
|
|
583
|
+
function findProjectForFile(filepath, structure) {
|
|
584
|
+
const normalizedPath = filepath.replace(/\\/g, "/");
|
|
585
|
+
const matches = [];
|
|
586
|
+
for (const project of structure.projects) {
|
|
587
|
+
if (normalizedPath === project.root || normalizedPath.startsWith(project.root + "/")) {
|
|
588
|
+
matches.push(project);
|
|
589
|
+
}
|
|
806
590
|
}
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
let normB = 0;
|
|
810
|
-
for (let i = 0;i < a.length; i++) {
|
|
811
|
-
dotProduct += a[i] * b[i];
|
|
812
|
-
normA += a[i] * a[i];
|
|
813
|
-
normB += b[i] * b[i];
|
|
591
|
+
if (matches.length > 0) {
|
|
592
|
+
return matches.reduce((best, current) => current.root.length > best.root.length ? current : best);
|
|
814
593
|
}
|
|
815
|
-
const
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
594
|
+
for (const { pattern, type } of PROJECT_PATTERNS) {
|
|
595
|
+
const match = normalizedPath.match(pattern);
|
|
596
|
+
if (match) {
|
|
597
|
+
return {
|
|
598
|
+
name: match[1],
|
|
599
|
+
root: match[0],
|
|
600
|
+
type
|
|
601
|
+
};
|
|
602
|
+
}
|
|
603
|
+
}
|
|
604
|
+
return {
|
|
605
|
+
name: "root",
|
|
606
|
+
root: "",
|
|
607
|
+
type: structure.rootType ?? "unknown"
|
|
608
|
+
};
|
|
819
609
|
}
|
|
610
|
+
var MAX_SCAN_DEPTH = 4, SKIP_DIRS, PROJECT_PATTERNS, SCOPE_KEYWORDS;
|
|
611
|
+
var init_projectDetector = __esm(() => {
|
|
612
|
+
SKIP_DIRS = new Set([
|
|
613
|
+
"node_modules",
|
|
614
|
+
".git",
|
|
615
|
+
"dist",
|
|
616
|
+
"build",
|
|
617
|
+
".next",
|
|
618
|
+
".nuxt",
|
|
619
|
+
"coverage",
|
|
620
|
+
".raggrep"
|
|
621
|
+
]);
|
|
622
|
+
PROJECT_PATTERNS = [
|
|
623
|
+
{ pattern: /^apps\/([^/]+)/, type: "app", defaultScope: "unknown" },
|
|
624
|
+
{ pattern: /^packages\/([^/]+)/, type: "library", defaultScope: "shared" },
|
|
625
|
+
{ pattern: /^libs\/([^/]+)/, type: "library", defaultScope: "shared" },
|
|
626
|
+
{ pattern: /^services\/([^/]+)/, type: "service", defaultScope: "backend" },
|
|
627
|
+
{ pattern: /^scripts\/([^/]+)/, type: "script", defaultScope: "tooling" },
|
|
628
|
+
{ pattern: /^tools\/([^/]+)/, type: "script", defaultScope: "tooling" }
|
|
629
|
+
];
|
|
630
|
+
SCOPE_KEYWORDS = {
|
|
631
|
+
frontend: [
|
|
632
|
+
"web",
|
|
633
|
+
"webapp",
|
|
634
|
+
"frontend",
|
|
635
|
+
"client",
|
|
636
|
+
"ui",
|
|
637
|
+
"app",
|
|
638
|
+
"mobile",
|
|
639
|
+
"react",
|
|
640
|
+
"vue",
|
|
641
|
+
"angular",
|
|
642
|
+
"next",
|
|
643
|
+
"nuxt"
|
|
644
|
+
],
|
|
645
|
+
backend: [
|
|
646
|
+
"api",
|
|
647
|
+
"server",
|
|
648
|
+
"backend",
|
|
649
|
+
"service",
|
|
650
|
+
"worker",
|
|
651
|
+
"lambda",
|
|
652
|
+
"functions"
|
|
653
|
+
],
|
|
654
|
+
shared: ["shared", "common", "utils", "lib", "core", "types", "models"],
|
|
655
|
+
tooling: [
|
|
656
|
+
"scripts",
|
|
657
|
+
"tools",
|
|
658
|
+
"cli",
|
|
659
|
+
"devtools",
|
|
660
|
+
"build",
|
|
661
|
+
"config",
|
|
662
|
+
"infra"
|
|
663
|
+
],
|
|
664
|
+
unknown: []
|
|
665
|
+
};
|
|
666
|
+
});
|
|
820
667
|
|
|
821
|
-
// src/
|
|
822
|
-
import * as
|
|
823
|
-
function
|
|
824
|
-
const
|
|
825
|
-
|
|
826
|
-
return parseTypeScript(content, filepath);
|
|
827
|
-
}
|
|
828
|
-
return parseGenericCode(content);
|
|
668
|
+
// src/introspection/conventions/entryPoints.ts
|
|
669
|
+
import * as path4 from "path";
|
|
670
|
+
function getParentFolder(filepath) {
|
|
671
|
+
const dir = path4.dirname(filepath);
|
|
672
|
+
return path4.basename(dir);
|
|
829
673
|
}
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
function isExported(node) {
|
|
847
|
-
if (!ts.canHaveModifiers(node))
|
|
848
|
-
return false;
|
|
849
|
-
const modifiers = ts.getModifiers(node);
|
|
850
|
-
return modifiers?.some((m) => m.kind === ts.SyntaxKind.ExportKeyword) ?? false;
|
|
851
|
-
}
|
|
852
|
-
function getJSDoc(node) {
|
|
853
|
-
const jsDocNodes = ts.getJSDocCommentsAndTags(node);
|
|
854
|
-
if (jsDocNodes.length === 0)
|
|
855
|
-
return;
|
|
856
|
-
return jsDocNodes.map((doc) => doc.getText(sourceFile)).join(`
|
|
857
|
-
`);
|
|
858
|
-
}
|
|
859
|
-
function getFunctionName(node) {
|
|
860
|
-
if (ts.isFunctionDeclaration(node) && node.name) {
|
|
861
|
-
return node.name.text;
|
|
862
|
-
}
|
|
863
|
-
if (ts.isMethodDeclaration(node) && ts.isIdentifier(node.name)) {
|
|
864
|
-
return node.name.text;
|
|
865
|
-
}
|
|
866
|
-
if (ts.isVariableDeclaration(node) && ts.isIdentifier(node.name)) {
|
|
867
|
-
return node.name.text;
|
|
868
|
-
}
|
|
869
|
-
return;
|
|
870
|
-
}
|
|
871
|
-
function visit(node) {
|
|
872
|
-
const { startLine, endLine } = getLineNumbers(node);
|
|
873
|
-
if (ts.isFunctionDeclaration(node) && node.name) {
|
|
874
|
-
chunks.push({
|
|
875
|
-
content: getNodeText(node),
|
|
876
|
-
startLine,
|
|
877
|
-
endLine,
|
|
878
|
-
type: "function",
|
|
879
|
-
name: node.name.text,
|
|
880
|
-
isExported: isExported(node),
|
|
881
|
-
jsDoc: getJSDoc(node)
|
|
882
|
-
});
|
|
883
|
-
return;
|
|
884
|
-
}
|
|
885
|
-
if (ts.isVariableStatement(node)) {
|
|
886
|
-
for (const decl of node.declarationList.declarations) {
|
|
887
|
-
if (decl.initializer && (ts.isArrowFunction(decl.initializer) || ts.isFunctionExpression(decl.initializer))) {
|
|
888
|
-
const name = ts.isIdentifier(decl.name) ? decl.name.text : undefined;
|
|
889
|
-
chunks.push({
|
|
890
|
-
content: getNodeText(node),
|
|
891
|
-
startLine,
|
|
892
|
-
endLine,
|
|
893
|
-
type: "function",
|
|
894
|
-
name,
|
|
895
|
-
isExported: isExported(node),
|
|
896
|
-
jsDoc: getJSDoc(node)
|
|
897
|
-
});
|
|
898
|
-
return;
|
|
674
|
+
var entryPointConventions;
|
|
675
|
+
var init_entryPoints = __esm(() => {
|
|
676
|
+
entryPointConventions = [
|
|
677
|
+
{
|
|
678
|
+
id: "index-file",
|
|
679
|
+
name: "Index/Barrel File",
|
|
680
|
+
description: "Module entry point that typically re-exports from other files",
|
|
681
|
+
category: "entry-point",
|
|
682
|
+
match: (filepath, filename) => {
|
|
683
|
+
return /^index\.(ts|tsx|js|jsx|mjs|cjs)$/.test(filename);
|
|
684
|
+
},
|
|
685
|
+
keywords: ["entry", "barrel", "exports", "module"],
|
|
686
|
+
dynamicKeywords: (filepath) => {
|
|
687
|
+
const parent = getParentFolder(filepath);
|
|
688
|
+
if (["src", "lib", "dist", "build", ".", ""].includes(parent)) {
|
|
689
|
+
return [];
|
|
899
690
|
}
|
|
691
|
+
return [parent.toLowerCase()];
|
|
900
692
|
}
|
|
693
|
+
},
|
|
694
|
+
{
|
|
695
|
+
id: "main-file",
|
|
696
|
+
name: "Main Entry Point",
|
|
697
|
+
description: "Application main entry point",
|
|
698
|
+
category: "entry-point",
|
|
699
|
+
match: (filepath, filename) => {
|
|
700
|
+
return /^main\.(ts|tsx|js|jsx|mjs|cjs)$/.test(filename);
|
|
701
|
+
},
|
|
702
|
+
keywords: ["entry", "main", "entrypoint", "bootstrap", "startup"]
|
|
703
|
+
},
|
|
704
|
+
{
|
|
705
|
+
id: "app-component",
|
|
706
|
+
name: "Root App Component",
|
|
707
|
+
description: "Root application component (React, Vue, etc.)",
|
|
708
|
+
category: "entry-point",
|
|
709
|
+
match: (filepath, filename) => {
|
|
710
|
+
return /^App\.(tsx|jsx|vue|svelte)$/.test(filename);
|
|
711
|
+
},
|
|
712
|
+
keywords: ["root", "app", "application", "component", "main"]
|
|
713
|
+
},
|
|
714
|
+
{
|
|
715
|
+
id: "deno-mod",
|
|
716
|
+
name: "Deno Module Entry",
|
|
717
|
+
description: "Deno module entry point",
|
|
718
|
+
category: "entry-point",
|
|
719
|
+
match: (filepath, filename) => {
|
|
720
|
+
return filename === "mod.ts";
|
|
721
|
+
},
|
|
722
|
+
keywords: ["entry", "module", "deno", "exports"],
|
|
723
|
+
dynamicKeywords: (filepath) => {
|
|
724
|
+
const parent = getParentFolder(filepath);
|
|
725
|
+
if (["src", "lib", ".", ""].includes(parent)) {
|
|
726
|
+
return [];
|
|
727
|
+
}
|
|
728
|
+
return [parent.toLowerCase()];
|
|
729
|
+
}
|
|
730
|
+
},
|
|
731
|
+
{
|
|
732
|
+
id: "python-init",
|
|
733
|
+
name: "Python Package Init",
|
|
734
|
+
description: "Python package initialization file",
|
|
735
|
+
category: "entry-point",
|
|
736
|
+
match: (filepath, filename) => {
|
|
737
|
+
return filename === "__init__.py";
|
|
738
|
+
},
|
|
739
|
+
keywords: ["entry", "package", "init", "python", "module"],
|
|
740
|
+
dynamicKeywords: (filepath) => {
|
|
741
|
+
const parent = getParentFolder(filepath);
|
|
742
|
+
if (["src", "lib", ".", ""].includes(parent)) {
|
|
743
|
+
return [];
|
|
744
|
+
}
|
|
745
|
+
return [parent.toLowerCase()];
|
|
746
|
+
}
|
|
747
|
+
},
|
|
748
|
+
{
|
|
749
|
+
id: "rust-lib",
|
|
750
|
+
name: "Rust Library Entry",
|
|
751
|
+
description: "Rust library crate entry point",
|
|
752
|
+
category: "entry-point",
|
|
753
|
+
match: (filepath, filename) => {
|
|
754
|
+
return filename === "lib.rs" || filename === "main.rs";
|
|
755
|
+
},
|
|
756
|
+
keywords: ["entry", "crate", "rust", "module"]
|
|
901
757
|
}
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
758
|
+
];
|
|
759
|
+
});
|
|
760
|
+
|
|
761
|
+
// src/introspection/conventions/configFiles.ts
|
|
762
|
+
var configFileConventions;
|
|
763
|
+
var init_configFiles = __esm(() => {
|
|
764
|
+
configFileConventions = [
|
|
765
|
+
{
|
|
766
|
+
id: "package-json",
|
|
767
|
+
name: "Package.json",
|
|
768
|
+
description: "Node.js package manifest",
|
|
769
|
+
category: "configuration",
|
|
770
|
+
match: (filepath, filename) => filename === "package.json",
|
|
771
|
+
keywords: ["package", "dependencies", "npm", "scripts", "manifest", "node"]
|
|
772
|
+
},
|
|
773
|
+
{
|
|
774
|
+
id: "pnpm-workspace",
|
|
775
|
+
name: "PNPM Workspace",
|
|
776
|
+
description: "PNPM monorepo workspace configuration",
|
|
777
|
+
category: "configuration",
|
|
778
|
+
match: (filepath, filename) => filename === "pnpm-workspace.yaml" || filename === "pnpm-workspace.yml",
|
|
779
|
+
keywords: ["workspace", "monorepo", "pnpm", "packages"]
|
|
780
|
+
},
|
|
781
|
+
{
|
|
782
|
+
id: "yarn-lock",
|
|
783
|
+
name: "Yarn Lock",
|
|
784
|
+
description: "Yarn dependency lock file",
|
|
785
|
+
category: "configuration",
|
|
786
|
+
match: (filepath, filename) => filename === "yarn.lock",
|
|
787
|
+
keywords: ["dependencies", "lock", "yarn", "versions"]
|
|
788
|
+
},
|
|
789
|
+
{
|
|
790
|
+
id: "package-lock",
|
|
791
|
+
name: "Package Lock",
|
|
792
|
+
description: "NPM dependency lock file",
|
|
793
|
+
category: "configuration",
|
|
794
|
+
match: (filepath, filename) => filename === "package-lock.json",
|
|
795
|
+
keywords: ["dependencies", "lock", "npm", "versions"]
|
|
796
|
+
},
|
|
797
|
+
{
|
|
798
|
+
id: "bun-lockb",
|
|
799
|
+
name: "Bun Lock",
|
|
800
|
+
description: "Bun dependency lock file",
|
|
801
|
+
category: "configuration",
|
|
802
|
+
match: (filepath, filename) => filename === "bun.lockb" || filename === "bun.lock",
|
|
803
|
+
keywords: ["dependencies", "lock", "bun", "versions"]
|
|
804
|
+
},
|
|
805
|
+
{
|
|
806
|
+
id: "tsconfig",
|
|
807
|
+
name: "TypeScript Config",
|
|
808
|
+
description: "TypeScript compiler configuration",
|
|
809
|
+
category: "configuration",
|
|
810
|
+
match: (filepath, filename) => filename === "tsconfig.json" || filename.startsWith("tsconfig.") && filename.endsWith(".json"),
|
|
811
|
+
keywords: [
|
|
812
|
+
"typescript",
|
|
813
|
+
"config",
|
|
814
|
+
"compiler",
|
|
815
|
+
"ts",
|
|
816
|
+
"settings",
|
|
817
|
+
"paths",
|
|
818
|
+
"types"
|
|
819
|
+
]
|
|
820
|
+
},
|
|
821
|
+
{
|
|
822
|
+
id: "jsconfig",
|
|
823
|
+
name: "JavaScript Config",
|
|
824
|
+
description: "JavaScript project configuration",
|
|
825
|
+
category: "configuration",
|
|
826
|
+
match: (filepath, filename) => filename === "jsconfig.json",
|
|
827
|
+
keywords: ["javascript", "config", "compiler", "js", "settings", "paths"]
|
|
828
|
+
},
|
|
829
|
+
{
|
|
830
|
+
id: "eslint-config",
|
|
831
|
+
name: "ESLint Config",
|
|
832
|
+
description: "ESLint linting configuration",
|
|
833
|
+
category: "configuration",
|
|
834
|
+
match: (filepath, filename) => filename === ".eslintrc" || filename === ".eslintrc.js" || filename === ".eslintrc.cjs" || filename === ".eslintrc.json" || filename === ".eslintrc.yml" || filename === ".eslintrc.yaml" || filename === "eslint.config.js" || filename === "eslint.config.mjs" || filename === "eslint.config.cjs",
|
|
835
|
+
keywords: ["eslint", "linting", "lint", "rules", "code quality"]
|
|
836
|
+
},
|
|
837
|
+
{
|
|
838
|
+
id: "prettier-config",
|
|
839
|
+
name: "Prettier Config",
|
|
840
|
+
description: "Prettier code formatting configuration",
|
|
841
|
+
category: "configuration",
|
|
842
|
+
match: (filepath, filename) => filename === ".prettierrc" || filename === ".prettierrc.js" || filename === ".prettierrc.cjs" || filename === ".prettierrc.json" || filename === ".prettierrc.yml" || filename === ".prettierrc.yaml" || filename === "prettier.config.js" || filename === "prettier.config.cjs" || filename === "prettier.config.mjs",
|
|
843
|
+
keywords: ["prettier", "formatting", "format", "code style", "style"]
|
|
844
|
+
},
|
|
845
|
+
{
|
|
846
|
+
id: "biome-config",
|
|
847
|
+
name: "Biome Config",
|
|
848
|
+
description: "Biome linting and formatting configuration",
|
|
849
|
+
category: "configuration",
|
|
850
|
+
match: (filepath, filename) => filename === "biome.json" || filename === "biome.jsonc",
|
|
851
|
+
keywords: ["biome", "linting", "formatting", "lint", "format"]
|
|
852
|
+
},
|
|
853
|
+
{
|
|
854
|
+
id: "vite-config",
|
|
855
|
+
name: "Vite Config",
|
|
856
|
+
description: "Vite build tool configuration",
|
|
857
|
+
category: "build",
|
|
858
|
+
match: (filepath, filename) => filename === "vite.config.ts" || filename === "vite.config.js" || filename === "vite.config.mjs",
|
|
859
|
+
keywords: ["vite", "bundler", "build", "dev server", "hmr"]
|
|
860
|
+
},
|
|
861
|
+
{
|
|
862
|
+
id: "webpack-config",
|
|
863
|
+
name: "Webpack Config",
|
|
864
|
+
description: "Webpack bundler configuration",
|
|
865
|
+
category: "build",
|
|
866
|
+
match: (filepath, filename) => filename === "webpack.config.js" || filename === "webpack.config.ts" || filename.startsWith("webpack.") && (filename.endsWith(".js") || filename.endsWith(".ts")),
|
|
867
|
+
keywords: ["webpack", "bundler", "build", "loaders", "plugins"]
|
|
868
|
+
},
|
|
869
|
+
{
|
|
870
|
+
id: "rollup-config",
|
|
871
|
+
name: "Rollup Config",
|
|
872
|
+
description: "Rollup bundler configuration",
|
|
873
|
+
category: "build",
|
|
874
|
+
match: (filepath, filename) => filename === "rollup.config.js" || filename === "rollup.config.ts" || filename === "rollup.config.mjs",
|
|
875
|
+
keywords: ["rollup", "bundler", "build", "esm", "bundle"]
|
|
876
|
+
},
|
|
877
|
+
{
|
|
878
|
+
id: "esbuild-config",
|
|
879
|
+
name: "esbuild Config",
|
|
880
|
+
description: "esbuild bundler configuration",
|
|
881
|
+
category: "build",
|
|
882
|
+
match: (filepath, filename) => filename === "esbuild.config.js" || filename === "esbuild.config.ts" || filename === "esbuild.config.mjs",
|
|
883
|
+
keywords: ["esbuild", "bundler", "build", "fast"]
|
|
884
|
+
},
|
|
885
|
+
{
|
|
886
|
+
id: "jest-config",
|
|
887
|
+
name: "Jest Config",
|
|
888
|
+
description: "Jest testing framework configuration",
|
|
889
|
+
category: "test",
|
|
890
|
+
match: (filepath, filename) => filename === "jest.config.js" || filename === "jest.config.ts" || filename === "jest.config.mjs" || filename === "jest.config.cjs" || filename === "jest.config.json",
|
|
891
|
+
keywords: ["jest", "testing", "test", "unit test", "config"]
|
|
892
|
+
},
|
|
893
|
+
{
|
|
894
|
+
id: "vitest-config",
|
|
895
|
+
name: "Vitest Config",
|
|
896
|
+
description: "Vitest testing framework configuration",
|
|
897
|
+
category: "test",
|
|
898
|
+
match: (filepath, filename) => filename === "vitest.config.ts" || filename === "vitest.config.js" || filename === "vitest.config.mts",
|
|
899
|
+
keywords: ["vitest", "testing", "test", "unit test", "config"]
|
|
900
|
+
},
|
|
901
|
+
{
|
|
902
|
+
id: "playwright-config",
|
|
903
|
+
name: "Playwright Config",
|
|
904
|
+
description: "Playwright E2E testing configuration",
|
|
905
|
+
category: "test",
|
|
906
|
+
match: (filepath, filename) => filename === "playwright.config.ts" || filename === "playwright.config.js",
|
|
907
|
+
keywords: ["playwright", "testing", "e2e", "end-to-end", "browser test"]
|
|
908
|
+
},
|
|
909
|
+
{
|
|
910
|
+
id: "cypress-config",
|
|
911
|
+
name: "Cypress Config",
|
|
912
|
+
description: "Cypress E2E testing configuration",
|
|
913
|
+
category: "test",
|
|
914
|
+
match: (filepath, filename) => filename === "cypress.config.ts" || filename === "cypress.config.js" || filename === "cypress.json",
|
|
915
|
+
keywords: ["cypress", "testing", "e2e", "end-to-end", "browser test"]
|
|
916
|
+
},
|
|
917
|
+
{
|
|
918
|
+
id: "tailwind-config",
|
|
919
|
+
name: "Tailwind Config",
|
|
920
|
+
description: "Tailwind CSS configuration",
|
|
921
|
+
category: "configuration",
|
|
922
|
+
match: (filepath, filename) => filename === "tailwind.config.js" || filename === "tailwind.config.ts" || filename === "tailwind.config.cjs" || filename === "tailwind.config.mjs",
|
|
923
|
+
keywords: ["tailwind", "css", "styling", "utility", "design"]
|
|
924
|
+
},
|
|
925
|
+
{
|
|
926
|
+
id: "postcss-config",
|
|
927
|
+
name: "PostCSS Config",
|
|
928
|
+
description: "PostCSS configuration",
|
|
929
|
+
category: "configuration",
|
|
930
|
+
match: (filepath, filename) => filename === "postcss.config.js" || filename === "postcss.config.cjs" || filename === "postcss.config.mjs" || filename === ".postcssrc" || filename === ".postcssrc.json",
|
|
931
|
+
keywords: ["postcss", "css", "styling", "transforms"]
|
|
932
|
+
},
|
|
933
|
+
{
|
|
934
|
+
id: "env-file",
|
|
935
|
+
name: "Environment File",
|
|
936
|
+
description: "Environment variables file",
|
|
937
|
+
category: "configuration",
|
|
938
|
+
match: (filepath, filename) => filename === ".env" || filename === ".env.local" || filename === ".env.development" || filename === ".env.production" || filename === ".env.test" || filename.startsWith(".env."),
|
|
939
|
+
keywords: ["environment", "env", "variables", "secrets", "config"]
|
|
940
|
+
},
|
|
941
|
+
{
|
|
942
|
+
id: "env-example",
|
|
943
|
+
name: "Environment Example",
|
|
944
|
+
description: "Example environment variables file",
|
|
945
|
+
category: "documentation",
|
|
946
|
+
match: (filepath, filename) => filename === ".env.example" || filename === ".env.sample" || filename === ".env.template",
|
|
947
|
+
keywords: ["environment", "env", "example", "template", "setup"]
|
|
948
|
+
},
|
|
949
|
+
{
|
|
950
|
+
id: "dockerfile",
|
|
951
|
+
name: "Dockerfile",
|
|
952
|
+
description: "Docker container image definition",
|
|
953
|
+
category: "deployment",
|
|
954
|
+
match: (filepath, filename) => filename === "Dockerfile" || filename.startsWith("Dockerfile."),
|
|
955
|
+
keywords: ["docker", "container", "image", "deployment", "build"]
|
|
956
|
+
},
|
|
957
|
+
{
|
|
958
|
+
id: "docker-compose",
|
|
959
|
+
name: "Docker Compose",
|
|
960
|
+
description: "Docker Compose multi-container configuration",
|
|
961
|
+
category: "deployment",
|
|
962
|
+
match: (filepath, filename) => filename === "docker-compose.yml" || filename === "docker-compose.yaml" || filename === "compose.yml" || filename === "compose.yaml" || filename.startsWith("docker-compose."),
|
|
963
|
+
keywords: ["docker", "compose", "containers", "services", "deployment"]
|
|
964
|
+
},
|
|
965
|
+
{
|
|
966
|
+
id: "github-actions",
|
|
967
|
+
name: "GitHub Actions Workflow",
|
|
968
|
+
description: "GitHub Actions CI/CD workflow",
|
|
969
|
+
category: "deployment",
|
|
970
|
+
match: (filepath) => filepath.includes(".github/workflows/") && filepath.endsWith(".yml"),
|
|
971
|
+
keywords: ["github", "actions", "ci", "cd", "workflow", "automation"]
|
|
972
|
+
},
|
|
973
|
+
{
|
|
974
|
+
id: "vercel-config",
|
|
975
|
+
name: "Vercel Config",
|
|
976
|
+
description: "Vercel deployment configuration",
|
|
977
|
+
category: "deployment",
|
|
978
|
+
match: (filepath, filename) => filename === "vercel.json",
|
|
979
|
+
keywords: ["vercel", "deployment", "hosting", "serverless"]
|
|
980
|
+
},
|
|
981
|
+
{
|
|
982
|
+
id: "netlify-config",
|
|
983
|
+
name: "Netlify Config",
|
|
984
|
+
description: "Netlify deployment configuration",
|
|
985
|
+
category: "deployment",
|
|
986
|
+
match: (filepath, filename) => filename === "netlify.toml",
|
|
987
|
+
keywords: ["netlify", "deployment", "hosting", "functions"]
|
|
988
|
+
},
|
|
989
|
+
{
|
|
990
|
+
id: "gitignore",
|
|
991
|
+
name: "Git Ignore",
|
|
992
|
+
description: "Git ignored files configuration",
|
|
993
|
+
category: "configuration",
|
|
994
|
+
match: (filepath, filename) => filename === ".gitignore",
|
|
995
|
+
keywords: ["git", "ignore", "version control", "excluded"]
|
|
996
|
+
},
|
|
997
|
+
{
|
|
998
|
+
id: "gitattributes",
|
|
999
|
+
name: "Git Attributes",
|
|
1000
|
+
description: "Git file attributes configuration",
|
|
1001
|
+
category: "configuration",
|
|
1002
|
+
match: (filepath, filename) => filename === ".gitattributes",
|
|
1003
|
+
keywords: ["git", "attributes", "version control", "line endings"]
|
|
1004
|
+
},
|
|
1005
|
+
{
|
|
1006
|
+
id: "readme",
|
|
1007
|
+
name: "README",
|
|
1008
|
+
description: "Project documentation",
|
|
1009
|
+
category: "documentation",
|
|
1010
|
+
match: (filepath, filename) => filename.toLowerCase() === "readme.md" || filename.toLowerCase() === "readme",
|
|
1011
|
+
keywords: [
|
|
1012
|
+
"readme",
|
|
1013
|
+
"documentation",
|
|
1014
|
+
"docs",
|
|
1015
|
+
"overview",
|
|
1016
|
+
"getting started"
|
|
1017
|
+
]
|
|
1018
|
+
},
|
|
1019
|
+
{
|
|
1020
|
+
id: "changelog",
|
|
1021
|
+
name: "Changelog",
|
|
1022
|
+
description: "Project changelog",
|
|
1023
|
+
category: "documentation",
|
|
1024
|
+
match: (filepath, filename) => filename.toLowerCase() === "changelog.md" || filename.toLowerCase() === "changelog",
|
|
1025
|
+
keywords: ["changelog", "changes", "releases", "history", "versions"]
|
|
1026
|
+
},
|
|
1027
|
+
{
|
|
1028
|
+
id: "contributing",
|
|
1029
|
+
name: "Contributing Guide",
|
|
1030
|
+
description: "Contribution guidelines",
|
|
1031
|
+
category: "documentation",
|
|
1032
|
+
match: (filepath, filename) => filename.toLowerCase() === "contributing.md" || filename.toLowerCase() === "contributing",
|
|
1033
|
+
keywords: ["contributing", "contribution", "guidelines", "development"]
|
|
1034
|
+
},
|
|
1035
|
+
{
|
|
1036
|
+
id: "license",
|
|
1037
|
+
name: "License",
|
|
1038
|
+
description: "Project license",
|
|
1039
|
+
category: "documentation",
|
|
1040
|
+
match: (filepath, filename) => filename.toLowerCase() === "license" || filename.toLowerCase() === "license.md" || filename.toLowerCase() === "license.txt",
|
|
1041
|
+
keywords: ["license", "legal", "copyright", "terms"]
|
|
937
1042
|
}
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
1043
|
+
];
|
|
1044
|
+
});
|
|
1045
|
+
|
|
1046
|
+
// src/introspection/conventions/frameworks/nextjs.ts
|
|
1047
|
+
var nextjsConventions, nextjsFramework;
|
|
1048
|
+
var init_nextjs = __esm(() => {
|
|
1049
|
+
nextjsConventions = [
|
|
1050
|
+
{
|
|
1051
|
+
id: "next-config",
|
|
1052
|
+
name: "Next.js Config",
|
|
1053
|
+
description: "Next.js framework configuration",
|
|
1054
|
+
category: "configuration",
|
|
1055
|
+
match: (filepath, filename) => filename === "next.config.js" || filename === "next.config.mjs" || filename === "next.config.ts",
|
|
1056
|
+
keywords: ["nextjs", "next", "config", "framework", "settings"]
|
|
1057
|
+
},
|
|
1058
|
+
{
|
|
1059
|
+
id: "next-env",
|
|
1060
|
+
name: "Next.js Environment Types",
|
|
1061
|
+
description: "Next.js TypeScript environment declarations",
|
|
1062
|
+
category: "types",
|
|
1063
|
+
match: (filepath, filename) => filename === "next-env.d.ts",
|
|
1064
|
+
keywords: ["nextjs", "types", "typescript", "declarations"]
|
|
1065
|
+
},
|
|
1066
|
+
{
|
|
1067
|
+
id: "next-layout",
|
|
1068
|
+
name: "Next.js Layout",
|
|
1069
|
+
description: "Next.js layout component (App Router)",
|
|
1070
|
+
category: "framework",
|
|
1071
|
+
match: (filepath, filename) => (filename === "layout.tsx" || filename === "layout.js") && (filepath.includes("/app/") || filepath.startsWith("app/")),
|
|
1072
|
+
keywords: ["nextjs", "layout", "wrapper", "template", "app router"],
|
|
1073
|
+
dynamicKeywords: (filepath) => {
|
|
1074
|
+
const match = filepath.match(/app\/(.+?)\/layout\./);
|
|
1075
|
+
if (match) {
|
|
1076
|
+
const segments = match[1].split("/").filter((s) => !s.startsWith("(") && !s.startsWith("["));
|
|
1077
|
+
return segments.map((s) => s.toLowerCase());
|
|
1078
|
+
}
|
|
1079
|
+
if (filepath === "app/layout.tsx" || filepath === "app/layout.js") {
|
|
1080
|
+
return ["root", "main"];
|
|
1081
|
+
}
|
|
1082
|
+
return [];
|
|
1083
|
+
}
|
|
1084
|
+
},
|
|
1085
|
+
{
|
|
1086
|
+
id: "next-page",
|
|
1087
|
+
name: "Next.js Page",
|
|
1088
|
+
description: "Next.js page component (App Router)",
|
|
1089
|
+
category: "framework",
|
|
1090
|
+
match: (filepath, filename) => (filename === "page.tsx" || filename === "page.js") && (filepath.includes("/app/") || filepath.startsWith("app/")),
|
|
1091
|
+
keywords: ["nextjs", "page", "route", "view", "app router"],
|
|
1092
|
+
dynamicKeywords: (filepath) => {
|
|
1093
|
+
const match = filepath.match(/app\/(.+?)\/page\./);
|
|
1094
|
+
if (match) {
|
|
1095
|
+
const segments = match[1].split("/").filter((s) => !s.startsWith("(")).map((s) => s.replace(/^\[(.+?)\]$/, "$1"));
|
|
1096
|
+
return segments.map((s) => s.toLowerCase());
|
|
1097
|
+
}
|
|
1098
|
+
if (filepath === "app/page.tsx" || filepath === "app/page.js") {
|
|
1099
|
+
return ["home", "index", "root"];
|
|
1100
|
+
}
|
|
1101
|
+
return [];
|
|
1102
|
+
}
|
|
1103
|
+
},
|
|
1104
|
+
{
|
|
1105
|
+
id: "next-loading",
|
|
1106
|
+
name: "Next.js Loading",
|
|
1107
|
+
description: "Next.js loading UI component",
|
|
1108
|
+
category: "framework",
|
|
1109
|
+
match: (filepath, filename) => (filename === "loading.tsx" || filename === "loading.js") && (filepath.includes("/app/") || filepath.startsWith("app/")),
|
|
1110
|
+
keywords: ["nextjs", "loading", "suspense", "skeleton", "spinner"]
|
|
1111
|
+
},
|
|
1112
|
+
{
|
|
1113
|
+
id: "next-error",
|
|
1114
|
+
name: "Next.js Error",
|
|
1115
|
+
description: "Next.js error boundary component",
|
|
1116
|
+
category: "framework",
|
|
1117
|
+
match: (filepath, filename) => (filename === "error.tsx" || filename === "error.js") && (filepath.includes("/app/") || filepath.startsWith("app/")),
|
|
1118
|
+
keywords: ["nextjs", "error", "boundary", "fallback", "catch"]
|
|
1119
|
+
},
|
|
1120
|
+
{
|
|
1121
|
+
id: "next-not-found",
|
|
1122
|
+
name: "Next.js Not Found",
|
|
1123
|
+
description: "Next.js 404 page component",
|
|
1124
|
+
category: "framework",
|
|
1125
|
+
match: (filepath, filename) => (filename === "not-found.tsx" || filename === "not-found.js") && (filepath.includes("/app/") || filepath.startsWith("app/")),
|
|
1126
|
+
keywords: ["nextjs", "404", "not found", "missing", "error"]
|
|
1127
|
+
},
|
|
1128
|
+
{
|
|
1129
|
+
id: "next-template",
|
|
1130
|
+
name: "Next.js Template",
|
|
1131
|
+
description: "Next.js template component",
|
|
1132
|
+
category: "framework",
|
|
1133
|
+
match: (filepath, filename) => (filename === "template.tsx" || filename === "template.js") && (filepath.includes("/app/") || filepath.startsWith("app/")),
|
|
1134
|
+
keywords: ["nextjs", "template", "wrapper", "app router"]
|
|
1135
|
+
},
|
|
1136
|
+
{
|
|
1137
|
+
id: "next-route-handler",
|
|
1138
|
+
name: "Next.js Route Handler",
|
|
1139
|
+
description: "Next.js API route handler (App Router)",
|
|
1140
|
+
category: "framework",
|
|
1141
|
+
match: (filepath, filename) => (filename === "route.ts" || filename === "route.js") && (filepath.includes("/app/") || filepath.startsWith("app/")),
|
|
1142
|
+
keywords: ["nextjs", "api", "route", "handler", "endpoint", "rest"],
|
|
1143
|
+
dynamicKeywords: (filepath) => {
|
|
1144
|
+
const match = filepath.match(/app\/api\/(.+?)\/route\./);
|
|
1145
|
+
if (match) {
|
|
1146
|
+
const segments = match[1].split("/").filter((s) => !s.startsWith("(")).map((s) => s.replace(/^\[(.+?)\]$/, "$1"));
|
|
1147
|
+
return ["api", ...segments.map((s) => s.toLowerCase())];
|
|
1148
|
+
}
|
|
1149
|
+
return ["api"];
|
|
1150
|
+
}
|
|
1151
|
+
},
|
|
1152
|
+
{
|
|
1153
|
+
id: "next-middleware",
|
|
1154
|
+
name: "Next.js Middleware",
|
|
1155
|
+
description: "Next.js edge middleware",
|
|
1156
|
+
category: "framework",
|
|
1157
|
+
match: (filepath, filename) => filename === "middleware.ts" || filename === "middleware.js",
|
|
1158
|
+
keywords: ["nextjs", "middleware", "edge", "request", "interceptor"]
|
|
1159
|
+
},
|
|
1160
|
+
{
|
|
1161
|
+
id: "next-global-error",
|
|
1162
|
+
name: "Next.js Global Error",
|
|
1163
|
+
description: "Next.js global error handler",
|
|
1164
|
+
category: "framework",
|
|
1165
|
+
match: (filepath, filename) => filename === "global-error.tsx" || filename === "global-error.js",
|
|
1166
|
+
keywords: ["nextjs", "error", "global", "boundary", "catch"]
|
|
1167
|
+
},
|
|
1168
|
+
{
|
|
1169
|
+
id: "next-pages-api",
|
|
1170
|
+
name: "Next.js API Route (Pages)",
|
|
1171
|
+
description: "Next.js API route (Pages Router)",
|
|
1172
|
+
category: "framework",
|
|
1173
|
+
match: (filepath) => filepath.includes("/pages/api/") || filepath.startsWith("pages/api/"),
|
|
1174
|
+
keywords: ["nextjs", "api", "route", "handler", "endpoint", "pages router"],
|
|
1175
|
+
dynamicKeywords: (filepath) => {
|
|
1176
|
+
const match = filepath.match(/pages\/api\/(.+?)\.(ts|js)/);
|
|
1177
|
+
if (match) {
|
|
1178
|
+
const segments = match[1].split("/").map((s) => s.replace(/^\[(.+?)\]$/, "$1"));
|
|
1179
|
+
return ["api", ...segments.map((s) => s.toLowerCase())];
|
|
1180
|
+
}
|
|
1181
|
+
return ["api"];
|
|
1182
|
+
}
|
|
1183
|
+
},
|
|
1184
|
+
{
|
|
1185
|
+
id: "next-pages-document",
|
|
1186
|
+
name: "Next.js Document",
|
|
1187
|
+
description: "Next.js custom document (Pages Router)",
|
|
1188
|
+
category: "framework",
|
|
1189
|
+
match: (filepath, filename) => (filename === "_document.tsx" || filename === "_document.js") && (filepath.includes("/pages/") || filepath.startsWith("pages/")),
|
|
1190
|
+
keywords: ["nextjs", "document", "html", "head", "body", "pages router"]
|
|
1191
|
+
},
|
|
1192
|
+
{
|
|
1193
|
+
id: "next-pages-app",
|
|
1194
|
+
name: "Next.js App (Pages)",
|
|
1195
|
+
description: "Next.js custom app (Pages Router)",
|
|
1196
|
+
category: "framework",
|
|
1197
|
+
match: (filepath, filename) => (filename === "_app.tsx" || filename === "_app.js") && (filepath.includes("/pages/") || filepath.startsWith("pages/")),
|
|
1198
|
+
keywords: ["nextjs", "app", "wrapper", "provider", "pages router"]
|
|
949
1199
|
}
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
1200
|
+
];
|
|
1201
|
+
nextjsFramework = {
|
|
1202
|
+
id: "nextjs",
|
|
1203
|
+
name: "Next.js",
|
|
1204
|
+
detect: (filepath) => {
|
|
1205
|
+
return filepath === "next.config.js" || filepath === "next.config.mjs" || filepath === "next.config.ts" || filepath.includes("/app/page.") || filepath.includes("/pages/_app.");
|
|
1206
|
+
},
|
|
1207
|
+
conventions: nextjsConventions
|
|
1208
|
+
};
|
|
1209
|
+
});
|
|
1210
|
+
|
|
1211
|
+
// src/introspection/conventions/frameworks/convex.ts
|
|
1212
|
+
var convexConventions, convexFramework;
|
|
1213
|
+
var init_convex = __esm(() => {
|
|
1214
|
+
convexConventions = [
|
|
1215
|
+
{
|
|
1216
|
+
id: "convex-config",
|
|
1217
|
+
name: "Convex Config",
|
|
1218
|
+
description: "Convex project configuration",
|
|
1219
|
+
category: "configuration",
|
|
1220
|
+
match: (filepath, filename) => filename === "convex.json",
|
|
1221
|
+
keywords: ["convex", "config", "backend", "settings"]
|
|
1222
|
+
},
|
|
1223
|
+
{
|
|
1224
|
+
id: "convex-schema",
|
|
1225
|
+
name: "Convex Schema",
|
|
1226
|
+
description: "Convex database schema definition",
|
|
1227
|
+
category: "framework",
|
|
1228
|
+
match: (filepath, filename) => filename === "schema.ts" && (filepath.includes("/convex/") || filepath.startsWith("convex/")),
|
|
1229
|
+
keywords: ["convex", "schema", "database", "tables", "types", "model"]
|
|
1230
|
+
},
|
|
1231
|
+
{
|
|
1232
|
+
id: "convex-function",
|
|
1233
|
+
name: "Convex Function File",
|
|
1234
|
+
description: "Convex backend function file",
|
|
1235
|
+
category: "framework",
|
|
1236
|
+
match: (filepath, filename, extension) => (extension === ".ts" || extension === ".js") && (filepath.includes("/convex/") || filepath.startsWith("convex/")) && !filepath.includes("/_generated/") && filename !== "schema.ts" && !filename.startsWith("_"),
|
|
1237
|
+
keywords: ["convex", "function", "backend", "query", "mutation", "action"],
|
|
1238
|
+
dynamicKeywords: (filepath) => {
|
|
1239
|
+
const match = filepath.match(/convex\/(.+?)\.(ts|js)/);
|
|
1240
|
+
if (match) {
|
|
1241
|
+
const name = match[1].replace(/\//g, " ").split(" ").pop() || "";
|
|
1242
|
+
if (name && !["schema", "http", "crons"].includes(name)) {
|
|
1243
|
+
return [name.toLowerCase()];
|
|
1244
|
+
}
|
|
954
1245
|
}
|
|
955
|
-
|
|
956
|
-
chunks.push({
|
|
957
|
-
content: getNodeText(node),
|
|
958
|
-
startLine,
|
|
959
|
-
endLine,
|
|
960
|
-
type: "variable",
|
|
961
|
-
name,
|
|
962
|
-
isExported: true,
|
|
963
|
-
jsDoc: getJSDoc(node)
|
|
964
|
-
});
|
|
1246
|
+
return [];
|
|
965
1247
|
}
|
|
966
|
-
|
|
1248
|
+
},
|
|
1249
|
+
{
|
|
1250
|
+
id: "convex-http",
|
|
1251
|
+
name: "Convex HTTP Routes",
|
|
1252
|
+
description: "Convex HTTP endpoint definitions",
|
|
1253
|
+
category: "framework",
|
|
1254
|
+
match: (filepath, filename) => filename === "http.ts" && (filepath.includes("/convex/") || filepath.startsWith("convex/")),
|
|
1255
|
+
keywords: ["convex", "http", "routes", "api", "endpoints", "rest"]
|
|
1256
|
+
},
|
|
1257
|
+
{
|
|
1258
|
+
id: "convex-crons",
|
|
1259
|
+
name: "Convex Cron Jobs",
|
|
1260
|
+
description: "Convex scheduled function definitions",
|
|
1261
|
+
category: "framework",
|
|
1262
|
+
match: (filepath, filename) => filename === "crons.ts" && (filepath.includes("/convex/") || filepath.startsWith("convex/")),
|
|
1263
|
+
keywords: [
|
|
1264
|
+
"convex",
|
|
1265
|
+
"crons",
|
|
1266
|
+
"scheduled",
|
|
1267
|
+
"jobs",
|
|
1268
|
+
"background",
|
|
1269
|
+
"recurring"
|
|
1270
|
+
]
|
|
1271
|
+
},
|
|
1272
|
+
{
|
|
1273
|
+
id: "convex-generated",
|
|
1274
|
+
name: "Convex Generated",
|
|
1275
|
+
description: "Convex auto-generated files",
|
|
1276
|
+
category: "framework",
|
|
1277
|
+
match: (filepath) => filepath.includes("/convex/_generated/") || filepath.startsWith("convex/_generated/"),
|
|
1278
|
+
keywords: ["convex", "generated", "types", "api"]
|
|
1279
|
+
},
|
|
1280
|
+
{
|
|
1281
|
+
id: "convex-auth",
|
|
1282
|
+
name: "Convex Auth",
|
|
1283
|
+
description: "Convex authentication configuration",
|
|
1284
|
+
category: "framework",
|
|
1285
|
+
match: (filepath, filename) => filename === "auth.ts" && (filepath.includes("/convex/") || filepath.startsWith("convex/")),
|
|
1286
|
+
keywords: ["convex", "auth", "authentication", "login", "users"]
|
|
1287
|
+
},
|
|
1288
|
+
{
|
|
1289
|
+
id: "convex-auth-config",
|
|
1290
|
+
name: "Convex Auth Config",
|
|
1291
|
+
description: "Convex auth configuration file",
|
|
1292
|
+
category: "configuration",
|
|
1293
|
+
match: (filepath, filename) => filename === "auth.config.ts",
|
|
1294
|
+
keywords: ["convex", "auth", "config", "providers", "oauth"]
|
|
967
1295
|
}
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
1296
|
+
];
|
|
1297
|
+
convexFramework = {
|
|
1298
|
+
id: "convex",
|
|
1299
|
+
name: "Convex",
|
|
1300
|
+
detect: (filepath) => {
|
|
1301
|
+
return filepath === "convex.json" || filepath.startsWith("convex/") || filepath.includes("/convex/");
|
|
1302
|
+
},
|
|
1303
|
+
conventions: convexConventions
|
|
1304
|
+
};
|
|
1305
|
+
});
|
|
1306
|
+
|
|
1307
|
+
// src/introspection/conventions/frameworks/index.ts
|
|
1308
|
+
function getAllFrameworkConventions() {
|
|
1309
|
+
return frameworkProviders.flatMap((f) => f.conventions);
|
|
1310
|
+
}
|
|
1311
|
+
var frameworkProviders;
|
|
1312
|
+
var init_frameworks = __esm(() => {
|
|
1313
|
+
init_nextjs();
|
|
1314
|
+
init_convex();
|
|
1315
|
+
init_nextjs();
|
|
1316
|
+
init_convex();
|
|
1317
|
+
frameworkProviders = [
|
|
1318
|
+
nextjsFramework,
|
|
1319
|
+
convexFramework
|
|
1320
|
+
];
|
|
1321
|
+
});
|
|
1322
|
+
|
|
1323
|
+
// src/introspection/conventions/index.ts
|
|
1324
|
+
import * as path5 from "path";
|
|
1325
|
+
function getAllConventions() {
|
|
1326
|
+
return [
|
|
1327
|
+
...entryPointConventions,
|
|
1328
|
+
...configFileConventions,
|
|
1329
|
+
...getAllFrameworkConventions()
|
|
1330
|
+
];
|
|
975
1331
|
}
|
|
976
|
-
function
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
1332
|
+
function getConventions() {
|
|
1333
|
+
return [
|
|
1334
|
+
...getAllConventions(),
|
|
1335
|
+
...typeDefinitionConventions,
|
|
1336
|
+
...testFileConventions
|
|
1337
|
+
];
|
|
1338
|
+
}
|
|
1339
|
+
function getConventionKeywords(filepath) {
|
|
1340
|
+
const conventions = getConventions();
|
|
1341
|
+
const filename = path5.basename(filepath);
|
|
1342
|
+
const extension = path5.extname(filepath);
|
|
1343
|
+
const keywords = new Set;
|
|
1344
|
+
for (const convention of conventions) {
|
|
1345
|
+
try {
|
|
1346
|
+
if (convention.match(filepath, filename, extension)) {
|
|
1347
|
+
for (const keyword of convention.keywords) {
|
|
1348
|
+
keywords.add(keyword.toLowerCase());
|
|
1349
|
+
}
|
|
1350
|
+
if (convention.dynamicKeywords) {
|
|
1351
|
+
const dynamicKws = convention.dynamicKeywords(filepath);
|
|
1352
|
+
for (const kw of dynamicKws) {
|
|
1353
|
+
if (kw && kw.length > 1) {
|
|
1354
|
+
keywords.add(kw.toLowerCase());
|
|
1355
|
+
}
|
|
1356
|
+
}
|
|
1357
|
+
}
|
|
989
1358
|
}
|
|
990
|
-
|
|
991
|
-
}
|
|
992
|
-
for (let i = 0;i < lines.length; i += CHUNK_SIZE - OVERLAP) {
|
|
993
|
-
const endIdx = Math.min(i + CHUNK_SIZE, lines.length);
|
|
994
|
-
chunks.push({
|
|
995
|
-
content: lines.slice(i, endIdx).join(`
|
|
996
|
-
`),
|
|
997
|
-
startLine: i + 1,
|
|
998
|
-
endLine: endIdx,
|
|
999
|
-
type: "block"
|
|
1000
|
-
});
|
|
1001
|
-
if (endIdx >= lines.length)
|
|
1002
|
-
break;
|
|
1359
|
+
} catch {}
|
|
1003
1360
|
}
|
|
1004
|
-
return
|
|
1361
|
+
return Array.from(keywords);
|
|
1005
1362
|
}
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1363
|
+
var typeDefinitionConventions, testFileConventions;
|
|
1364
|
+
var init_conventions = __esm(() => {
|
|
1365
|
+
init_entryPoints();
|
|
1366
|
+
init_configFiles();
|
|
1367
|
+
init_frameworks();
|
|
1368
|
+
init_entryPoints();
|
|
1369
|
+
init_configFiles();
|
|
1370
|
+
init_frameworks();
|
|
1371
|
+
typeDefinitionConventions = [
|
|
1372
|
+
{
|
|
1373
|
+
id: "dts-file",
|
|
1374
|
+
name: "TypeScript Declaration",
|
|
1375
|
+
description: "TypeScript type declaration file",
|
|
1376
|
+
category: "types",
|
|
1377
|
+
match: (filepath, filename) => filename.endsWith(".d.ts"),
|
|
1378
|
+
keywords: ["types", "declarations", "typescript", "definitions"]
|
|
1379
|
+
},
|
|
1380
|
+
{
|
|
1381
|
+
id: "types-file",
|
|
1382
|
+
name: "Types File",
|
|
1383
|
+
description: "TypeScript types file",
|
|
1384
|
+
category: "types",
|
|
1385
|
+
match: (filepath, filename) => filename.endsWith(".types.ts") || filename === "types.ts",
|
|
1386
|
+
keywords: ["types", "definitions", "typescript", "interfaces"],
|
|
1387
|
+
dynamicKeywords: (filepath) => {
|
|
1388
|
+
const match = filepath.match(/([^/]+)\.types\.ts$/);
|
|
1389
|
+
if (match) {
|
|
1390
|
+
return [match[1].toLowerCase()];
|
|
1391
|
+
}
|
|
1392
|
+
return [];
|
|
1393
|
+
}
|
|
1394
|
+
},
|
|
1395
|
+
{
|
|
1396
|
+
id: "types-folder",
|
|
1397
|
+
name: "Types Folder File",
|
|
1398
|
+
description: "File in a types folder",
|
|
1399
|
+
category: "types",
|
|
1400
|
+
match: (filepath) => filepath.includes("/types/") || filepath.startsWith("types/"),
|
|
1401
|
+
keywords: ["types", "definitions"]
|
|
1402
|
+
}
|
|
1403
|
+
];
|
|
1404
|
+
testFileConventions = [
|
|
1405
|
+
{
|
|
1406
|
+
id: "test-file",
|
|
1407
|
+
name: "Test File",
|
|
1408
|
+
description: "Unit/integration test file",
|
|
1409
|
+
category: "test",
|
|
1410
|
+
match: (filepath, filename) => filename.includes(".test.") || filename.includes(".spec.") || filename.includes("_test."),
|
|
1411
|
+
keywords: ["test", "spec", "unit test"],
|
|
1412
|
+
dynamicKeywords: (filepath) => {
|
|
1413
|
+
const match = filepath.match(/([^/]+)\.(test|spec)\./);
|
|
1414
|
+
if (match) {
|
|
1415
|
+
return [match[1].toLowerCase()];
|
|
1416
|
+
}
|
|
1417
|
+
return [];
|
|
1418
|
+
}
|
|
1419
|
+
},
|
|
1420
|
+
{
|
|
1421
|
+
id: "test-folder",
|
|
1422
|
+
name: "Test Folder File",
|
|
1423
|
+
description: "File in a test folder",
|
|
1424
|
+
category: "test",
|
|
1425
|
+
match: (filepath) => filepath.includes("/__tests__/") || filepath.includes("/test/") || filepath.includes("/tests/") || filepath.startsWith("__tests__/") || filepath.startsWith("test/") || filepath.startsWith("tests/"),
|
|
1426
|
+
keywords: ["test", "testing"]
|
|
1427
|
+
}
|
|
1428
|
+
];
|
|
1429
|
+
});
|
|
1430
|
+
|
|
1431
|
+
// src/introspection/fileIntrospector.ts
|
|
1432
|
+
import * as path6 from "path";
|
|
1433
|
+
function introspectFile(filepath, structure, fileContent) {
|
|
1434
|
+
const normalizedPath = filepath.replace(/\\/g, "/");
|
|
1435
|
+
const segments = normalizedPath.split("/").filter((s) => s.length > 0);
|
|
1436
|
+
const filename = segments[segments.length - 1] || "";
|
|
1437
|
+
const ext = path6.extname(filename);
|
|
1438
|
+
const project = findProjectForFile(normalizedPath, structure);
|
|
1439
|
+
const language = EXTENSION_TO_LANGUAGE[ext] || "unknown";
|
|
1440
|
+
const layer = detectLayer(segments, filename);
|
|
1441
|
+
const domain = detectDomain(segments);
|
|
1442
|
+
const scope = detectScope(segments, project, layer);
|
|
1443
|
+
let framework;
|
|
1444
|
+
if (fileContent) {
|
|
1445
|
+
framework = detectFramework(fileContent);
|
|
1446
|
+
}
|
|
1447
|
+
return {
|
|
1448
|
+
filepath: normalizedPath,
|
|
1449
|
+
project,
|
|
1450
|
+
scope,
|
|
1451
|
+
layer,
|
|
1452
|
+
domain,
|
|
1453
|
+
language,
|
|
1454
|
+
framework,
|
|
1455
|
+
depth: segments.length - 1,
|
|
1456
|
+
pathSegments: segments.slice(0, -1)
|
|
1457
|
+
};
|
|
1009
1458
|
}
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
function extractKeywords(content, name, maxKeywords = 50) {
|
|
1019
|
-
const keywords = new Set;
|
|
1020
|
-
if (name) {
|
|
1021
|
-
keywords.add(name.toLowerCase());
|
|
1022
|
-
const parts = name.split(/(?=[A-Z])/).map((p) => p.toLowerCase());
|
|
1023
|
-
parts.forEach((p) => p.length > 2 && keywords.add(p));
|
|
1459
|
+
function detectLayer(segments, filename) {
|
|
1460
|
+
const filenameLower = filename.toLowerCase();
|
|
1461
|
+
for (const [layer, patterns] of Object.entries(LAYER_PATTERNS)) {
|
|
1462
|
+
for (const pattern of patterns) {
|
|
1463
|
+
if (filenameLower.includes(pattern)) {
|
|
1464
|
+
return layer;
|
|
1465
|
+
}
|
|
1466
|
+
}
|
|
1024
1467
|
}
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1468
|
+
for (let i = segments.length - 2;i >= 0; i--) {
|
|
1469
|
+
const segment = segments[i].toLowerCase();
|
|
1470
|
+
for (const [layer, patterns] of Object.entries(LAYER_PATTERNS)) {
|
|
1471
|
+
if (patterns.includes(segment)) {
|
|
1472
|
+
return layer;
|
|
1473
|
+
}
|
|
1031
1474
|
}
|
|
1032
1475
|
}
|
|
1033
|
-
return
|
|
1034
|
-
}
|
|
1035
|
-
function splitIdentifier(str) {
|
|
1036
|
-
return str.replace(/([a-z])([A-Z])/g, "$1 $2").replace(/[_-]/g, " ").split(/\s+/).map((s) => s.toLowerCase()).filter((s) => s.length > 1);
|
|
1476
|
+
return;
|
|
1037
1477
|
}
|
|
1038
|
-
function
|
|
1039
|
-
const
|
|
1040
|
-
|
|
1041
|
-
|
|
1478
|
+
function detectDomain(segments) {
|
|
1479
|
+
const skipSegments = new Set([
|
|
1480
|
+
"src",
|
|
1481
|
+
"lib",
|
|
1482
|
+
"app",
|
|
1483
|
+
"apps",
|
|
1484
|
+
"packages",
|
|
1485
|
+
"services",
|
|
1486
|
+
"modules",
|
|
1487
|
+
"features",
|
|
1488
|
+
...Object.values(LAYER_PATTERNS).flat()
|
|
1489
|
+
]);
|
|
1042
1490
|
for (const segment of segments) {
|
|
1043
|
-
|
|
1491
|
+
const segmentLower = segment.toLowerCase();
|
|
1492
|
+
if (skipSegments.has(segmentLower))
|
|
1044
1493
|
continue;
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
keywords.add(lower);
|
|
1494
|
+
if (DOMAIN_PATTERNS.includes(segmentLower)) {
|
|
1495
|
+
return segmentLower;
|
|
1048
1496
|
}
|
|
1049
|
-
const
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
keywords.add(part);
|
|
1497
|
+
for (const domain of DOMAIN_PATTERNS) {
|
|
1498
|
+
if (segmentLower.startsWith(domain) || segmentLower.endsWith(domain)) {
|
|
1499
|
+
return domain;
|
|
1053
1500
|
}
|
|
1054
1501
|
}
|
|
1055
1502
|
}
|
|
1056
|
-
return
|
|
1503
|
+
return;
|
|
1057
1504
|
}
|
|
1058
|
-
function
|
|
1059
|
-
const
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
}
|
|
1505
|
+
function detectScope(segments, project, layer) {
|
|
1506
|
+
const projectScope = detectScopeFromName(project.name);
|
|
1507
|
+
if (projectScope !== "unknown") {
|
|
1508
|
+
return projectScope;
|
|
1509
|
+
}
|
|
1510
|
+
if (layer) {
|
|
1511
|
+
switch (layer) {
|
|
1512
|
+
case "controller":
|
|
1513
|
+
case "repository":
|
|
1514
|
+
case "middleware":
|
|
1515
|
+
return "backend";
|
|
1516
|
+
case "presentation":
|
|
1517
|
+
return "frontend";
|
|
1518
|
+
case "util":
|
|
1519
|
+
case "model":
|
|
1520
|
+
return "shared";
|
|
1521
|
+
case "test":
|
|
1522
|
+
return "tooling";
|
|
1077
1523
|
}
|
|
1078
|
-
if (layer)
|
|
1079
|
-
break;
|
|
1080
1524
|
}
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
if (["
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
domain = lower;
|
|
1092
|
-
break;
|
|
1525
|
+
for (const segment of segments) {
|
|
1526
|
+
const segmentLower = segment.toLowerCase();
|
|
1527
|
+
if (["server", "api", "backend"].includes(segmentLower)) {
|
|
1528
|
+
return "backend";
|
|
1529
|
+
}
|
|
1530
|
+
if (["client", "web", "frontend", "ui"].includes(segmentLower)) {
|
|
1531
|
+
return "frontend";
|
|
1532
|
+
}
|
|
1533
|
+
if (["shared", "common", "lib", "libs"].includes(segmentLower)) {
|
|
1534
|
+
return "shared";
|
|
1093
1535
|
}
|
|
1094
1536
|
}
|
|
1095
|
-
return
|
|
1096
|
-
segments: dirSegments,
|
|
1097
|
-
layer,
|
|
1098
|
-
domain,
|
|
1099
|
-
depth: dirSegments.length,
|
|
1100
|
-
keywords
|
|
1101
|
-
};
|
|
1537
|
+
return "unknown";
|
|
1102
1538
|
}
|
|
1103
|
-
function
|
|
1104
|
-
const
|
|
1105
|
-
|
|
1106
|
-
|
|
1539
|
+
function detectFramework(content) {
|
|
1540
|
+
for (const [framework, indicators] of Object.entries(FRAMEWORK_INDICATORS)) {
|
|
1541
|
+
for (const indicator of indicators) {
|
|
1542
|
+
if (content.includes(`from '${indicator}`) || content.includes(`from "${indicator}`) || content.includes(`require('${indicator}`) || content.includes(`require("${indicator}`)) {
|
|
1543
|
+
return framework;
|
|
1544
|
+
}
|
|
1545
|
+
}
|
|
1107
1546
|
}
|
|
1108
|
-
|
|
1109
|
-
|
|
1547
|
+
return;
|
|
1548
|
+
}
|
|
1549
|
+
function introspectionToKeywords(intro) {
|
|
1550
|
+
const keywords = [];
|
|
1551
|
+
const filename = path6.basename(intro.filepath);
|
|
1552
|
+
const filenameWithoutExt = filename.replace(/\.[^.]+$/, "");
|
|
1553
|
+
const filenameParts = filenameWithoutExt.split(/[-_.]/).flatMap((part) => part.split(/(?=[A-Z])/)).map((part) => part.toLowerCase()).filter((part) => part.length > 1);
|
|
1554
|
+
keywords.push(...filenameParts);
|
|
1555
|
+
keywords.push(filenameWithoutExt.toLowerCase());
|
|
1556
|
+
if (intro.project.name && intro.project.name !== "root") {
|
|
1557
|
+
keywords.push(intro.project.name.toLowerCase());
|
|
1110
1558
|
}
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
parts.push(...significantSegments.map((s) => s.toLowerCase()));
|
|
1559
|
+
if (intro.scope !== "unknown") {
|
|
1560
|
+
keywords.push(intro.scope);
|
|
1114
1561
|
}
|
|
1115
|
-
if (
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1562
|
+
if (intro.layer) {
|
|
1563
|
+
keywords.push(intro.layer);
|
|
1564
|
+
}
|
|
1565
|
+
if (intro.domain) {
|
|
1566
|
+
keywords.push(intro.domain);
|
|
1567
|
+
}
|
|
1568
|
+
if (intro.language !== "unknown") {
|
|
1569
|
+
keywords.push(intro.language);
|
|
1570
|
+
}
|
|
1571
|
+
if (intro.framework) {
|
|
1572
|
+
keywords.push(intro.framework);
|
|
1573
|
+
}
|
|
1574
|
+
const skipSegments = new Set(["src", "lib", "index"]);
|
|
1575
|
+
for (const segment of intro.pathSegments) {
|
|
1576
|
+
if (!skipSegments.has(segment.toLowerCase()) && segment.length > 2) {
|
|
1577
|
+
keywords.push(segment.toLowerCase());
|
|
1578
|
+
}
|
|
1579
|
+
}
|
|
1580
|
+
const conventionKeywords = getConventionKeywords(intro.filepath);
|
|
1581
|
+
keywords.push(...conventionKeywords);
|
|
1582
|
+
return [...new Set(keywords)];
|
|
1119
1583
|
}
|
|
1120
|
-
var
|
|
1121
|
-
var
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
"let",
|
|
1125
|
-
"var",
|
|
1126
|
-
"function",
|
|
1127
|
-
"class",
|
|
1128
|
-
"interface",
|
|
1129
|
-
"type",
|
|
1130
|
-
"enum",
|
|
1131
|
-
"export",
|
|
1132
|
-
"import",
|
|
1133
|
-
"from",
|
|
1134
|
-
"return",
|
|
1135
|
-
"async",
|
|
1136
|
-
"await",
|
|
1137
|
-
"new",
|
|
1138
|
-
"this",
|
|
1139
|
-
"true",
|
|
1140
|
-
"false",
|
|
1141
|
-
"null",
|
|
1142
|
-
"undefined",
|
|
1143
|
-
"if",
|
|
1144
|
-
"else",
|
|
1145
|
-
"for",
|
|
1146
|
-
"while",
|
|
1147
|
-
"switch",
|
|
1148
|
-
"case",
|
|
1149
|
-
"break",
|
|
1150
|
-
"continue",
|
|
1151
|
-
"try",
|
|
1152
|
-
"catch",
|
|
1153
|
-
"finally",
|
|
1154
|
-
"throw",
|
|
1155
|
-
"typeof",
|
|
1156
|
-
"instanceof",
|
|
1157
|
-
"void",
|
|
1158
|
-
"delete",
|
|
1159
|
-
"in",
|
|
1160
|
-
"of",
|
|
1161
|
-
"string",
|
|
1162
|
-
"number",
|
|
1163
|
-
"boolean",
|
|
1164
|
-
"any",
|
|
1165
|
-
"unknown",
|
|
1166
|
-
"never",
|
|
1167
|
-
"object",
|
|
1168
|
-
"public",
|
|
1169
|
-
"private",
|
|
1170
|
-
"protected",
|
|
1171
|
-
"static",
|
|
1172
|
-
"readonly",
|
|
1173
|
-
"abstract",
|
|
1174
|
-
"implements",
|
|
1175
|
-
"extends",
|
|
1176
|
-
"super",
|
|
1177
|
-
"get",
|
|
1178
|
-
"set",
|
|
1179
|
-
"constructor",
|
|
1180
|
-
"the",
|
|
1181
|
-
"and",
|
|
1182
|
-
"for",
|
|
1183
|
-
"not",
|
|
1184
|
-
"with",
|
|
1185
|
-
"are",
|
|
1186
|
-
"was",
|
|
1187
|
-
"has",
|
|
1188
|
-
"have"
|
|
1189
|
-
]);
|
|
1584
|
+
var LAYER_PATTERNS, DOMAIN_PATTERNS, FRAMEWORK_INDICATORS, EXTENSION_TO_LANGUAGE;
|
|
1585
|
+
var init_fileIntrospector = __esm(() => {
|
|
1586
|
+
init_projectDetector();
|
|
1587
|
+
init_conventions();
|
|
1190
1588
|
LAYER_PATTERNS = {
|
|
1191
|
-
controller: ["controller", "
|
|
1192
|
-
service: ["service", "
|
|
1193
|
-
repository: ["repository", "
|
|
1194
|
-
model: [
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1589
|
+
controller: ["controller", "api", "routes", "route", "handler"],
|
|
1590
|
+
service: ["service", "logic", "usecase", "usecases", "handler"],
|
|
1591
|
+
repository: ["repository", "repo", "dao", "store", "persistence"],
|
|
1592
|
+
model: [
|
|
1593
|
+
"model",
|
|
1594
|
+
"models",
|
|
1595
|
+
"entity",
|
|
1596
|
+
"entities",
|
|
1597
|
+
"schema",
|
|
1598
|
+
"schemas",
|
|
1599
|
+
"types",
|
|
1600
|
+
"type"
|
|
1601
|
+
],
|
|
1602
|
+
util: ["util", "utils", "helper", "helpers", "common", "lib"],
|
|
1603
|
+
config: ["config", "configuration", "settings"],
|
|
1604
|
+
middleware: ["middleware", "middlewares"],
|
|
1605
|
+
domain: ["domain"],
|
|
1606
|
+
infrastructure: ["infrastructure", "infra"],
|
|
1607
|
+
application: ["application", "app"],
|
|
1608
|
+
presentation: [
|
|
1609
|
+
"presentation",
|
|
1610
|
+
"ui",
|
|
1611
|
+
"views",
|
|
1612
|
+
"view",
|
|
1613
|
+
"component",
|
|
1614
|
+
"components"
|
|
1615
|
+
],
|
|
1616
|
+
test: ["test", "tests", "spec", "specs", "__tests__", "e2e"]
|
|
1617
|
+
};
|
|
1618
|
+
DOMAIN_PATTERNS = [
|
|
1619
|
+
"auth",
|
|
1620
|
+
"authentication",
|
|
1621
|
+
"user",
|
|
1622
|
+
"users",
|
|
1623
|
+
"account",
|
|
1624
|
+
"accounts",
|
|
1625
|
+
"profile",
|
|
1626
|
+
"profiles",
|
|
1627
|
+
"product",
|
|
1628
|
+
"products",
|
|
1629
|
+
"item",
|
|
1630
|
+
"items",
|
|
1631
|
+
"catalog",
|
|
1632
|
+
"order",
|
|
1633
|
+
"orders",
|
|
1634
|
+
"cart",
|
|
1635
|
+
"checkout",
|
|
1636
|
+
"payment",
|
|
1637
|
+
"payments",
|
|
1638
|
+
"billing",
|
|
1639
|
+
"subscription",
|
|
1640
|
+
"subscriptions",
|
|
1641
|
+
"notification",
|
|
1642
|
+
"notifications",
|
|
1643
|
+
"email",
|
|
1644
|
+
"sms",
|
|
1645
|
+
"report",
|
|
1646
|
+
"reports",
|
|
1647
|
+
"analytics",
|
|
1648
|
+
"metrics",
|
|
1649
|
+
"dashboard",
|
|
1650
|
+
"admin",
|
|
1651
|
+
"settings",
|
|
1652
|
+
"search",
|
|
1653
|
+
"chat",
|
|
1654
|
+
"message",
|
|
1655
|
+
"messages",
|
|
1656
|
+
"feed",
|
|
1657
|
+
"post",
|
|
1658
|
+
"posts",
|
|
1659
|
+
"comment",
|
|
1660
|
+
"comments",
|
|
1661
|
+
"media",
|
|
1662
|
+
"upload",
|
|
1663
|
+
"file",
|
|
1664
|
+
"files",
|
|
1665
|
+
"storage",
|
|
1666
|
+
"cache",
|
|
1667
|
+
"session",
|
|
1668
|
+
"log",
|
|
1669
|
+
"logs",
|
|
1670
|
+
"audit"
|
|
1671
|
+
];
|
|
1672
|
+
FRAMEWORK_INDICATORS = {
|
|
1673
|
+
nextjs: ["next", "next/"],
|
|
1674
|
+
express: ["express"],
|
|
1675
|
+
fastify: ["fastify"],
|
|
1676
|
+
react: ["react"],
|
|
1677
|
+
vue: ["vue"],
|
|
1678
|
+
angular: ["@angular/"],
|
|
1679
|
+
nestjs: ["@nestjs/"],
|
|
1680
|
+
koa: ["koa"]
|
|
1681
|
+
};
|
|
1682
|
+
EXTENSION_TO_LANGUAGE = {
|
|
1683
|
+
".ts": "typescript",
|
|
1684
|
+
".tsx": "typescript",
|
|
1685
|
+
".js": "javascript",
|
|
1686
|
+
".jsx": "javascript",
|
|
1687
|
+
".mjs": "javascript",
|
|
1688
|
+
".cjs": "javascript",
|
|
1689
|
+
".py": "python",
|
|
1690
|
+
".go": "go",
|
|
1691
|
+
".rs": "rust",
|
|
1692
|
+
".java": "java",
|
|
1693
|
+
".kt": "kotlin",
|
|
1694
|
+
".swift": "swift",
|
|
1695
|
+
".rb": "ruby",
|
|
1696
|
+
".php": "php",
|
|
1697
|
+
".cs": "csharp",
|
|
1698
|
+
".cpp": "cpp",
|
|
1699
|
+
".c": "c",
|
|
1700
|
+
".h": "c",
|
|
1701
|
+
".hpp": "cpp",
|
|
1702
|
+
".md": "markdown",
|
|
1703
|
+
".json": "json",
|
|
1704
|
+
".yaml": "yaml",
|
|
1705
|
+
".yml": "yaml"
|
|
1202
1706
|
};
|
|
1203
1707
|
});
|
|
1204
1708
|
|
|
1205
|
-
// src/
|
|
1709
|
+
// src/introspection/index.ts
|
|
1710
|
+
import * as path7 from "path";
|
|
1206
1711
|
import * as fs3 from "fs/promises";
|
|
1207
|
-
import * as path4 from "path";
|
|
1208
1712
|
|
|
1209
|
-
class
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
this.symbolicPath = path4.join(indexDir, "index", moduleId, "symbolic");
|
|
1217
|
-
this.moduleId = moduleId;
|
|
1713
|
+
class IntrospectionIndex {
|
|
1714
|
+
rootDir;
|
|
1715
|
+
structure = null;
|
|
1716
|
+
files = new Map;
|
|
1717
|
+
config = {};
|
|
1718
|
+
constructor(rootDir) {
|
|
1719
|
+
this.rootDir = rootDir;
|
|
1218
1720
|
}
|
|
1219
1721
|
async initialize() {
|
|
1722
|
+
this.structure = await detectProjectStructure(this.rootDir);
|
|
1220
1723
|
try {
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
moduleId: this.moduleId,
|
|
1227
|
-
fileCount: 0,
|
|
1228
|
-
bm25Data: {
|
|
1229
|
-
avgDocLength: 0,
|
|
1230
|
-
documentFrequencies: {},
|
|
1231
|
-
totalDocs: 0
|
|
1232
|
-
}
|
|
1233
|
-
};
|
|
1234
|
-
this.bm25Index = new BM25Index;
|
|
1235
|
-
}
|
|
1236
|
-
}
|
|
1237
|
-
addFile(summary) {
|
|
1238
|
-
this.fileSummaries.set(summary.filepath, summary);
|
|
1724
|
+
const configPath = path7.join(this.rootDir, ".raggrep", "config.json");
|
|
1725
|
+
const configContent = await fs3.readFile(configPath, "utf-8");
|
|
1726
|
+
const config = JSON.parse(configContent);
|
|
1727
|
+
this.config = config.introspection || {};
|
|
1728
|
+
} catch {}
|
|
1239
1729
|
}
|
|
1240
|
-
|
|
1241
|
-
return this.
|
|
1730
|
+
getStructure() {
|
|
1731
|
+
return this.structure;
|
|
1242
1732
|
}
|
|
1243
|
-
|
|
1244
|
-
this.
|
|
1245
|
-
|
|
1246
|
-
const content = [
|
|
1247
|
-
...summary.keywords,
|
|
1248
|
-
...summary.exports,
|
|
1249
|
-
...extractPathKeywords(filepath)
|
|
1250
|
-
].join(" ");
|
|
1251
|
-
this.bm25Index.addDocuments([{ id: filepath, content }]);
|
|
1252
|
-
}
|
|
1253
|
-
if (this.meta) {
|
|
1254
|
-
this.meta.fileCount = this.fileSummaries.size;
|
|
1255
|
-
this.meta.bm25Data.totalDocs = this.fileSummaries.size;
|
|
1733
|
+
addFile(filepath, content) {
|
|
1734
|
+
if (!this.structure) {
|
|
1735
|
+
throw new Error("IntrospectionIndex not initialized");
|
|
1256
1736
|
}
|
|
1737
|
+
const intro = introspectFile(filepath, this.structure, content);
|
|
1738
|
+
this.applyOverrides(intro);
|
|
1739
|
+
this.files.set(filepath, intro);
|
|
1740
|
+
return intro;
|
|
1257
1741
|
}
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
return Array.from(this.fileSummaries.keys());
|
|
1261
|
-
}
|
|
1262
|
-
const results = this.bm25Index.search(query, maxCandidates);
|
|
1263
|
-
return results.map((r) => r.id);
|
|
1742
|
+
getFile(filepath) {
|
|
1743
|
+
return this.files.get(filepath);
|
|
1264
1744
|
}
|
|
1265
1745
|
getAllFiles() {
|
|
1266
|
-
return Array.from(this.
|
|
1746
|
+
return Array.from(this.files.values());
|
|
1267
1747
|
}
|
|
1268
|
-
|
|
1269
|
-
|
|
1748
|
+
applyOverrides(intro) {
|
|
1749
|
+
if (!this.config.projects)
|
|
1750
|
+
return;
|
|
1751
|
+
for (const [projectPath, overrides] of Object.entries(this.config.projects)) {
|
|
1752
|
+
if (intro.filepath.startsWith(projectPath + "/") || intro.project.root === projectPath) {
|
|
1753
|
+
if (overrides.scope) {
|
|
1754
|
+
intro.scope = overrides.scope;
|
|
1755
|
+
}
|
|
1756
|
+
if (overrides.framework) {
|
|
1757
|
+
intro.framework = overrides.framework;
|
|
1758
|
+
}
|
|
1759
|
+
break;
|
|
1760
|
+
}
|
|
1761
|
+
}
|
|
1270
1762
|
}
|
|
1271
|
-
async save() {
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
await fs3.
|
|
1763
|
+
async save(config) {
|
|
1764
|
+
const introDir = path7.join(getRaggrepDir(this.rootDir, config), "introspection");
|
|
1765
|
+
await fs3.mkdir(introDir, { recursive: true });
|
|
1766
|
+
const projectPath = path7.join(introDir, "_project.json");
|
|
1767
|
+
await fs3.writeFile(projectPath, JSON.stringify({
|
|
1768
|
+
version: "1.0.0",
|
|
1769
|
+
lastUpdated: new Date().toISOString(),
|
|
1770
|
+
structure: this.structure
|
|
1771
|
+
}, null, 2));
|
|
1772
|
+
for (const [filepath, intro] of this.files) {
|
|
1773
|
+
const introFilePath = path7.join(introDir, "files", filepath.replace(/\.[^.]+$/, ".json"));
|
|
1774
|
+
await fs3.mkdir(path7.dirname(introFilePath), { recursive: true });
|
|
1775
|
+
await fs3.writeFile(introFilePath, JSON.stringify(intro, null, 2));
|
|
1283
1776
|
}
|
|
1777
|
+
console.log(` [Introspection] Saved metadata for ${this.files.size} files`);
|
|
1284
1778
|
}
|
|
1285
|
-
async load() {
|
|
1286
|
-
const
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
|
|
1779
|
+
async load(config) {
|
|
1780
|
+
const introDir = path7.join(getRaggrepDir(this.rootDir, config), "introspection");
|
|
1781
|
+
try {
|
|
1782
|
+
const projectPath = path7.join(introDir, "_project.json");
|
|
1783
|
+
const projectContent = await fs3.readFile(projectPath, "utf-8");
|
|
1784
|
+
const projectData = JSON.parse(projectContent);
|
|
1785
|
+
this.structure = projectData.structure;
|
|
1786
|
+
await this.loadFilesRecursive(path7.join(introDir, "files"), "");
|
|
1787
|
+
} catch {
|
|
1788
|
+
this.structure = null;
|
|
1789
|
+
this.files.clear();
|
|
1790
|
+
}
|
|
1292
1791
|
}
|
|
1293
|
-
async
|
|
1792
|
+
async loadFilesRecursive(basePath, prefix) {
|
|
1294
1793
|
try {
|
|
1295
|
-
const entries = await fs3.readdir(
|
|
1794
|
+
const entries = await fs3.readdir(basePath, { withFileTypes: true });
|
|
1296
1795
|
for (const entry of entries) {
|
|
1297
|
-
const
|
|
1796
|
+
const entryPath = path7.join(basePath, entry.name);
|
|
1797
|
+
const relativePath = prefix ? `${prefix}/${entry.name}` : entry.name;
|
|
1298
1798
|
if (entry.isDirectory()) {
|
|
1299
|
-
await this.
|
|
1300
|
-
} else if (entry.name.endsWith(".json")
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
if (summary.filepath) {
|
|
1305
|
-
this.fileSummaries.set(summary.filepath, summary);
|
|
1306
|
-
}
|
|
1307
|
-
} catch {}
|
|
1799
|
+
await this.loadFilesRecursive(entryPath, relativePath);
|
|
1800
|
+
} else if (entry.name.endsWith(".json")) {
|
|
1801
|
+
const content = await fs3.readFile(entryPath, "utf-8");
|
|
1802
|
+
const intro = JSON.parse(content);
|
|
1803
|
+
this.files.set(intro.filepath, intro);
|
|
1308
1804
|
}
|
|
1309
1805
|
}
|
|
1310
1806
|
} catch {}
|
|
1311
1807
|
}
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
|
|
1315
|
-
}
|
|
1316
|
-
async deleteFileSummary(filepath) {
|
|
1317
|
-
try {
|
|
1318
|
-
await fs3.unlink(this.getFileSummaryPath(filepath));
|
|
1319
|
-
} catch {}
|
|
1320
|
-
this.fileSummaries.delete(filepath);
|
|
1808
|
+
clear() {
|
|
1809
|
+
this.files.clear();
|
|
1810
|
+
this.structure = null;
|
|
1321
1811
|
}
|
|
1322
|
-
|
|
1323
|
-
|
|
1324
|
-
|
|
1325
|
-
|
|
1326
|
-
|
|
1327
|
-
|
|
1328
|
-
|
|
1812
|
+
}
|
|
1813
|
+
var init_introspection = __esm(() => {
|
|
1814
|
+
init_projectDetector();
|
|
1815
|
+
init_fileIntrospector();
|
|
1816
|
+
init_config2();
|
|
1817
|
+
init_fileIntrospector();
|
|
1818
|
+
init_projectDetector();
|
|
1819
|
+
});
|
|
1820
|
+
|
|
1821
|
+
// src/modules/core/symbols.ts
|
|
1822
|
+
function extractSymbols(content) {
|
|
1823
|
+
const symbols = [];
|
|
1824
|
+
const seenSymbols = new Set;
|
|
1825
|
+
const lines = content.split(`
|
|
1826
|
+
`);
|
|
1827
|
+
for (const { type, pattern, exported } of SYMBOL_PATTERNS) {
|
|
1828
|
+
pattern.lastIndex = 0;
|
|
1829
|
+
let match;
|
|
1830
|
+
while ((match = pattern.exec(content)) !== null) {
|
|
1831
|
+
const name = match[1];
|
|
1832
|
+
const symbolKey = `${name}:${type}`;
|
|
1833
|
+
if (seenSymbols.has(symbolKey))
|
|
1834
|
+
continue;
|
|
1835
|
+
seenSymbols.add(symbolKey);
|
|
1836
|
+
const beforeMatch = content.substring(0, match.index);
|
|
1837
|
+
const line = beforeMatch.split(`
|
|
1838
|
+
`).length;
|
|
1839
|
+
symbols.push({
|
|
1840
|
+
name,
|
|
1841
|
+
type,
|
|
1842
|
+
line,
|
|
1843
|
+
isExported: exported
|
|
1844
|
+
});
|
|
1329
1845
|
}
|
|
1330
1846
|
}
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
|
|
1336
|
-
|
|
1337
|
-
|
|
1338
|
-
|
|
1339
|
-
|
|
1340
|
-
|
|
1341
|
-
|
|
1342
|
-
};
|
|
1847
|
+
return symbols.sort((a, b) => a.line - b.line);
|
|
1848
|
+
}
|
|
1849
|
+
function symbolsToKeywords(symbols) {
|
|
1850
|
+
const keywords = new Set;
|
|
1851
|
+
for (const symbol of symbols) {
|
|
1852
|
+
keywords.add(symbol.name.toLowerCase());
|
|
1853
|
+
const parts = symbol.name.replace(/([a-z])([A-Z])/g, "$1 $2").replace(/([A-Z]+)([A-Z][a-z])/g, "$1 $2").toLowerCase().split(/\s+/);
|
|
1854
|
+
for (const part of parts) {
|
|
1855
|
+
if (part.length > 2) {
|
|
1856
|
+
keywords.add(part);
|
|
1857
|
+
}
|
|
1343
1858
|
}
|
|
1344
|
-
this.bm25Index = new BM25Index;
|
|
1345
1859
|
}
|
|
1860
|
+
return Array.from(keywords);
|
|
1346
1861
|
}
|
|
1347
|
-
var
|
|
1348
|
-
|
|
1349
|
-
|
|
1350
|
-
|
|
1351
|
-
|
|
1352
|
-
|
|
1353
|
-
|
|
1354
|
-
|
|
1862
|
+
var SYMBOL_PATTERNS;
|
|
1863
|
+
var init_symbols = __esm(() => {
|
|
1864
|
+
SYMBOL_PATTERNS = [
|
|
1865
|
+
{
|
|
1866
|
+
type: "function",
|
|
1867
|
+
pattern: /^export\s+(?:async\s+)?function\s+(\w+)/gm,
|
|
1868
|
+
exported: true
|
|
1869
|
+
},
|
|
1870
|
+
{
|
|
1871
|
+
type: "function",
|
|
1872
|
+
pattern: /^export\s+(?:const|let)\s+(\w+)\s*=\s*(?:async\s*)?\(/gm,
|
|
1873
|
+
exported: true
|
|
1874
|
+
},
|
|
1875
|
+
{
|
|
1876
|
+
type: "class",
|
|
1877
|
+
pattern: /^export\s+(?:abstract\s+)?class\s+(\w+)/gm,
|
|
1878
|
+
exported: true
|
|
1879
|
+
},
|
|
1880
|
+
{
|
|
1881
|
+
type: "interface",
|
|
1882
|
+
pattern: /^export\s+interface\s+(\w+)/gm,
|
|
1883
|
+
exported: true
|
|
1884
|
+
},
|
|
1885
|
+
{
|
|
1886
|
+
type: "type",
|
|
1887
|
+
pattern: /^export\s+type\s+(\w+)/gm,
|
|
1888
|
+
exported: true
|
|
1889
|
+
},
|
|
1890
|
+
{
|
|
1891
|
+
type: "enum",
|
|
1892
|
+
pattern: /^export\s+(?:const\s+)?enum\s+(\w+)/gm,
|
|
1893
|
+
exported: true
|
|
1894
|
+
},
|
|
1895
|
+
{
|
|
1896
|
+
type: "variable",
|
|
1897
|
+
pattern: /^export\s+(?:const|let|var)\s+(\w+)\s*(?::|=)/gm,
|
|
1898
|
+
exported: true
|
|
1899
|
+
},
|
|
1900
|
+
{
|
|
1901
|
+
type: "function",
|
|
1902
|
+
pattern: /^export\s+default\s+(?:async\s+)?function\s+(\w+)/gm,
|
|
1903
|
+
exported: true
|
|
1904
|
+
},
|
|
1905
|
+
{
|
|
1906
|
+
type: "class",
|
|
1907
|
+
pattern: /^export\s+default\s+class\s+(\w+)/gm,
|
|
1908
|
+
exported: true
|
|
1909
|
+
},
|
|
1910
|
+
{
|
|
1911
|
+
type: "function",
|
|
1912
|
+
pattern: /^(?:async\s+)?function\s+(\w+)/gm,
|
|
1913
|
+
exported: false
|
|
1914
|
+
},
|
|
1915
|
+
{
|
|
1916
|
+
type: "function",
|
|
1917
|
+
pattern: /^(?:const|let)\s+(\w+)\s*=\s*(?:async\s*)?\(/gm,
|
|
1918
|
+
exported: false
|
|
1919
|
+
},
|
|
1920
|
+
{
|
|
1921
|
+
type: "class",
|
|
1922
|
+
pattern: /^(?:abstract\s+)?class\s+(\w+)/gm,
|
|
1923
|
+
exported: false
|
|
1924
|
+
},
|
|
1925
|
+
{
|
|
1926
|
+
type: "interface",
|
|
1927
|
+
pattern: /^interface\s+(\w+)/gm,
|
|
1928
|
+
exported: false
|
|
1929
|
+
},
|
|
1930
|
+
{
|
|
1931
|
+
type: "type",
|
|
1932
|
+
pattern: /^type\s+(\w+)/gm,
|
|
1933
|
+
exported: false
|
|
1934
|
+
},
|
|
1935
|
+
{
|
|
1936
|
+
type: "enum",
|
|
1937
|
+
pattern: /^(?:const\s+)?enum\s+(\w+)/gm,
|
|
1938
|
+
exported: false
|
|
1939
|
+
},
|
|
1940
|
+
{
|
|
1941
|
+
type: "function",
|
|
1942
|
+
pattern: /^def\s+(\w+)\s*\(/gm,
|
|
1943
|
+
exported: false
|
|
1944
|
+
},
|
|
1945
|
+
{
|
|
1946
|
+
type: "class",
|
|
1947
|
+
pattern: /^class\s+(\w+)(?:\s*\(|:)/gm,
|
|
1948
|
+
exported: false
|
|
1949
|
+
},
|
|
1950
|
+
{
|
|
1951
|
+
type: "function",
|
|
1952
|
+
pattern: /^func\s+(?:\([^)]+\)\s+)?(\w+)\s*\(/gm,
|
|
1953
|
+
exported: false
|
|
1954
|
+
},
|
|
1955
|
+
{
|
|
1956
|
+
type: "type",
|
|
1957
|
+
pattern: /^type\s+(\w+)\s+(?:struct|interface)/gm,
|
|
1958
|
+
exported: false
|
|
1959
|
+
},
|
|
1960
|
+
{
|
|
1961
|
+
type: "function",
|
|
1962
|
+
pattern: /^(?:pub\s+)?(?:async\s+)?fn\s+(\w+)/gm,
|
|
1963
|
+
exported: false
|
|
1964
|
+
},
|
|
1965
|
+
{
|
|
1966
|
+
type: "type",
|
|
1967
|
+
pattern: /^(?:pub\s+)?struct\s+(\w+)/gm,
|
|
1968
|
+
exported: false
|
|
1969
|
+
},
|
|
1970
|
+
{
|
|
1971
|
+
type: "enum",
|
|
1972
|
+
pattern: /^(?:pub\s+)?enum\s+(\w+)/gm,
|
|
1973
|
+
exported: false
|
|
1974
|
+
},
|
|
1975
|
+
{
|
|
1976
|
+
type: "interface",
|
|
1977
|
+
pattern: /^(?:pub\s+)?trait\s+(\w+)/gm,
|
|
1978
|
+
exported: false
|
|
1979
|
+
}
|
|
1980
|
+
];
|
|
1355
1981
|
});
|
|
1356
1982
|
|
|
1357
|
-
// src/modules/
|
|
1358
|
-
var
|
|
1359
|
-
__export(
|
|
1360
|
-
|
|
1361
|
-
DEFAULT_TOP_K: () => DEFAULT_TOP_K2,
|
|
1362
|
-
DEFAULT_MIN_SCORE: () => DEFAULT_MIN_SCORE2
|
|
1983
|
+
// src/modules/core/index.ts
|
|
1984
|
+
var exports_core = {};
|
|
1985
|
+
__export(exports_core, {
|
|
1986
|
+
CoreModule: () => CoreModule
|
|
1363
1987
|
});
|
|
1364
|
-
import * as
|
|
1988
|
+
import * as path8 from "path";
|
|
1989
|
+
import * as fs4 from "fs/promises";
|
|
1365
1990
|
|
|
1366
|
-
class
|
|
1367
|
-
id = "
|
|
1368
|
-
name = "
|
|
1369
|
-
description = "
|
|
1991
|
+
class CoreModule {
|
|
1992
|
+
id = "core";
|
|
1993
|
+
name = "Core Search";
|
|
1994
|
+
description = "Language-agnostic text search with symbol extraction";
|
|
1370
1995
|
version = "1.0.0";
|
|
1371
|
-
|
|
1372
|
-
|
|
1373
|
-
pendingSummaries = new Map;
|
|
1996
|
+
symbolIndex = new Map;
|
|
1997
|
+
bm25Index = null;
|
|
1374
1998
|
rootDir = "";
|
|
1375
|
-
async initialize(
|
|
1376
|
-
this.embeddingConfig = getEmbeddingConfigFromModule(config);
|
|
1377
|
-
configureEmbeddings(this.embeddingConfig);
|
|
1378
|
-
this.pendingSummaries.clear();
|
|
1379
|
-
}
|
|
1999
|
+
async initialize(_config) {}
|
|
1380
2000
|
async indexFile(filepath, content, ctx) {
|
|
1381
2001
|
this.rootDir = ctx.rootDir;
|
|
1382
|
-
const
|
|
1383
|
-
|
|
1384
|
-
|
|
1385
|
-
|
|
1386
|
-
const
|
|
1387
|
-
const
|
|
1388
|
-
const
|
|
1389
|
-
|
|
1390
|
-
|
|
1391
|
-
|
|
1392
|
-
|
|
1393
|
-
|
|
1394
|
-
|
|
1395
|
-
|
|
1396
|
-
|
|
1397
|
-
|
|
1398
|
-
type: pc.type,
|
|
1399
|
-
name: pc.name,
|
|
1400
|
-
isExported: pc.isExported,
|
|
1401
|
-
jsDoc: pc.jsDoc
|
|
1402
|
-
}));
|
|
1403
|
-
const references = this.extractReferences(content, filepath);
|
|
1404
|
-
const stats = await ctx.getFileStats(filepath);
|
|
1405
|
-
const currentConfig = getEmbeddingConfig();
|
|
1406
|
-
const moduleData = {
|
|
1407
|
-
embeddings,
|
|
1408
|
-
embeddingModel: currentConfig.model
|
|
1409
|
-
};
|
|
1410
|
-
const chunkTypes = [...new Set(parsedChunks.map((pc) => pc.type))];
|
|
1411
|
-
const exports = parsedChunks.filter((pc) => pc.isExported && pc.name).map((pc) => pc.name);
|
|
1412
|
-
const allKeywords = new Set;
|
|
1413
|
-
for (const pc of parsedChunks) {
|
|
1414
|
-
const keywords = extractKeywords(pc.content, pc.name);
|
|
1415
|
-
keywords.forEach((k) => allKeywords.add(k));
|
|
1416
|
-
}
|
|
1417
|
-
pathContext.keywords.forEach((k) => allKeywords.add(k));
|
|
1418
|
-
const fileSummary = {
|
|
1419
|
-
filepath,
|
|
1420
|
-
chunkCount: chunks.length,
|
|
1421
|
-
chunkTypes,
|
|
1422
|
-
keywords: Array.from(allKeywords),
|
|
1423
|
-
exports,
|
|
1424
|
-
lastModified: stats.lastModified,
|
|
1425
|
-
pathContext: {
|
|
1426
|
-
segments: pathContext.segments,
|
|
1427
|
-
layer: pathContext.layer,
|
|
1428
|
-
domain: pathContext.domain,
|
|
1429
|
-
depth: pathContext.depth
|
|
1430
|
-
}
|
|
2002
|
+
const symbols = extractSymbols(content);
|
|
2003
|
+
const symbolKeywords = symbolsToKeywords(symbols);
|
|
2004
|
+
const contentTokens = tokenize(content);
|
|
2005
|
+
const intro = ctx.getIntrospection?.(filepath);
|
|
2006
|
+
const introKeywords = intro ? introspectionToKeywords(intro) : [];
|
|
2007
|
+
const allTokens = [...new Set([...contentTokens, ...symbolKeywords, ...introKeywords])];
|
|
2008
|
+
const chunks = this.createChunks(filepath, content, symbols);
|
|
2009
|
+
const stats = await ctx.getFileStats(filepath);
|
|
2010
|
+
this.symbolIndex.set(filepath, {
|
|
2011
|
+
filepath,
|
|
2012
|
+
symbols,
|
|
2013
|
+
tokens: allTokens
|
|
2014
|
+
});
|
|
2015
|
+
const moduleData = {
|
|
2016
|
+
symbols,
|
|
2017
|
+
tokens: allTokens
|
|
1431
2018
|
};
|
|
1432
|
-
this.pendingSummaries.set(filepath, fileSummary);
|
|
1433
2019
|
return {
|
|
1434
2020
|
filepath,
|
|
1435
2021
|
lastModified: stats.lastModified,
|
|
1436
2022
|
chunks,
|
|
1437
|
-
moduleData
|
|
1438
|
-
references
|
|
2023
|
+
moduleData
|
|
1439
2024
|
};
|
|
1440
2025
|
}
|
|
1441
|
-
|
|
1442
|
-
const
|
|
1443
|
-
|
|
1444
|
-
|
|
1445
|
-
for (
|
|
1446
|
-
|
|
1447
|
-
|
|
1448
|
-
|
|
1449
|
-
|
|
1450
|
-
|
|
1451
|
-
|
|
1452
|
-
|
|
1453
|
-
|
|
1454
|
-
|
|
1455
|
-
|
|
1456
|
-
|
|
1457
|
-
|
|
1458
|
-
|
|
1459
|
-
await symbolicIndex.initialize();
|
|
1460
|
-
const maxCandidates = topK * TIER1_CANDIDATE_MULTIPLIER;
|
|
1461
|
-
candidateFiles = symbolicIndex.findCandidates(query, maxCandidates);
|
|
1462
|
-
if (candidateFiles.length === 0) {
|
|
1463
|
-
candidateFiles = symbolicIndex.getAllFiles();
|
|
2026
|
+
createChunks(filepath, content, symbols) {
|
|
2027
|
+
const lines = content.split(`
|
|
2028
|
+
`);
|
|
2029
|
+
const chunks = [];
|
|
2030
|
+
for (let start = 0;start < lines.length; start += LINES_PER_CHUNK - CHUNK_OVERLAP) {
|
|
2031
|
+
const end = Math.min(start + LINES_PER_CHUNK, lines.length);
|
|
2032
|
+
const chunkLines = lines.slice(start, end);
|
|
2033
|
+
const chunkContent = chunkLines.join(`
|
|
2034
|
+
`);
|
|
2035
|
+
const chunkSymbols = symbols.filter((s) => s.line >= start + 1 && s.line <= end);
|
|
2036
|
+
let chunkType = "block";
|
|
2037
|
+
let chunkName;
|
|
2038
|
+
let isExported = false;
|
|
2039
|
+
if (chunkSymbols.length > 0) {
|
|
2040
|
+
const primarySymbol = chunkSymbols[0];
|
|
2041
|
+
chunkType = this.symbolTypeToChunkType(primarySymbol.type);
|
|
2042
|
+
chunkName = primarySymbol.name;
|
|
2043
|
+
isExported = primarySymbol.isExported;
|
|
1464
2044
|
}
|
|
1465
|
-
|
|
1466
|
-
|
|
1467
|
-
|
|
1468
|
-
|
|
1469
|
-
|
|
1470
|
-
|
|
1471
|
-
|
|
1472
|
-
|
|
1473
|
-
|
|
1474
|
-
}
|
|
1475
|
-
return filepath.includes(pattern);
|
|
1476
|
-
});
|
|
2045
|
+
const chunkId = `${filepath}:${start + 1}-${end}`;
|
|
2046
|
+
chunks.push({
|
|
2047
|
+
id: chunkId,
|
|
2048
|
+
content: chunkContent,
|
|
2049
|
+
startLine: start + 1,
|
|
2050
|
+
endLine: end,
|
|
2051
|
+
type: chunkType,
|
|
2052
|
+
name: chunkName,
|
|
2053
|
+
isExported
|
|
1477
2054
|
});
|
|
2055
|
+
if (end >= lines.length)
|
|
2056
|
+
break;
|
|
1478
2057
|
}
|
|
1479
|
-
|
|
1480
|
-
|
|
1481
|
-
|
|
1482
|
-
|
|
1483
|
-
|
|
1484
|
-
|
|
1485
|
-
|
|
1486
|
-
|
|
1487
|
-
|
|
1488
|
-
|
|
1489
|
-
|
|
1490
|
-
|
|
1491
|
-
|
|
1492
|
-
|
|
1493
|
-
|
|
1494
|
-
|
|
1495
|
-
|
|
1496
|
-
|
|
1497
|
-
|
|
1498
|
-
});
|
|
1499
|
-
bm25Index.addDocuments([{ id: chunk.id, content: chunk.content }]);
|
|
1500
|
-
}
|
|
2058
|
+
return chunks;
|
|
2059
|
+
}
|
|
2060
|
+
symbolTypeToChunkType(symbolType) {
|
|
2061
|
+
switch (symbolType) {
|
|
2062
|
+
case "function":
|
|
2063
|
+
case "method":
|
|
2064
|
+
return "function";
|
|
2065
|
+
case "class":
|
|
2066
|
+
return "class";
|
|
2067
|
+
case "interface":
|
|
2068
|
+
return "interface";
|
|
2069
|
+
case "type":
|
|
2070
|
+
return "type";
|
|
2071
|
+
case "enum":
|
|
2072
|
+
return "enum";
|
|
2073
|
+
case "variable":
|
|
2074
|
+
return "variable";
|
|
2075
|
+
default:
|
|
2076
|
+
return "block";
|
|
1501
2077
|
}
|
|
1502
|
-
|
|
1503
|
-
|
|
1504
|
-
|
|
1505
|
-
|
|
2078
|
+
}
|
|
2079
|
+
async finalize(ctx) {
|
|
2080
|
+
const config = ctx.config;
|
|
2081
|
+
const coreDir = path8.join(getRaggrepDir(ctx.rootDir, config), "index", "core");
|
|
2082
|
+
await fs4.mkdir(coreDir, { recursive: true });
|
|
2083
|
+
this.bm25Index = new BM25Index;
|
|
2084
|
+
for (const [filepath, entry] of this.symbolIndex) {
|
|
2085
|
+
this.bm25Index.addDocument(filepath, entry.tokens);
|
|
1506
2086
|
}
|
|
1507
|
-
const
|
|
1508
|
-
|
|
1509
|
-
|
|
1510
|
-
|
|
1511
|
-
|
|
1512
|
-
|
|
1513
|
-
|
|
1514
|
-
|
|
1515
|
-
|
|
1516
|
-
|
|
1517
|
-
|
|
1518
|
-
|
|
1519
|
-
|
|
1520
|
-
|
|
1521
|
-
|
|
1522
|
-
|
|
1523
|
-
|
|
1524
|
-
|
|
1525
|
-
}
|
|
2087
|
+
const symbolIndexData = {
|
|
2088
|
+
version: this.version,
|
|
2089
|
+
lastUpdated: new Date().toISOString(),
|
|
2090
|
+
files: Object.fromEntries(this.symbolIndex),
|
|
2091
|
+
bm25Data: this.bm25Index.serialize()
|
|
2092
|
+
};
|
|
2093
|
+
await fs4.writeFile(path8.join(coreDir, "symbols.json"), JSON.stringify(symbolIndexData, null, 2));
|
|
2094
|
+
console.log(` [Core] Symbol index built with ${this.symbolIndex.size} files`);
|
|
2095
|
+
}
|
|
2096
|
+
async search(query, ctx, options) {
|
|
2097
|
+
const config = ctx.config;
|
|
2098
|
+
const topK = options?.topK ?? DEFAULT_TOP_K;
|
|
2099
|
+
const minScore = options?.minScore ?? DEFAULT_MIN_SCORE;
|
|
2100
|
+
if (this.symbolIndex.size === 0) {
|
|
2101
|
+
await this.loadSymbolIndex(ctx.rootDir, config);
|
|
2102
|
+
}
|
|
2103
|
+
if (!this.bm25Index || this.symbolIndex.size === 0) {
|
|
2104
|
+
return [];
|
|
1526
2105
|
}
|
|
2106
|
+
const queryTokens = tokenize(query);
|
|
2107
|
+
const bm25Results = this.bm25Index.search(query, topK * 2);
|
|
2108
|
+
const bm25Scores = new Map(bm25Results.map((r) => [r.id, r.score]));
|
|
2109
|
+
const symbolMatches = this.findSymbolMatches(queryTokens);
|
|
1527
2110
|
const results = [];
|
|
1528
|
-
for (const
|
|
1529
|
-
const
|
|
1530
|
-
const bm25Score = bm25Scores.get(
|
|
1531
|
-
const
|
|
1532
|
-
|
|
1533
|
-
|
|
2111
|
+
for (const filepath of this.symbolIndex.keys()) {
|
|
2112
|
+
const entry = this.symbolIndex.get(filepath);
|
|
2113
|
+
const bm25Score = bm25Scores.get(filepath) ?? 0;
|
|
2114
|
+
const symbolScore = symbolMatches.get(filepath) ?? 0;
|
|
2115
|
+
if (bm25Score === 0 && symbolScore === 0)
|
|
2116
|
+
continue;
|
|
2117
|
+
const combinedScore = 0.6 * normalizeScore(bm25Score) + 0.4 * symbolScore;
|
|
2118
|
+
if (combinedScore >= minScore) {
|
|
2119
|
+
const fileIndex = await ctx.loadFileIndex(filepath);
|
|
2120
|
+
if (!fileIndex)
|
|
2121
|
+
continue;
|
|
2122
|
+
const bestChunk = this.findBestChunk(fileIndex.chunks, queryTokens, entry.symbols);
|
|
1534
2123
|
results.push({
|
|
1535
2124
|
filepath,
|
|
1536
|
-
chunk,
|
|
1537
|
-
score:
|
|
2125
|
+
chunk: bestChunk,
|
|
2126
|
+
score: combinedScore,
|
|
1538
2127
|
moduleId: this.id,
|
|
1539
2128
|
context: {
|
|
1540
|
-
|
|
1541
|
-
|
|
1542
|
-
pathBoost
|
|
2129
|
+
bm25Score: normalizeScore(bm25Score),
|
|
2130
|
+
symbolScore
|
|
1543
2131
|
}
|
|
1544
2132
|
});
|
|
1545
2133
|
}
|
|
1546
2134
|
}
|
|
1547
|
-
results.sort((a, b) => b.score - a.score);
|
|
1548
|
-
return results.slice(0, topK);
|
|
2135
|
+
return results.sort((a, b) => b.score - a.score).slice(0, topK);
|
|
1549
2136
|
}
|
|
1550
|
-
|
|
1551
|
-
const
|
|
1552
|
-
const
|
|
1553
|
-
|
|
1554
|
-
|
|
1555
|
-
|
|
1556
|
-
|
|
1557
|
-
|
|
1558
|
-
|
|
1559
|
-
|
|
1560
|
-
|
|
2137
|
+
findSymbolMatches(queryTokens) {
|
|
2138
|
+
const matches = new Map;
|
|
2139
|
+
for (const [filepath, entry] of this.symbolIndex) {
|
|
2140
|
+
let matchScore = 0;
|
|
2141
|
+
for (const symbol of entry.symbols) {
|
|
2142
|
+
const symbolName = symbol.name.toLowerCase();
|
|
2143
|
+
const symbolParts = symbolsToKeywords([symbol]);
|
|
2144
|
+
for (const token of queryTokens) {
|
|
2145
|
+
if (symbolName === token) {
|
|
2146
|
+
matchScore += symbol.isExported ? 1 : 0.8;
|
|
2147
|
+
} else if (symbolName.includes(token) || token.includes(symbolName)) {
|
|
2148
|
+
matchScore += symbol.isExported ? 0.5 : 0.4;
|
|
2149
|
+
} else if (symbolParts.some((p) => p === token)) {
|
|
2150
|
+
matchScore += symbol.isExported ? 0.3 : 0.2;
|
|
2151
|
+
}
|
|
2152
|
+
}
|
|
2153
|
+
}
|
|
2154
|
+
if (matchScore > 0) {
|
|
2155
|
+
matches.set(filepath, Math.min(1, matchScore / queryTokens.length));
|
|
2156
|
+
}
|
|
2157
|
+
}
|
|
2158
|
+
return matches;
|
|
2159
|
+
}
|
|
2160
|
+
findBestChunk(chunks, queryTokens, symbols) {
|
|
2161
|
+
let bestChunk = chunks[0];
|
|
2162
|
+
let bestScore = 0;
|
|
2163
|
+
for (const chunk of chunks) {
|
|
2164
|
+
let score = 0;
|
|
2165
|
+
const chunkContent = chunk.content.toLowerCase();
|
|
2166
|
+
for (const token of queryTokens) {
|
|
2167
|
+
if (chunkContent.includes(token)) {
|
|
2168
|
+
score += 1;
|
|
2169
|
+
}
|
|
2170
|
+
}
|
|
2171
|
+
if (chunk.name) {
|
|
2172
|
+
const nameLower = chunk.name.toLowerCase();
|
|
2173
|
+
for (const token of queryTokens) {
|
|
2174
|
+
if (nameLower.includes(token)) {
|
|
2175
|
+
score += 2;
|
|
2176
|
+
}
|
|
2177
|
+
}
|
|
2178
|
+
}
|
|
2179
|
+
if (chunk.isExported) {
|
|
2180
|
+
score += 0.5;
|
|
2181
|
+
}
|
|
2182
|
+
if (score > bestScore) {
|
|
2183
|
+
bestScore = score;
|
|
2184
|
+
bestChunk = chunk;
|
|
1561
2185
|
}
|
|
1562
2186
|
}
|
|
1563
|
-
|
|
1564
|
-
|
|
1565
|
-
|
|
1566
|
-
|
|
1567
|
-
|
|
1568
|
-
|
|
2187
|
+
return bestChunk;
|
|
2188
|
+
}
|
|
2189
|
+
async loadSymbolIndex(rootDir, config) {
|
|
2190
|
+
const coreDir = path8.join(getRaggrepDir(rootDir, config), "index", "core");
|
|
2191
|
+
const symbolsPath = path8.join(coreDir, "symbols.json");
|
|
2192
|
+
try {
|
|
2193
|
+
const content = await fs4.readFile(symbolsPath, "utf-8");
|
|
2194
|
+
const data = JSON.parse(content);
|
|
2195
|
+
this.symbolIndex = new Map(Object.entries(data.files));
|
|
2196
|
+
if (data.bm25Data) {
|
|
2197
|
+
this.bm25Index = BM25Index.deserialize(data.bm25Data);
|
|
1569
2198
|
}
|
|
2199
|
+
} catch (error) {
|
|
2200
|
+
this.symbolIndex = new Map;
|
|
2201
|
+
this.bm25Index = null;
|
|
1570
2202
|
}
|
|
1571
|
-
|
|
2203
|
+
}
|
|
2204
|
+
async dispose() {
|
|
2205
|
+
this.symbolIndex.clear();
|
|
2206
|
+
this.bm25Index = null;
|
|
1572
2207
|
}
|
|
1573
2208
|
}
|
|
1574
|
-
var
|
|
1575
|
-
var
|
|
1576
|
-
init_embeddings();
|
|
2209
|
+
var DEFAULT_MIN_SCORE = 0.1, DEFAULT_TOP_K = 20, LINES_PER_CHUNK = 50, CHUNK_OVERLAP = 10;
|
|
2210
|
+
var init_core = __esm(() => {
|
|
1577
2211
|
init_config2();
|
|
1578
|
-
|
|
1579
|
-
|
|
1580
|
-
init_keywords();
|
|
1581
|
-
init_keywords();
|
|
2212
|
+
init_introspection();
|
|
2213
|
+
init_symbols();
|
|
1582
2214
|
});
|
|
1583
2215
|
|
|
1584
|
-
// src/
|
|
1585
|
-
|
|
1586
|
-
|
|
1587
|
-
|
|
1588
|
-
if (this.modules.has(module.id)) {
|
|
1589
|
-
console.warn(`Module '${module.id}' is already registered, overwriting...`);
|
|
1590
|
-
}
|
|
1591
|
-
this.modules.set(module.id, module);
|
|
1592
|
-
}
|
|
1593
|
-
get(id) {
|
|
1594
|
-
return this.modules.get(id);
|
|
1595
|
-
}
|
|
1596
|
-
list() {
|
|
1597
|
-
return Array.from(this.modules.values());
|
|
2216
|
+
// src/domain/services/similarity.ts
|
|
2217
|
+
function cosineSimilarity(a, b) {
|
|
2218
|
+
if (a.length !== b.length) {
|
|
2219
|
+
throw new Error(`Vector length mismatch: ${a.length} vs ${b.length}`);
|
|
1598
2220
|
}
|
|
1599
|
-
|
|
1600
|
-
|
|
1601
|
-
|
|
2221
|
+
let dotProduct = 0;
|
|
2222
|
+
let normA = 0;
|
|
2223
|
+
let normB = 0;
|
|
2224
|
+
for (let i = 0;i < a.length; i++) {
|
|
2225
|
+
dotProduct += a[i] * b[i];
|
|
2226
|
+
normA += a[i] * a[i];
|
|
2227
|
+
normB += b[i] * b[i];
|
|
1602
2228
|
}
|
|
2229
|
+
const magnitude = Math.sqrt(normA) * Math.sqrt(normB);
|
|
2230
|
+
if (magnitude === 0)
|
|
2231
|
+
return 0;
|
|
2232
|
+
return dotProduct / magnitude;
|
|
1603
2233
|
}
|
|
1604
|
-
async function registerBuiltInModules() {
|
|
1605
|
-
const { CoreModule: CoreModule2 } = await Promise.resolve().then(() => (init_core(), exports_core));
|
|
1606
|
-
const { TypeScriptModule: TypeScriptModule2 } = await Promise.resolve().then(() => (init_typescript(), exports_typescript));
|
|
1607
|
-
registry.register(new CoreModule2);
|
|
1608
|
-
registry.register(new TypeScriptModule2);
|
|
1609
|
-
}
|
|
1610
|
-
var registry;
|
|
1611
|
-
var init_registry = __esm(() => {
|
|
1612
|
-
registry = new ModuleRegistryImpl;
|
|
1613
|
-
});
|
|
1614
2234
|
|
|
1615
|
-
// src/
|
|
1616
|
-
import * as
|
|
1617
|
-
|
|
1618
|
-
|
|
1619
|
-
|
|
1620
|
-
|
|
1621
|
-
if (scope === "unknown")
|
|
1622
|
-
continue;
|
|
1623
|
-
for (const keyword of keywords) {
|
|
1624
|
-
if (nameLower.includes(keyword)) {
|
|
1625
|
-
return scope;
|
|
1626
|
-
}
|
|
1627
|
-
}
|
|
2235
|
+
// src/modules/language/typescript/parseCode.ts
|
|
2236
|
+
import * as ts from "typescript";
|
|
2237
|
+
function parseCode(content, filepath) {
|
|
2238
|
+
const ext = filepath.split(".").pop()?.toLowerCase();
|
|
2239
|
+
if (["ts", "tsx", "js", "jsx", "mts", "cts", "mjs", "cjs"].includes(ext || "")) {
|
|
2240
|
+
return parseTypeScript(content, filepath);
|
|
1628
2241
|
}
|
|
1629
|
-
return
|
|
2242
|
+
return parseGenericCode(content);
|
|
1630
2243
|
}
|
|
1631
|
-
|
|
1632
|
-
|
|
1633
|
-
|
|
1634
|
-
|
|
1635
|
-
const
|
|
1636
|
-
|
|
1637
|
-
const
|
|
1638
|
-
const
|
|
1639
|
-
|
|
1640
|
-
|
|
1641
|
-
|
|
1642
|
-
|
|
1643
|
-
|
|
2244
|
+
function parseTypeScript(content, filepath) {
|
|
2245
|
+
const chunks = [];
|
|
2246
|
+
const lines = content.split(`
|
|
2247
|
+
`);
|
|
2248
|
+
const sourceFile = ts.createSourceFile(filepath, content, ts.ScriptTarget.Latest, true, filepath.endsWith(".tsx") || filepath.endsWith(".jsx") ? ts.ScriptKind.TSX : ts.ScriptKind.TS);
|
|
2249
|
+
function getLineNumbers(node) {
|
|
2250
|
+
const start = sourceFile.getLineAndCharacterOfPosition(node.getStart());
|
|
2251
|
+
const end = sourceFile.getLineAndCharacterOfPosition(node.getEnd());
|
|
2252
|
+
return {
|
|
2253
|
+
startLine: start.line + 1,
|
|
2254
|
+
endLine: end.line + 1
|
|
2255
|
+
};
|
|
2256
|
+
}
|
|
2257
|
+
function getNodeText(node) {
|
|
2258
|
+
return node.getText(sourceFile);
|
|
2259
|
+
}
|
|
2260
|
+
function isExported(node) {
|
|
2261
|
+
if (!ts.canHaveModifiers(node))
|
|
2262
|
+
return false;
|
|
2263
|
+
const modifiers = ts.getModifiers(node);
|
|
2264
|
+
return modifiers?.some((m) => m.kind === ts.SyntaxKind.ExportKeyword) ?? false;
|
|
2265
|
+
}
|
|
2266
|
+
function getJSDoc(node) {
|
|
2267
|
+
const jsDocNodes = ts.getJSDocCommentsAndTags(node);
|
|
2268
|
+
if (jsDocNodes.length === 0)
|
|
2269
|
+
return;
|
|
2270
|
+
return jsDocNodes.map((doc) => doc.getText(sourceFile)).join(`
|
|
2271
|
+
`);
|
|
2272
|
+
}
|
|
2273
|
+
function getFunctionName(node) {
|
|
2274
|
+
if (ts.isFunctionDeclaration(node) && node.name) {
|
|
2275
|
+
return node.name.text;
|
|
1644
2276
|
}
|
|
1645
|
-
|
|
1646
|
-
|
|
1647
|
-
continue;
|
|
1648
|
-
if (SKIP_DIRS.has(entry.name))
|
|
1649
|
-
continue;
|
|
1650
|
-
const subPath = currentDir ? `${currentDir}/${entry.name}` : entry.name;
|
|
1651
|
-
const subResults = await scanForPackageJsons(rootDir, subPath, depth + 1);
|
|
1652
|
-
results.push(...subResults);
|
|
2277
|
+
if (ts.isMethodDeclaration(node) && ts.isIdentifier(node.name)) {
|
|
2278
|
+
return node.name.text;
|
|
1653
2279
|
}
|
|
1654
|
-
|
|
1655
|
-
|
|
1656
|
-
}
|
|
1657
|
-
async function parsePackageJson(rootDir, relativePath) {
|
|
1658
|
-
try {
|
|
1659
|
-
const packageJsonPath = path6.join(rootDir, relativePath, "package.json");
|
|
1660
|
-
const content = await fs4.readFile(packageJsonPath, "utf-8");
|
|
1661
|
-
const pkg = JSON.parse(content);
|
|
1662
|
-
const name = pkg.name || path6.basename(relativePath);
|
|
1663
|
-
const deps = { ...pkg.dependencies, ...pkg.devDependencies };
|
|
1664
|
-
let type = "unknown";
|
|
1665
|
-
if (deps["next"] || deps["react"] || deps["vue"] || deps["svelte"]) {
|
|
1666
|
-
type = "app";
|
|
1667
|
-
} else if (deps["express"] || deps["fastify"] || deps["koa"] || deps["hono"]) {
|
|
1668
|
-
type = "service";
|
|
1669
|
-
} else if (pkg.main || pkg.exports) {
|
|
1670
|
-
type = "library";
|
|
2280
|
+
if (ts.isVariableDeclaration(node) && ts.isIdentifier(node.name)) {
|
|
2281
|
+
return node.name.text;
|
|
1671
2282
|
}
|
|
1672
|
-
|
|
1673
|
-
return { name, relativePath, type, hasWorkspaces };
|
|
1674
|
-
} catch {
|
|
1675
|
-
return null;
|
|
2283
|
+
return;
|
|
1676
2284
|
}
|
|
1677
|
-
|
|
1678
|
-
|
|
1679
|
-
|
|
1680
|
-
|
|
1681
|
-
|
|
1682
|
-
|
|
1683
|
-
|
|
1684
|
-
|
|
1685
|
-
|
|
1686
|
-
|
|
1687
|
-
|
|
1688
|
-
|
|
1689
|
-
|
|
1690
|
-
|
|
1691
|
-
|
|
1692
|
-
|
|
1693
|
-
|
|
1694
|
-
|
|
1695
|
-
|
|
1696
|
-
|
|
1697
|
-
|
|
1698
|
-
|
|
1699
|
-
|
|
1700
|
-
|
|
1701
|
-
|
|
1702
|
-
|
|
1703
|
-
|
|
1704
|
-
|
|
1705
|
-
}
|
|
2285
|
+
function visit(node) {
|
|
2286
|
+
const { startLine, endLine } = getLineNumbers(node);
|
|
2287
|
+
if (ts.isFunctionDeclaration(node) && node.name) {
|
|
2288
|
+
chunks.push({
|
|
2289
|
+
content: getNodeText(node),
|
|
2290
|
+
startLine,
|
|
2291
|
+
endLine,
|
|
2292
|
+
type: "function",
|
|
2293
|
+
name: node.name.text,
|
|
2294
|
+
isExported: isExported(node),
|
|
2295
|
+
jsDoc: getJSDoc(node)
|
|
2296
|
+
});
|
|
2297
|
+
return;
|
|
2298
|
+
}
|
|
2299
|
+
if (ts.isVariableStatement(node)) {
|
|
2300
|
+
for (const decl of node.declarationList.declarations) {
|
|
2301
|
+
if (decl.initializer && (ts.isArrowFunction(decl.initializer) || ts.isFunctionExpression(decl.initializer))) {
|
|
2302
|
+
const name = ts.isIdentifier(decl.name) ? decl.name.text : undefined;
|
|
2303
|
+
chunks.push({
|
|
2304
|
+
content: getNodeText(node),
|
|
2305
|
+
startLine,
|
|
2306
|
+
endLine,
|
|
2307
|
+
type: "function",
|
|
2308
|
+
name,
|
|
2309
|
+
isExported: isExported(node),
|
|
2310
|
+
jsDoc: getJSDoc(node)
|
|
2311
|
+
});
|
|
2312
|
+
return;
|
|
2313
|
+
}
|
|
1706
2314
|
}
|
|
1707
2315
|
}
|
|
1708
|
-
|
|
1709
|
-
|
|
1710
|
-
|
|
1711
|
-
|
|
1712
|
-
|
|
1713
|
-
|
|
1714
|
-
|
|
1715
|
-
|
|
1716
|
-
|
|
1717
|
-
|
|
1718
|
-
|
|
1719
|
-
|
|
2316
|
+
if (ts.isClassDeclaration(node) && node.name) {
|
|
2317
|
+
chunks.push({
|
|
2318
|
+
content: getNodeText(node),
|
|
2319
|
+
startLine,
|
|
2320
|
+
endLine,
|
|
2321
|
+
type: "class",
|
|
2322
|
+
name: node.name.text,
|
|
2323
|
+
isExported: isExported(node),
|
|
2324
|
+
jsDoc: getJSDoc(node)
|
|
2325
|
+
});
|
|
2326
|
+
return;
|
|
2327
|
+
}
|
|
2328
|
+
if (ts.isInterfaceDeclaration(node)) {
|
|
2329
|
+
chunks.push({
|
|
2330
|
+
content: getNodeText(node),
|
|
2331
|
+
startLine,
|
|
2332
|
+
endLine,
|
|
2333
|
+
type: "interface",
|
|
2334
|
+
name: node.name.text,
|
|
2335
|
+
isExported: isExported(node),
|
|
2336
|
+
jsDoc: getJSDoc(node)
|
|
2337
|
+
});
|
|
2338
|
+
return;
|
|
2339
|
+
}
|
|
2340
|
+
if (ts.isTypeAliasDeclaration(node)) {
|
|
2341
|
+
chunks.push({
|
|
2342
|
+
content: getNodeText(node),
|
|
2343
|
+
startLine,
|
|
2344
|
+
endLine,
|
|
2345
|
+
type: "type",
|
|
2346
|
+
name: node.name.text,
|
|
2347
|
+
isExported: isExported(node),
|
|
2348
|
+
jsDoc: getJSDoc(node)
|
|
2349
|
+
});
|
|
2350
|
+
return;
|
|
2351
|
+
}
|
|
2352
|
+
if (ts.isEnumDeclaration(node)) {
|
|
2353
|
+
chunks.push({
|
|
2354
|
+
content: getNodeText(node),
|
|
2355
|
+
startLine,
|
|
2356
|
+
endLine,
|
|
2357
|
+
type: "enum",
|
|
2358
|
+
name: node.name.text,
|
|
2359
|
+
isExported: isExported(node),
|
|
2360
|
+
jsDoc: getJSDoc(node)
|
|
1720
2361
|
});
|
|
2362
|
+
return;
|
|
1721
2363
|
}
|
|
1722
|
-
|
|
1723
|
-
|
|
1724
|
-
|
|
1725
|
-
|
|
1726
|
-
|
|
1727
|
-
|
|
1728
|
-
|
|
1729
|
-
|
|
1730
|
-
|
|
1731
|
-
|
|
1732
|
-
|
|
1733
|
-
|
|
2364
|
+
if (ts.isVariableStatement(node) && isExported(node)) {
|
|
2365
|
+
for (const decl of node.declarationList.declarations) {
|
|
2366
|
+
if (decl.initializer && (ts.isArrowFunction(decl.initializer) || ts.isFunctionExpression(decl.initializer))) {
|
|
2367
|
+
continue;
|
|
2368
|
+
}
|
|
2369
|
+
const name = ts.isIdentifier(decl.name) ? decl.name.text : undefined;
|
|
2370
|
+
chunks.push({
|
|
2371
|
+
content: getNodeText(node),
|
|
2372
|
+
startLine,
|
|
2373
|
+
endLine,
|
|
2374
|
+
type: "variable",
|
|
2375
|
+
name,
|
|
2376
|
+
isExported: true,
|
|
2377
|
+
jsDoc: getJSDoc(node)
|
|
2378
|
+
});
|
|
1734
2379
|
}
|
|
1735
|
-
|
|
1736
|
-
|
|
1737
|
-
|
|
1738
|
-
projects,
|
|
1739
|
-
isMonorepo,
|
|
1740
|
-
rootType: isMonorepo ? undefined : rootType
|
|
1741
|
-
};
|
|
1742
|
-
} catch {
|
|
1743
|
-
return {
|
|
1744
|
-
projects: [],
|
|
1745
|
-
isMonorepo: false,
|
|
1746
|
-
rootType: "unknown"
|
|
1747
|
-
};
|
|
2380
|
+
return;
|
|
2381
|
+
}
|
|
2382
|
+
ts.forEachChild(node, visit);
|
|
1748
2383
|
}
|
|
1749
|
-
|
|
1750
|
-
|
|
1751
|
-
|
|
1752
|
-
case "apps":
|
|
1753
|
-
return "app";
|
|
1754
|
-
case "packages":
|
|
1755
|
-
case "libs":
|
|
1756
|
-
return "library";
|
|
1757
|
-
case "services":
|
|
1758
|
-
return "service";
|
|
1759
|
-
case "scripts":
|
|
1760
|
-
case "tools":
|
|
1761
|
-
return "script";
|
|
1762
|
-
default:
|
|
1763
|
-
return "unknown";
|
|
2384
|
+
ts.forEachChild(sourceFile, visit);
|
|
2385
|
+
if (chunks.length === 0) {
|
|
2386
|
+
return parseGenericCode(content);
|
|
1764
2387
|
}
|
|
2388
|
+
return chunks;
|
|
1765
2389
|
}
|
|
1766
|
-
function
|
|
1767
|
-
const
|
|
1768
|
-
const
|
|
1769
|
-
|
|
1770
|
-
|
|
1771
|
-
|
|
1772
|
-
|
|
1773
|
-
|
|
1774
|
-
|
|
1775
|
-
|
|
2390
|
+
function parseGenericCode(content) {
|
|
2391
|
+
const chunks = [];
|
|
2392
|
+
const lines = content.split(`
|
|
2393
|
+
`);
|
|
2394
|
+
const CHUNK_SIZE = 30;
|
|
2395
|
+
const OVERLAP = 5;
|
|
2396
|
+
if (lines.length <= CHUNK_SIZE) {
|
|
2397
|
+
return [
|
|
2398
|
+
{
|
|
2399
|
+
content,
|
|
2400
|
+
startLine: 1,
|
|
2401
|
+
endLine: lines.length,
|
|
2402
|
+
type: "file"
|
|
2403
|
+
}
|
|
2404
|
+
];
|
|
1776
2405
|
}
|
|
1777
|
-
for (
|
|
1778
|
-
const
|
|
1779
|
-
|
|
1780
|
-
|
|
1781
|
-
|
|
1782
|
-
|
|
1783
|
-
|
|
1784
|
-
|
|
1785
|
-
}
|
|
2406
|
+
for (let i = 0;i < lines.length; i += CHUNK_SIZE - OVERLAP) {
|
|
2407
|
+
const endIdx = Math.min(i + CHUNK_SIZE, lines.length);
|
|
2408
|
+
chunks.push({
|
|
2409
|
+
content: lines.slice(i, endIdx).join(`
|
|
2410
|
+
`),
|
|
2411
|
+
startLine: i + 1,
|
|
2412
|
+
endLine: endIdx,
|
|
2413
|
+
type: "block"
|
|
2414
|
+
});
|
|
2415
|
+
if (endIdx >= lines.length)
|
|
2416
|
+
break;
|
|
1786
2417
|
}
|
|
1787
|
-
return
|
|
1788
|
-
name: "root",
|
|
1789
|
-
root: "",
|
|
1790
|
-
type: structure.rootType ?? "unknown"
|
|
1791
|
-
};
|
|
2418
|
+
return chunks;
|
|
1792
2419
|
}
|
|
1793
|
-
|
|
1794
|
-
|
|
1795
|
-
|
|
1796
|
-
|
|
1797
|
-
|
|
1798
|
-
|
|
1799
|
-
|
|
1800
|
-
|
|
1801
|
-
|
|
1802
|
-
"coverage",
|
|
1803
|
-
".raggrep"
|
|
1804
|
-
]);
|
|
1805
|
-
PROJECT_PATTERNS = [
|
|
1806
|
-
{ pattern: /^apps\/([^/]+)/, type: "app", defaultScope: "unknown" },
|
|
1807
|
-
{ pattern: /^packages\/([^/]+)/, type: "library", defaultScope: "shared" },
|
|
1808
|
-
{ pattern: /^libs\/([^/]+)/, type: "library", defaultScope: "shared" },
|
|
1809
|
-
{ pattern: /^services\/([^/]+)/, type: "service", defaultScope: "backend" },
|
|
1810
|
-
{ pattern: /^scripts\/([^/]+)/, type: "script", defaultScope: "tooling" },
|
|
1811
|
-
{ pattern: /^tools\/([^/]+)/, type: "script", defaultScope: "tooling" }
|
|
1812
|
-
];
|
|
1813
|
-
SCOPE_KEYWORDS = {
|
|
1814
|
-
frontend: [
|
|
1815
|
-
"web",
|
|
1816
|
-
"webapp",
|
|
1817
|
-
"frontend",
|
|
1818
|
-
"client",
|
|
1819
|
-
"ui",
|
|
1820
|
-
"app",
|
|
1821
|
-
"mobile",
|
|
1822
|
-
"react",
|
|
1823
|
-
"vue",
|
|
1824
|
-
"angular",
|
|
1825
|
-
"next",
|
|
1826
|
-
"nuxt"
|
|
1827
|
-
],
|
|
1828
|
-
backend: [
|
|
1829
|
-
"api",
|
|
1830
|
-
"server",
|
|
1831
|
-
"backend",
|
|
1832
|
-
"service",
|
|
1833
|
-
"worker",
|
|
1834
|
-
"lambda",
|
|
1835
|
-
"functions"
|
|
1836
|
-
],
|
|
1837
|
-
shared: ["shared", "common", "utils", "lib", "core", "types", "models"],
|
|
1838
|
-
tooling: [
|
|
1839
|
-
"scripts",
|
|
1840
|
-
"tools",
|
|
1841
|
-
"cli",
|
|
1842
|
-
"devtools",
|
|
1843
|
-
"build",
|
|
1844
|
-
"config",
|
|
1845
|
-
"infra"
|
|
1846
|
-
],
|
|
1847
|
-
unknown: []
|
|
1848
|
-
};
|
|
2420
|
+
function generateChunkId(filepath, startLine, endLine) {
|
|
2421
|
+
const safePath = filepath.replace(/[/\\]/g, "-").replace(/\./g, "_");
|
|
2422
|
+
return `${safePath}-${startLine}-${endLine}`;
|
|
2423
|
+
}
|
|
2424
|
+
var init_parseCode = () => {};
|
|
2425
|
+
|
|
2426
|
+
// src/infrastructure/storage/fileIndexStorage.ts
|
|
2427
|
+
var init_fileIndexStorage = __esm(() => {
|
|
2428
|
+
init_entities();
|
|
1849
2429
|
});
|
|
1850
2430
|
|
|
1851
|
-
// src/
|
|
1852
|
-
|
|
1853
|
-
|
|
1854
|
-
|
|
1855
|
-
|
|
1856
|
-
|
|
1857
|
-
|
|
1858
|
-
|
|
1859
|
-
const
|
|
1860
|
-
|
|
1861
|
-
|
|
1862
|
-
|
|
1863
|
-
|
|
1864
|
-
|
|
1865
|
-
|
|
2431
|
+
// src/domain/services/keywords.ts
|
|
2432
|
+
function extractKeywords(content, name, maxKeywords = 50) {
|
|
2433
|
+
const keywords = new Set;
|
|
2434
|
+
if (name) {
|
|
2435
|
+
keywords.add(name.toLowerCase());
|
|
2436
|
+
const parts = name.split(/(?=[A-Z])/).map((p) => p.toLowerCase());
|
|
2437
|
+
parts.forEach((p) => p.length > 2 && keywords.add(p));
|
|
2438
|
+
}
|
|
2439
|
+
const identifierRegex = /\b([a-zA-Z_][a-zA-Z0-9_]{2,})\b/g;
|
|
2440
|
+
let match;
|
|
2441
|
+
while ((match = identifierRegex.exec(content)) !== null) {
|
|
2442
|
+
const word = match[1].toLowerCase();
|
|
2443
|
+
if (!COMMON_KEYWORDS.has(word) && word.length > 2) {
|
|
2444
|
+
keywords.add(word);
|
|
2445
|
+
}
|
|
2446
|
+
}
|
|
2447
|
+
return Array.from(keywords).slice(0, maxKeywords);
|
|
2448
|
+
}
|
|
2449
|
+
function splitIdentifier(str) {
|
|
2450
|
+
return str.replace(/([a-z])([A-Z])/g, "$1 $2").replace(/[_-]/g, " ").split(/\s+/).map((s) => s.toLowerCase()).filter((s) => s.length > 1);
|
|
2451
|
+
}
|
|
2452
|
+
function extractPathKeywords(filepath) {
|
|
2453
|
+
const keywords = new Set;
|
|
2454
|
+
const pathWithoutExt = filepath.replace(/\.[^.]+$/, "");
|
|
2455
|
+
const segments = pathWithoutExt.split(/[/\\]/);
|
|
2456
|
+
for (const segment of segments) {
|
|
2457
|
+
if (segment.length < 2)
|
|
2458
|
+
continue;
|
|
2459
|
+
const lower = segment.toLowerCase();
|
|
2460
|
+
if (!COMMON_KEYWORDS.has(lower) && lower.length > 2) {
|
|
2461
|
+
keywords.add(lower);
|
|
2462
|
+
}
|
|
2463
|
+
const parts = splitIdentifier(segment);
|
|
2464
|
+
for (const part of parts) {
|
|
2465
|
+
if (!COMMON_KEYWORDS.has(part) && part.length > 2) {
|
|
2466
|
+
keywords.add(part);
|
|
2467
|
+
}
|
|
2468
|
+
}
|
|
1866
2469
|
}
|
|
1867
|
-
return
|
|
1868
|
-
filepath: normalizedPath,
|
|
1869
|
-
project,
|
|
1870
|
-
scope,
|
|
1871
|
-
layer,
|
|
1872
|
-
domain,
|
|
1873
|
-
language,
|
|
1874
|
-
framework,
|
|
1875
|
-
depth: segments.length - 1,
|
|
1876
|
-
pathSegments: segments.slice(0, -1)
|
|
1877
|
-
};
|
|
2470
|
+
return Array.from(keywords);
|
|
1878
2471
|
}
|
|
1879
|
-
function
|
|
2472
|
+
function parsePathContext(filepath) {
|
|
2473
|
+
const pathWithoutExt = filepath.replace(/\.[^.]+$/, "");
|
|
2474
|
+
const allSegments = pathWithoutExt.split(/[/\\]/);
|
|
2475
|
+
const filename = allSegments[allSegments.length - 1];
|
|
2476
|
+
const dirSegments = allSegments.slice(0, -1);
|
|
2477
|
+
const keywords = extractPathKeywords(filepath);
|
|
2478
|
+
let layer;
|
|
2479
|
+
const allLower = [...dirSegments, filename].map((s) => s.toLowerCase()).join(" ");
|
|
1880
2480
|
const filenameLower = filename.toLowerCase();
|
|
1881
|
-
for (const [
|
|
2481
|
+
for (const [layerName, patterns] of Object.entries(LAYER_PATTERNS2)) {
|
|
1882
2482
|
for (const pattern of patterns) {
|
|
1883
2483
|
if (filenameLower.includes(pattern)) {
|
|
1884
|
-
|
|
2484
|
+
layer = layerName;
|
|
2485
|
+
break;
|
|
2486
|
+
}
|
|
2487
|
+
if (dirSegments.some((s) => s.toLowerCase() === pattern)) {
|
|
2488
|
+
layer = layerName;
|
|
2489
|
+
break;
|
|
1885
2490
|
}
|
|
1886
2491
|
}
|
|
2492
|
+
if (layer)
|
|
2493
|
+
break;
|
|
1887
2494
|
}
|
|
1888
|
-
|
|
1889
|
-
|
|
1890
|
-
|
|
1891
|
-
|
|
1892
|
-
|
|
1893
|
-
|
|
2495
|
+
let domain;
|
|
2496
|
+
const layerPatternSet = new Set(Object.values(LAYER_PATTERNS2).flat());
|
|
2497
|
+
const reversedSegments = [...dirSegments].reverse();
|
|
2498
|
+
for (const segment of reversedSegments) {
|
|
2499
|
+
const lower = segment.toLowerCase();
|
|
2500
|
+
if (["src", "lib", "app", "packages", "modules"].includes(lower))
|
|
2501
|
+
continue;
|
|
2502
|
+
if (layerPatternSet.has(lower))
|
|
2503
|
+
continue;
|
|
2504
|
+
if (lower.length > 2) {
|
|
2505
|
+
domain = lower;
|
|
2506
|
+
break;
|
|
1894
2507
|
}
|
|
1895
2508
|
}
|
|
1896
|
-
return
|
|
2509
|
+
return {
|
|
2510
|
+
segments: dirSegments,
|
|
2511
|
+
layer,
|
|
2512
|
+
domain,
|
|
2513
|
+
depth: dirSegments.length,
|
|
2514
|
+
keywords
|
|
2515
|
+
};
|
|
1897
2516
|
}
|
|
1898
|
-
function
|
|
1899
|
-
const
|
|
1900
|
-
|
|
1901
|
-
|
|
1902
|
-
|
|
1903
|
-
|
|
1904
|
-
|
|
1905
|
-
|
|
1906
|
-
|
|
1907
|
-
|
|
1908
|
-
...
|
|
2517
|
+
function formatPathContextForEmbedding(pathContext) {
|
|
2518
|
+
const parts = [];
|
|
2519
|
+
if (pathContext.domain) {
|
|
2520
|
+
parts.push(pathContext.domain);
|
|
2521
|
+
}
|
|
2522
|
+
if (pathContext.layer) {
|
|
2523
|
+
parts.push(pathContext.layer);
|
|
2524
|
+
}
|
|
2525
|
+
const significantSegments = pathContext.segments.slice(-3).filter((s) => s.length > 2 && !["src", "lib", "app"].includes(s.toLowerCase()));
|
|
2526
|
+
if (significantSegments.length > 0) {
|
|
2527
|
+
parts.push(...significantSegments.map((s) => s.toLowerCase()));
|
|
2528
|
+
}
|
|
2529
|
+
if (parts.length === 0)
|
|
2530
|
+
return "";
|
|
2531
|
+
const unique = [...new Set(parts)];
|
|
2532
|
+
return `[${unique.join(" ")}]`;
|
|
2533
|
+
}
|
|
2534
|
+
var COMMON_KEYWORDS, LAYER_PATTERNS2;
|
|
2535
|
+
var init_keywords = __esm(() => {
|
|
2536
|
+
COMMON_KEYWORDS = new Set([
|
|
2537
|
+
"const",
|
|
2538
|
+
"let",
|
|
2539
|
+
"var",
|
|
2540
|
+
"function",
|
|
2541
|
+
"class",
|
|
2542
|
+
"interface",
|
|
2543
|
+
"type",
|
|
2544
|
+
"enum",
|
|
2545
|
+
"export",
|
|
2546
|
+
"import",
|
|
2547
|
+
"from",
|
|
2548
|
+
"return",
|
|
2549
|
+
"async",
|
|
2550
|
+
"await",
|
|
2551
|
+
"new",
|
|
2552
|
+
"this",
|
|
2553
|
+
"true",
|
|
2554
|
+
"false",
|
|
2555
|
+
"null",
|
|
2556
|
+
"undefined",
|
|
2557
|
+
"if",
|
|
2558
|
+
"else",
|
|
2559
|
+
"for",
|
|
2560
|
+
"while",
|
|
2561
|
+
"switch",
|
|
2562
|
+
"case",
|
|
2563
|
+
"break",
|
|
2564
|
+
"continue",
|
|
2565
|
+
"try",
|
|
2566
|
+
"catch",
|
|
2567
|
+
"finally",
|
|
2568
|
+
"throw",
|
|
2569
|
+
"typeof",
|
|
2570
|
+
"instanceof",
|
|
2571
|
+
"void",
|
|
2572
|
+
"delete",
|
|
2573
|
+
"in",
|
|
2574
|
+
"of",
|
|
2575
|
+
"string",
|
|
2576
|
+
"number",
|
|
2577
|
+
"boolean",
|
|
2578
|
+
"any",
|
|
2579
|
+
"unknown",
|
|
2580
|
+
"never",
|
|
2581
|
+
"object",
|
|
2582
|
+
"public",
|
|
2583
|
+
"private",
|
|
2584
|
+
"protected",
|
|
2585
|
+
"static",
|
|
2586
|
+
"readonly",
|
|
2587
|
+
"abstract",
|
|
2588
|
+
"implements",
|
|
2589
|
+
"extends",
|
|
2590
|
+
"super",
|
|
2591
|
+
"get",
|
|
2592
|
+
"set",
|
|
2593
|
+
"constructor",
|
|
2594
|
+
"the",
|
|
2595
|
+
"and",
|
|
2596
|
+
"for",
|
|
2597
|
+
"not",
|
|
2598
|
+
"with",
|
|
2599
|
+
"are",
|
|
2600
|
+
"was",
|
|
2601
|
+
"has",
|
|
2602
|
+
"have"
|
|
1909
2603
|
]);
|
|
1910
|
-
|
|
1911
|
-
|
|
1912
|
-
|
|
1913
|
-
|
|
1914
|
-
|
|
1915
|
-
|
|
2604
|
+
LAYER_PATTERNS2 = {
|
|
2605
|
+
controller: ["controller", "controllers", "handler", "handlers", "route", "routes", "api"],
|
|
2606
|
+
service: ["service", "services", "usecase", "usecases", "application"],
|
|
2607
|
+
repository: ["repository", "repositories", "repo", "repos", "dao", "store", "storage"],
|
|
2608
|
+
model: ["model", "models", "entity", "entities", "schema", "schemas"],
|
|
2609
|
+
util: ["util", "utils", "utility", "utilities", "helper", "helpers", "common", "shared"],
|
|
2610
|
+
config: ["config", "configs", "configuration", "settings"],
|
|
2611
|
+
middleware: ["middleware", "middlewares", "interceptor", "interceptors"],
|
|
2612
|
+
domain: ["domain", "core", "business"],
|
|
2613
|
+
infrastructure: ["infrastructure", "infra", "external", "adapters"],
|
|
2614
|
+
presentation: ["presentation", "view", "views", "component", "components", "ui"],
|
|
2615
|
+
test: ["test", "tests", "spec", "specs", "__tests__", "__test__"]
|
|
2616
|
+
};
|
|
2617
|
+
});
|
|
2618
|
+
|
|
2619
|
+
// src/infrastructure/storage/symbolicIndex.ts
|
|
2620
|
+
import * as fs5 from "fs/promises";
|
|
2621
|
+
import * as path9 from "path";
|
|
2622
|
+
|
|
2623
|
+
class SymbolicIndex {
|
|
2624
|
+
meta = null;
|
|
2625
|
+
fileSummaries = new Map;
|
|
2626
|
+
bm25Index = null;
|
|
2627
|
+
symbolicPath;
|
|
2628
|
+
moduleId;
|
|
2629
|
+
constructor(indexDir, moduleId) {
|
|
2630
|
+
this.symbolicPath = path9.join(indexDir, "index", moduleId, "symbolic");
|
|
2631
|
+
this.moduleId = moduleId;
|
|
2632
|
+
}
|
|
2633
|
+
async initialize() {
|
|
2634
|
+
try {
|
|
2635
|
+
await this.load();
|
|
2636
|
+
} catch {
|
|
2637
|
+
this.meta = {
|
|
2638
|
+
version: "1.0.0",
|
|
2639
|
+
lastUpdated: new Date().toISOString(),
|
|
2640
|
+
moduleId: this.moduleId,
|
|
2641
|
+
fileCount: 0,
|
|
2642
|
+
bm25Data: {
|
|
2643
|
+
avgDocLength: 0,
|
|
2644
|
+
documentFrequencies: {},
|
|
2645
|
+
totalDocs: 0
|
|
2646
|
+
}
|
|
2647
|
+
};
|
|
2648
|
+
this.bm25Index = new BM25Index;
|
|
1916
2649
|
}
|
|
1917
|
-
|
|
1918
|
-
|
|
1919
|
-
|
|
2650
|
+
}
|
|
2651
|
+
addFile(summary) {
|
|
2652
|
+
this.fileSummaries.set(summary.filepath, summary);
|
|
2653
|
+
}
|
|
2654
|
+
removeFile(filepath) {
|
|
2655
|
+
return this.fileSummaries.delete(filepath);
|
|
2656
|
+
}
|
|
2657
|
+
buildBM25Index() {
|
|
2658
|
+
this.bm25Index = new BM25Index;
|
|
2659
|
+
for (const [filepath, summary] of this.fileSummaries) {
|
|
2660
|
+
const content = [
|
|
2661
|
+
...summary.keywords,
|
|
2662
|
+
...summary.exports,
|
|
2663
|
+
...extractPathKeywords(filepath)
|
|
2664
|
+
].join(" ");
|
|
2665
|
+
this.bm25Index.addDocuments([{ id: filepath, content }]);
|
|
2666
|
+
}
|
|
2667
|
+
if (this.meta) {
|
|
2668
|
+
this.meta.fileCount = this.fileSummaries.size;
|
|
2669
|
+
this.meta.bm25Data.totalDocs = this.fileSummaries.size;
|
|
2670
|
+
}
|
|
2671
|
+
}
|
|
2672
|
+
findCandidates(query, maxCandidates = 20) {
|
|
2673
|
+
if (!this.bm25Index) {
|
|
2674
|
+
return Array.from(this.fileSummaries.keys());
|
|
2675
|
+
}
|
|
2676
|
+
const results = this.bm25Index.search(query, maxCandidates);
|
|
2677
|
+
return results.map((r) => r.id);
|
|
2678
|
+
}
|
|
2679
|
+
getAllFiles() {
|
|
2680
|
+
return Array.from(this.fileSummaries.keys());
|
|
2681
|
+
}
|
|
2682
|
+
getFileSummary(filepath) {
|
|
2683
|
+
return this.fileSummaries.get(filepath);
|
|
2684
|
+
}
|
|
2685
|
+
async save() {
|
|
2686
|
+
if (!this.meta)
|
|
2687
|
+
throw new Error("Index not initialized");
|
|
2688
|
+
this.meta.lastUpdated = new Date().toISOString();
|
|
2689
|
+
this.meta.fileCount = this.fileSummaries.size;
|
|
2690
|
+
await fs5.mkdir(this.symbolicPath, { recursive: true });
|
|
2691
|
+
const metaPath = path9.join(this.symbolicPath, "_meta.json");
|
|
2692
|
+
await fs5.writeFile(metaPath, JSON.stringify(this.meta, null, 2));
|
|
2693
|
+
for (const [filepath, summary] of this.fileSummaries) {
|
|
2694
|
+
const summaryPath = this.getFileSummaryPath(filepath);
|
|
2695
|
+
await fs5.mkdir(path9.dirname(summaryPath), { recursive: true });
|
|
2696
|
+
await fs5.writeFile(summaryPath, JSON.stringify(summary, null, 2));
|
|
2697
|
+
}
|
|
2698
|
+
}
|
|
2699
|
+
async load() {
|
|
2700
|
+
const metaPath = path9.join(this.symbolicPath, "_meta.json");
|
|
2701
|
+
const metaContent = await fs5.readFile(metaPath, "utf-8");
|
|
2702
|
+
this.meta = JSON.parse(metaContent);
|
|
2703
|
+
this.fileSummaries.clear();
|
|
2704
|
+
await this.loadFileSummariesRecursive(this.symbolicPath);
|
|
2705
|
+
this.buildBM25Index();
|
|
2706
|
+
}
|
|
2707
|
+
async loadFileSummariesRecursive(dir) {
|
|
2708
|
+
try {
|
|
2709
|
+
const entries = await fs5.readdir(dir, { withFileTypes: true });
|
|
2710
|
+
for (const entry of entries) {
|
|
2711
|
+
const fullPath = path9.join(dir, entry.name);
|
|
2712
|
+
if (entry.isDirectory()) {
|
|
2713
|
+
await this.loadFileSummariesRecursive(fullPath);
|
|
2714
|
+
} else if (entry.name.endsWith(".json") && entry.name !== "_meta.json") {
|
|
2715
|
+
try {
|
|
2716
|
+
const content = await fs5.readFile(fullPath, "utf-8");
|
|
2717
|
+
const summary = JSON.parse(content);
|
|
2718
|
+
if (summary.filepath) {
|
|
2719
|
+
this.fileSummaries.set(summary.filepath, summary);
|
|
2720
|
+
}
|
|
2721
|
+
} catch {}
|
|
2722
|
+
}
|
|
1920
2723
|
}
|
|
1921
|
-
}
|
|
2724
|
+
} catch {}
|
|
1922
2725
|
}
|
|
1923
|
-
|
|
1924
|
-
|
|
1925
|
-
|
|
1926
|
-
const projectScope = detectScopeFromName(project.name);
|
|
1927
|
-
if (projectScope !== "unknown") {
|
|
1928
|
-
return projectScope;
|
|
2726
|
+
getFileSummaryPath(filepath) {
|
|
2727
|
+
const jsonPath = filepath.replace(/\.[^.]+$/, ".json");
|
|
2728
|
+
return path9.join(this.symbolicPath, jsonPath);
|
|
1929
2729
|
}
|
|
1930
|
-
|
|
1931
|
-
|
|
1932
|
-
|
|
1933
|
-
|
|
1934
|
-
|
|
1935
|
-
return "backend";
|
|
1936
|
-
case "presentation":
|
|
1937
|
-
return "frontend";
|
|
1938
|
-
case "util":
|
|
1939
|
-
case "model":
|
|
1940
|
-
return "shared";
|
|
1941
|
-
case "test":
|
|
1942
|
-
return "tooling";
|
|
1943
|
-
}
|
|
2730
|
+
async deleteFileSummary(filepath) {
|
|
2731
|
+
try {
|
|
2732
|
+
await fs5.unlink(this.getFileSummaryPath(filepath));
|
|
2733
|
+
} catch {}
|
|
2734
|
+
this.fileSummaries.delete(filepath);
|
|
1944
2735
|
}
|
|
1945
|
-
|
|
1946
|
-
|
|
1947
|
-
|
|
1948
|
-
|
|
1949
|
-
|
|
1950
|
-
|
|
1951
|
-
return
|
|
1952
|
-
}
|
|
1953
|
-
if (["shared", "common", "lib", "libs"].includes(segmentLower)) {
|
|
1954
|
-
return "shared";
|
|
2736
|
+
async exists() {
|
|
2737
|
+
try {
|
|
2738
|
+
const metaPath = path9.join(this.symbolicPath, "_meta.json");
|
|
2739
|
+
await fs5.access(metaPath);
|
|
2740
|
+
return true;
|
|
2741
|
+
} catch {
|
|
2742
|
+
return false;
|
|
1955
2743
|
}
|
|
1956
2744
|
}
|
|
1957
|
-
|
|
1958
|
-
|
|
1959
|
-
|
|
1960
|
-
|
|
1961
|
-
|
|
1962
|
-
|
|
1963
|
-
|
|
1964
|
-
|
|
2745
|
+
get size() {
|
|
2746
|
+
return this.fileSummaries.size;
|
|
2747
|
+
}
|
|
2748
|
+
clear() {
|
|
2749
|
+
this.fileSummaries.clear();
|
|
2750
|
+
if (this.meta) {
|
|
2751
|
+
this.meta.fileCount = 0;
|
|
2752
|
+
this.meta.bm25Data = {
|
|
2753
|
+
avgDocLength: 0,
|
|
2754
|
+
documentFrequencies: {},
|
|
2755
|
+
totalDocs: 0
|
|
2756
|
+
};
|
|
1965
2757
|
}
|
|
2758
|
+
this.bm25Index = new BM25Index;
|
|
1966
2759
|
}
|
|
1967
|
-
return;
|
|
1968
2760
|
}
|
|
1969
|
-
var
|
|
1970
|
-
|
|
1971
|
-
init_projectDetector();
|
|
1972
|
-
LAYER_PATTERNS2 = {
|
|
1973
|
-
controller: ["controller", "api", "routes", "route", "handler"],
|
|
1974
|
-
service: ["service", "logic", "usecase", "usecases", "handler"],
|
|
1975
|
-
repository: ["repository", "repo", "dao", "store", "persistence"],
|
|
1976
|
-
model: ["model", "models", "entity", "entities", "schema", "schemas", "types", "type"],
|
|
1977
|
-
util: ["util", "utils", "helper", "helpers", "common", "lib"],
|
|
1978
|
-
config: ["config", "configuration", "settings"],
|
|
1979
|
-
middleware: ["middleware", "middlewares"],
|
|
1980
|
-
domain: ["domain"],
|
|
1981
|
-
infrastructure: ["infrastructure", "infra"],
|
|
1982
|
-
application: ["application", "app"],
|
|
1983
|
-
presentation: ["presentation", "ui", "views", "view", "component", "components"],
|
|
1984
|
-
test: ["test", "tests", "spec", "specs", "__tests__", "e2e"]
|
|
1985
|
-
};
|
|
1986
|
-
DOMAIN_PATTERNS = [
|
|
1987
|
-
"auth",
|
|
1988
|
-
"authentication",
|
|
1989
|
-
"user",
|
|
1990
|
-
"users",
|
|
1991
|
-
"account",
|
|
1992
|
-
"accounts",
|
|
1993
|
-
"profile",
|
|
1994
|
-
"profiles",
|
|
1995
|
-
"product",
|
|
1996
|
-
"products",
|
|
1997
|
-
"item",
|
|
1998
|
-
"items",
|
|
1999
|
-
"catalog",
|
|
2000
|
-
"order",
|
|
2001
|
-
"orders",
|
|
2002
|
-
"cart",
|
|
2003
|
-
"checkout",
|
|
2004
|
-
"payment",
|
|
2005
|
-
"payments",
|
|
2006
|
-
"billing",
|
|
2007
|
-
"subscription",
|
|
2008
|
-
"subscriptions",
|
|
2009
|
-
"notification",
|
|
2010
|
-
"notifications",
|
|
2011
|
-
"email",
|
|
2012
|
-
"sms",
|
|
2013
|
-
"report",
|
|
2014
|
-
"reports",
|
|
2015
|
-
"analytics",
|
|
2016
|
-
"metrics",
|
|
2017
|
-
"dashboard",
|
|
2018
|
-
"admin",
|
|
2019
|
-
"settings",
|
|
2020
|
-
"search",
|
|
2021
|
-
"chat",
|
|
2022
|
-
"message",
|
|
2023
|
-
"messages",
|
|
2024
|
-
"feed",
|
|
2025
|
-
"post",
|
|
2026
|
-
"posts",
|
|
2027
|
-
"comment",
|
|
2028
|
-
"comments",
|
|
2029
|
-
"media",
|
|
2030
|
-
"upload",
|
|
2031
|
-
"file",
|
|
2032
|
-
"files",
|
|
2033
|
-
"storage",
|
|
2034
|
-
"cache",
|
|
2035
|
-
"session",
|
|
2036
|
-
"log",
|
|
2037
|
-
"logs",
|
|
2038
|
-
"audit"
|
|
2039
|
-
];
|
|
2040
|
-
FRAMEWORK_INDICATORS = {
|
|
2041
|
-
nextjs: ["next", "next/"],
|
|
2042
|
-
express: ["express"],
|
|
2043
|
-
fastify: ["fastify"],
|
|
2044
|
-
react: ["react"],
|
|
2045
|
-
vue: ["vue"],
|
|
2046
|
-
angular: ["@angular/"],
|
|
2047
|
-
nestjs: ["@nestjs/"],
|
|
2048
|
-
koa: ["koa"]
|
|
2049
|
-
};
|
|
2050
|
-
EXTENSION_TO_LANGUAGE = {
|
|
2051
|
-
".ts": "typescript",
|
|
2052
|
-
".tsx": "typescript",
|
|
2053
|
-
".js": "javascript",
|
|
2054
|
-
".jsx": "javascript",
|
|
2055
|
-
".mjs": "javascript",
|
|
2056
|
-
".cjs": "javascript",
|
|
2057
|
-
".py": "python",
|
|
2058
|
-
".go": "go",
|
|
2059
|
-
".rs": "rust",
|
|
2060
|
-
".java": "java",
|
|
2061
|
-
".kt": "kotlin",
|
|
2062
|
-
".swift": "swift",
|
|
2063
|
-
".rb": "ruby",
|
|
2064
|
-
".php": "php",
|
|
2065
|
-
".cs": "csharp",
|
|
2066
|
-
".cpp": "cpp",
|
|
2067
|
-
".c": "c",
|
|
2068
|
-
".h": "c",
|
|
2069
|
-
".hpp": "cpp",
|
|
2070
|
-
".md": "markdown",
|
|
2071
|
-
".json": "json",
|
|
2072
|
-
".yaml": "yaml",
|
|
2073
|
-
".yml": "yaml"
|
|
2074
|
-
};
|
|
2761
|
+
var init_symbolicIndex = __esm(() => {
|
|
2762
|
+
init_keywords();
|
|
2075
2763
|
});
|
|
2076
2764
|
|
|
2077
|
-
// src/
|
|
2078
|
-
|
|
2079
|
-
|
|
2765
|
+
// src/infrastructure/storage/index.ts
|
|
2766
|
+
var init_storage = __esm(() => {
|
|
2767
|
+
init_fileIndexStorage();
|
|
2768
|
+
init_symbolicIndex();
|
|
2769
|
+
});
|
|
2080
2770
|
|
|
2081
|
-
|
|
2082
|
-
|
|
2083
|
-
|
|
2084
|
-
|
|
2085
|
-
|
|
2086
|
-
|
|
2087
|
-
|
|
2088
|
-
|
|
2089
|
-
|
|
2090
|
-
|
|
2091
|
-
|
|
2092
|
-
|
|
2093
|
-
|
|
2094
|
-
|
|
2095
|
-
|
|
2096
|
-
|
|
2097
|
-
|
|
2098
|
-
|
|
2099
|
-
|
|
2771
|
+
// src/modules/language/typescript/index.ts
|
|
2772
|
+
var exports_typescript = {};
|
|
2773
|
+
__export(exports_typescript, {
|
|
2774
|
+
TypeScriptModule: () => TypeScriptModule,
|
|
2775
|
+
DEFAULT_TOP_K: () => DEFAULT_TOP_K2,
|
|
2776
|
+
DEFAULT_MIN_SCORE: () => DEFAULT_MIN_SCORE2
|
|
2777
|
+
});
|
|
2778
|
+
import * as path10 from "path";
|
|
2779
|
+
|
|
2780
|
+
class TypeScriptModule {
|
|
2781
|
+
id = "language/typescript";
|
|
2782
|
+
name = "TypeScript Search";
|
|
2783
|
+
description = "TypeScript-aware code search with AST parsing and semantic embeddings";
|
|
2784
|
+
version = "1.0.0";
|
|
2785
|
+
embeddingConfig = null;
|
|
2786
|
+
symbolicIndex = null;
|
|
2787
|
+
pendingSummaries = new Map;
|
|
2788
|
+
rootDir = "";
|
|
2789
|
+
async initialize(config) {
|
|
2790
|
+
this.embeddingConfig = getEmbeddingConfigFromModule(config);
|
|
2791
|
+
configureEmbeddings(this.embeddingConfig);
|
|
2792
|
+
this.pendingSummaries.clear();
|
|
2100
2793
|
}
|
|
2101
|
-
|
|
2102
|
-
|
|
2103
|
-
|
|
2794
|
+
async indexFile(filepath, content, ctx) {
|
|
2795
|
+
this.rootDir = ctx.rootDir;
|
|
2796
|
+
const parsedChunks = parseCode(content, filepath);
|
|
2797
|
+
if (parsedChunks.length === 0) {
|
|
2798
|
+
return null;
|
|
2799
|
+
}
|
|
2800
|
+
const pathContext = parsePathContext(filepath);
|
|
2801
|
+
const pathPrefix = formatPathContextForEmbedding(pathContext);
|
|
2802
|
+
const chunkContents = parsedChunks.map((c) => {
|
|
2803
|
+
const namePrefix = c.name ? `${c.name}: ` : "";
|
|
2804
|
+
return `${pathPrefix} ${namePrefix}${c.content}`;
|
|
2805
|
+
});
|
|
2806
|
+
const embeddings = await getEmbeddings(chunkContents);
|
|
2807
|
+
const chunks = parsedChunks.map((pc) => ({
|
|
2808
|
+
id: generateChunkId(filepath, pc.startLine, pc.endLine),
|
|
2809
|
+
content: pc.content,
|
|
2810
|
+
startLine: pc.startLine,
|
|
2811
|
+
endLine: pc.endLine,
|
|
2812
|
+
type: pc.type,
|
|
2813
|
+
name: pc.name,
|
|
2814
|
+
isExported: pc.isExported,
|
|
2815
|
+
jsDoc: pc.jsDoc
|
|
2816
|
+
}));
|
|
2817
|
+
const references = this.extractReferences(content, filepath);
|
|
2818
|
+
const stats = await ctx.getFileStats(filepath);
|
|
2819
|
+
const currentConfig = getEmbeddingConfig();
|
|
2820
|
+
const moduleData = {
|
|
2821
|
+
embeddings,
|
|
2822
|
+
embeddingModel: currentConfig.model
|
|
2823
|
+
};
|
|
2824
|
+
const chunkTypes = [...new Set(parsedChunks.map((pc) => pc.type))];
|
|
2825
|
+
const exports = parsedChunks.filter((pc) => pc.isExported && pc.name).map((pc) => pc.name);
|
|
2826
|
+
const allKeywords = new Set;
|
|
2827
|
+
for (const pc of parsedChunks) {
|
|
2828
|
+
const keywords = extractKeywords(pc.content, pc.name);
|
|
2829
|
+
keywords.forEach((k) => allKeywords.add(k));
|
|
2104
2830
|
}
|
|
2105
|
-
|
|
2106
|
-
|
|
2107
|
-
|
|
2108
|
-
|
|
2109
|
-
|
|
2110
|
-
|
|
2111
|
-
|
|
2831
|
+
pathContext.keywords.forEach((k) => allKeywords.add(k));
|
|
2832
|
+
const fileSummary = {
|
|
2833
|
+
filepath,
|
|
2834
|
+
chunkCount: chunks.length,
|
|
2835
|
+
chunkTypes,
|
|
2836
|
+
keywords: Array.from(allKeywords),
|
|
2837
|
+
exports,
|
|
2838
|
+
lastModified: stats.lastModified,
|
|
2839
|
+
pathContext: {
|
|
2840
|
+
segments: pathContext.segments,
|
|
2841
|
+
layer: pathContext.layer,
|
|
2842
|
+
domain: pathContext.domain,
|
|
2843
|
+
depth: pathContext.depth
|
|
2844
|
+
}
|
|
2845
|
+
};
|
|
2846
|
+
this.pendingSummaries.set(filepath, fileSummary);
|
|
2847
|
+
return {
|
|
2848
|
+
filepath,
|
|
2849
|
+
lastModified: stats.lastModified,
|
|
2850
|
+
chunks,
|
|
2851
|
+
moduleData,
|
|
2852
|
+
references
|
|
2853
|
+
};
|
|
2112
2854
|
}
|
|
2113
|
-
|
|
2114
|
-
|
|
2855
|
+
async finalize(ctx) {
|
|
2856
|
+
const indexDir = getRaggrepDir(ctx.rootDir, ctx.config);
|
|
2857
|
+
this.symbolicIndex = new SymbolicIndex(indexDir, this.id);
|
|
2858
|
+
await this.symbolicIndex.initialize();
|
|
2859
|
+
for (const [filepath, summary] of this.pendingSummaries) {
|
|
2860
|
+
this.symbolicIndex.addFile(summary);
|
|
2861
|
+
}
|
|
2862
|
+
this.symbolicIndex.buildBM25Index();
|
|
2863
|
+
await this.symbolicIndex.save();
|
|
2864
|
+
console.log(` Symbolic index built with ${this.pendingSummaries.size} file summaries`);
|
|
2865
|
+
this.pendingSummaries.clear();
|
|
2115
2866
|
}
|
|
2116
|
-
|
|
2117
|
-
|
|
2118
|
-
|
|
2119
|
-
|
|
2120
|
-
|
|
2121
|
-
|
|
2122
|
-
|
|
2867
|
+
async search(query, ctx, options = {}) {
|
|
2868
|
+
const { topK = DEFAULT_TOP_K2, minScore = DEFAULT_MIN_SCORE2, filePatterns } = options;
|
|
2869
|
+
const indexDir = getRaggrepDir(ctx.rootDir, ctx.config);
|
|
2870
|
+
const symbolicIndex = new SymbolicIndex(indexDir, this.id);
|
|
2871
|
+
let candidateFiles;
|
|
2872
|
+
try {
|
|
2873
|
+
await symbolicIndex.initialize();
|
|
2874
|
+
const maxCandidates = topK * TIER1_CANDIDATE_MULTIPLIER;
|
|
2875
|
+
candidateFiles = symbolicIndex.findCandidates(query, maxCandidates);
|
|
2876
|
+
if (candidateFiles.length === 0) {
|
|
2877
|
+
candidateFiles = symbolicIndex.getAllFiles();
|
|
2878
|
+
}
|
|
2879
|
+
} catch {
|
|
2880
|
+
candidateFiles = await ctx.listIndexedFiles();
|
|
2881
|
+
}
|
|
2882
|
+
if (filePatterns && filePatterns.length > 0) {
|
|
2883
|
+
candidateFiles = candidateFiles.filter((filepath) => {
|
|
2884
|
+
return filePatterns.some((pattern) => {
|
|
2885
|
+
if (pattern.startsWith("*.")) {
|
|
2886
|
+
const ext = pattern.slice(1);
|
|
2887
|
+
return filepath.endsWith(ext);
|
|
2888
|
+
}
|
|
2889
|
+
return filepath.includes(pattern);
|
|
2890
|
+
});
|
|
2891
|
+
});
|
|
2892
|
+
}
|
|
2893
|
+
const queryEmbedding = await getEmbedding(query);
|
|
2894
|
+
const bm25Index = new BM25Index;
|
|
2895
|
+
const allChunksData = [];
|
|
2896
|
+
for (const filepath of candidateFiles) {
|
|
2897
|
+
const fileIndex = await ctx.loadFileIndex(filepath);
|
|
2898
|
+
if (!fileIndex)
|
|
2899
|
+
continue;
|
|
2900
|
+
const moduleData = fileIndex.moduleData;
|
|
2901
|
+
if (!moduleData?.embeddings)
|
|
2902
|
+
continue;
|
|
2903
|
+
for (let i = 0;i < fileIndex.chunks.length; i++) {
|
|
2904
|
+
const chunk = fileIndex.chunks[i];
|
|
2905
|
+
const embedding = moduleData.embeddings[i];
|
|
2906
|
+
if (!embedding)
|
|
2907
|
+
continue;
|
|
2908
|
+
allChunksData.push({
|
|
2909
|
+
filepath: fileIndex.filepath,
|
|
2910
|
+
chunk,
|
|
2911
|
+
embedding
|
|
2912
|
+
});
|
|
2913
|
+
bm25Index.addDocuments([{ id: chunk.id, content: chunk.content }]);
|
|
2914
|
+
}
|
|
2915
|
+
}
|
|
2916
|
+
const bm25Results = bm25Index.search(query, topK * 3);
|
|
2917
|
+
const bm25Scores = new Map;
|
|
2918
|
+
for (const result of bm25Results) {
|
|
2919
|
+
bm25Scores.set(result.id, normalizeScore(result.score, 3));
|
|
2920
|
+
}
|
|
2921
|
+
const queryTerms = query.toLowerCase().split(/\s+/).filter((t) => t.length > 2);
|
|
2922
|
+
const pathBoosts = new Map;
|
|
2923
|
+
for (const filepath of candidateFiles) {
|
|
2924
|
+
const summary = symbolicIndex.getFileSummary(filepath);
|
|
2925
|
+
if (summary?.pathContext) {
|
|
2926
|
+
let boost = 0;
|
|
2927
|
+
const ctx2 = summary.pathContext;
|
|
2928
|
+
if (ctx2.domain && queryTerms.some((t) => ctx2.domain.includes(t) || t.includes(ctx2.domain))) {
|
|
2929
|
+
boost += 0.1;
|
|
2123
2930
|
}
|
|
2124
|
-
if (
|
|
2125
|
-
|
|
2931
|
+
if (ctx2.layer && queryTerms.some((t) => ctx2.layer.includes(t) || t.includes(ctx2.layer))) {
|
|
2932
|
+
boost += 0.05;
|
|
2126
2933
|
}
|
|
2127
|
-
|
|
2934
|
+
const segmentMatch = ctx2.segments.some((seg) => queryTerms.some((t) => seg.toLowerCase().includes(t) || t.includes(seg.toLowerCase())));
|
|
2935
|
+
if (segmentMatch) {
|
|
2936
|
+
boost += 0.05;
|
|
2937
|
+
}
|
|
2938
|
+
pathBoosts.set(filepath, boost);
|
|
2939
|
+
}
|
|
2940
|
+
}
|
|
2941
|
+
const results = [];
|
|
2942
|
+
for (const { filepath, chunk, embedding } of allChunksData) {
|
|
2943
|
+
const semanticScore = cosineSimilarity(queryEmbedding, embedding);
|
|
2944
|
+
const bm25Score = bm25Scores.get(chunk.id) || 0;
|
|
2945
|
+
const pathBoost = pathBoosts.get(filepath) || 0;
|
|
2946
|
+
const hybridScore = SEMANTIC_WEIGHT * semanticScore + BM25_WEIGHT * bm25Score + pathBoost;
|
|
2947
|
+
if (hybridScore >= minScore || bm25Score > 0.3) {
|
|
2948
|
+
results.push({
|
|
2949
|
+
filepath,
|
|
2950
|
+
chunk,
|
|
2951
|
+
score: hybridScore,
|
|
2952
|
+
moduleId: this.id,
|
|
2953
|
+
context: {
|
|
2954
|
+
semanticScore,
|
|
2955
|
+
bm25Score,
|
|
2956
|
+
pathBoost
|
|
2957
|
+
}
|
|
2958
|
+
});
|
|
2128
2959
|
}
|
|
2129
2960
|
}
|
|
2961
|
+
results.sort((a, b) => b.score - a.score);
|
|
2962
|
+
return results.slice(0, topK);
|
|
2130
2963
|
}
|
|
2131
|
-
|
|
2132
|
-
const
|
|
2133
|
-
|
|
2134
|
-
const
|
|
2135
|
-
|
|
2136
|
-
|
|
2137
|
-
|
|
2138
|
-
|
|
2139
|
-
|
|
2140
|
-
|
|
2141
|
-
|
|
2142
|
-
|
|
2143
|
-
await fs5.writeFile(introFilePath, JSON.stringify(intro, null, 2));
|
|
2964
|
+
extractReferences(content, filepath) {
|
|
2965
|
+
const references = [];
|
|
2966
|
+
const importRegex = /import\s+.*?\s+from\s+['"]([^'"]+)['"]/g;
|
|
2967
|
+
const requireRegex = /require\s*\(\s*['"]([^'"]+)['"]\s*\)/g;
|
|
2968
|
+
let match;
|
|
2969
|
+
while ((match = importRegex.exec(content)) !== null) {
|
|
2970
|
+
const importPath = match[1];
|
|
2971
|
+
if (importPath.startsWith(".")) {
|
|
2972
|
+
const dir = path10.dirname(filepath);
|
|
2973
|
+
const resolved = path10.normalize(path10.join(dir, importPath));
|
|
2974
|
+
references.push(resolved);
|
|
2975
|
+
}
|
|
2144
2976
|
}
|
|
2145
|
-
|
|
2977
|
+
while ((match = requireRegex.exec(content)) !== null) {
|
|
2978
|
+
const importPath = match[1];
|
|
2979
|
+
if (importPath.startsWith(".")) {
|
|
2980
|
+
const dir = path10.dirname(filepath);
|
|
2981
|
+
const resolved = path10.normalize(path10.join(dir, importPath));
|
|
2982
|
+
references.push(resolved);
|
|
2983
|
+
}
|
|
2984
|
+
}
|
|
2985
|
+
return references;
|
|
2146
2986
|
}
|
|
2147
|
-
|
|
2148
|
-
|
|
2149
|
-
|
|
2150
|
-
|
|
2151
|
-
|
|
2152
|
-
|
|
2153
|
-
|
|
2154
|
-
|
|
2155
|
-
|
|
2156
|
-
|
|
2157
|
-
|
|
2987
|
+
}
|
|
2988
|
+
var DEFAULT_MIN_SCORE2 = 0.15, DEFAULT_TOP_K2 = 10, SEMANTIC_WEIGHT = 0.7, BM25_WEIGHT = 0.3, TIER1_CANDIDATE_MULTIPLIER = 3;
|
|
2989
|
+
var init_typescript = __esm(() => {
|
|
2990
|
+
init_embeddings();
|
|
2991
|
+
init_config2();
|
|
2992
|
+
init_parseCode();
|
|
2993
|
+
init_storage();
|
|
2994
|
+
init_keywords();
|
|
2995
|
+
init_keywords();
|
|
2996
|
+
});
|
|
2997
|
+
|
|
2998
|
+
// src/modules/registry.ts
|
|
2999
|
+
class ModuleRegistryImpl {
|
|
3000
|
+
modules = new Map;
|
|
3001
|
+
register(module) {
|
|
3002
|
+
if (this.modules.has(module.id)) {
|
|
3003
|
+
console.warn(`Module '${module.id}' is already registered, overwriting...`);
|
|
2158
3004
|
}
|
|
3005
|
+
this.modules.set(module.id, module);
|
|
2159
3006
|
}
|
|
2160
|
-
|
|
2161
|
-
|
|
2162
|
-
const entries = await fs5.readdir(basePath, { withFileTypes: true });
|
|
2163
|
-
for (const entry of entries) {
|
|
2164
|
-
const entryPath = path8.join(basePath, entry.name);
|
|
2165
|
-
const relativePath = prefix ? `${prefix}/${entry.name}` : entry.name;
|
|
2166
|
-
if (entry.isDirectory()) {
|
|
2167
|
-
await this.loadFilesRecursive(entryPath, relativePath);
|
|
2168
|
-
} else if (entry.name.endsWith(".json")) {
|
|
2169
|
-
const content = await fs5.readFile(entryPath, "utf-8");
|
|
2170
|
-
const intro = JSON.parse(content);
|
|
2171
|
-
this.files.set(intro.filepath, intro);
|
|
2172
|
-
}
|
|
2173
|
-
}
|
|
2174
|
-
} catch {}
|
|
3007
|
+
get(id) {
|
|
3008
|
+
return this.modules.get(id);
|
|
2175
3009
|
}
|
|
2176
|
-
|
|
2177
|
-
this.
|
|
2178
|
-
|
|
3010
|
+
list() {
|
|
3011
|
+
return Array.from(this.modules.values());
|
|
3012
|
+
}
|
|
3013
|
+
getEnabled(config) {
|
|
3014
|
+
const enabledIds = new Set(config.modules.filter((m) => m.enabled).map((m) => m.id));
|
|
3015
|
+
return this.list().filter((m) => enabledIds.has(m.id));
|
|
2179
3016
|
}
|
|
2180
3017
|
}
|
|
2181
|
-
|
|
2182
|
-
|
|
2183
|
-
|
|
2184
|
-
|
|
2185
|
-
|
|
2186
|
-
|
|
3018
|
+
async function registerBuiltInModules() {
|
|
3019
|
+
const { CoreModule: CoreModule2 } = await Promise.resolve().then(() => (init_core(), exports_core));
|
|
3020
|
+
const { TypeScriptModule: TypeScriptModule2 } = await Promise.resolve().then(() => (init_typescript(), exports_typescript));
|
|
3021
|
+
registry.register(new CoreModule2);
|
|
3022
|
+
registry.register(new TypeScriptModule2);
|
|
3023
|
+
}
|
|
3024
|
+
var registry;
|
|
3025
|
+
var init_registry = __esm(() => {
|
|
3026
|
+
registry = new ModuleRegistryImpl;
|
|
2187
3027
|
});
|
|
2188
3028
|
|
|
2189
3029
|
// src/app/indexer/watcher.ts
|
|
2190
3030
|
import { watch } from "chokidar";
|
|
2191
|
-
import * as
|
|
3031
|
+
import * as path11 from "path";
|
|
2192
3032
|
async function watchDirectory(rootDir, options = {}) {
|
|
2193
3033
|
const {
|
|
2194
3034
|
debounceMs = DEFAULT_DEBOUNCE_MS,
|
|
@@ -2199,13 +3039,19 @@ async function watchDirectory(rootDir, options = {}) {
|
|
|
2199
3039
|
onFileChange,
|
|
2200
3040
|
onError
|
|
2201
3041
|
} = options;
|
|
2202
|
-
rootDir =
|
|
3042
|
+
rootDir = path11.resolve(rootDir);
|
|
2203
3043
|
const config = await loadConfig(rootDir);
|
|
2204
|
-
const
|
|
3044
|
+
const indexLocation = getIndexLocation(rootDir);
|
|
3045
|
+
const validExtensions = new Set(config.extensions);
|
|
2205
3046
|
const ignorePatterns = [
|
|
2206
3047
|
...config.ignorePaths.map((p) => `**/${p}/**`),
|
|
2207
|
-
|
|
3048
|
+
"**/node_modules/**",
|
|
3049
|
+
"**/.git/**"
|
|
2208
3050
|
];
|
|
3051
|
+
function shouldWatchFile(filepath) {
|
|
3052
|
+
const ext = path11.extname(filepath);
|
|
3053
|
+
return validExtensions.has(ext);
|
|
3054
|
+
}
|
|
2209
3055
|
let isRunning = true;
|
|
2210
3056
|
let isIndexing = false;
|
|
2211
3057
|
let pendingChanges = new Map;
|
|
@@ -2285,7 +3131,10 @@ async function watchDirectory(rootDir, options = {}) {
|
|
|
2285
3131
|
function handleFileEvent(event, filepath) {
|
|
2286
3132
|
if (!isRunning)
|
|
2287
3133
|
return;
|
|
2288
|
-
const relativePath =
|
|
3134
|
+
const relativePath = path11.relative(rootDir, filepath);
|
|
3135
|
+
if (!shouldWatchFile(filepath)) {
|
|
3136
|
+
return;
|
|
3137
|
+
}
|
|
2289
3138
|
for (const ignorePath of config.ignorePaths) {
|
|
2290
3139
|
if (relativePath.startsWith(ignorePath) || relativePath.includes(`/${ignorePath}/`)) {
|
|
2291
3140
|
return;
|
|
@@ -2301,8 +3150,7 @@ async function watchDirectory(rootDir, options = {}) {
|
|
|
2301
3150
|
pendingChanges.set(relativePath, event);
|
|
2302
3151
|
scheduleProcessing();
|
|
2303
3152
|
}
|
|
2304
|
-
watcher = watch(
|
|
2305
|
-
cwd: rootDir,
|
|
3153
|
+
watcher = watch(rootDir, {
|
|
2306
3154
|
ignored: ignorePatterns,
|
|
2307
3155
|
persistent: true,
|
|
2308
3156
|
ignoreInitial: true,
|
|
@@ -2311,11 +3159,12 @@ async function watchDirectory(rootDir, options = {}) {
|
|
|
2311
3159
|
pollInterval: 50
|
|
2312
3160
|
},
|
|
2313
3161
|
usePolling: false,
|
|
2314
|
-
atomic: true
|
|
3162
|
+
atomic: true,
|
|
3163
|
+
depth: 99
|
|
2315
3164
|
});
|
|
2316
|
-
watcher.on("add", (filepath) => handleFileEvent("add",
|
|
2317
|
-
watcher.on("change", (filepath) => handleFileEvent("change",
|
|
2318
|
-
watcher.on("unlink", (filepath) => handleFileEvent("unlink",
|
|
3165
|
+
watcher.on("add", (filepath) => handleFileEvent("add", filepath));
|
|
3166
|
+
watcher.on("change", (filepath) => handleFileEvent("change", filepath));
|
|
3167
|
+
watcher.on("unlink", (filepath) => handleFileEvent("unlink", filepath));
|
|
2319
3168
|
watcher.on("error", (error) => {
|
|
2320
3169
|
const err = error instanceof Error ? error : new Error(String(error));
|
|
2321
3170
|
console.error("[Watch] Watcher error:", err);
|
|
@@ -2323,9 +3172,9 @@ async function watchDirectory(rootDir, options = {}) {
|
|
|
2323
3172
|
onError(err);
|
|
2324
3173
|
}
|
|
2325
3174
|
});
|
|
2326
|
-
await new Promise((
|
|
3175
|
+
await new Promise((resolve3) => {
|
|
2327
3176
|
watcher.on("ready", () => {
|
|
2328
|
-
|
|
3177
|
+
resolve3();
|
|
2329
3178
|
});
|
|
2330
3179
|
});
|
|
2331
3180
|
return {
|
|
@@ -2359,11 +3208,13 @@ __export(exports_indexer, {
|
|
|
2359
3208
|
});
|
|
2360
3209
|
import { glob } from "glob";
|
|
2361
3210
|
import * as fs6 from "fs/promises";
|
|
2362
|
-
import * as
|
|
3211
|
+
import * as path12 from "path";
|
|
2363
3212
|
async function indexDirectory(rootDir, options = {}) {
|
|
2364
3213
|
const verbose = options.verbose ?? false;
|
|
2365
|
-
rootDir =
|
|
3214
|
+
rootDir = path12.resolve(rootDir);
|
|
3215
|
+
const location = getIndexLocation(rootDir);
|
|
2366
3216
|
console.log(`Indexing directory: ${rootDir}`);
|
|
3217
|
+
console.log(`Index location: ${location.indexDir}`);
|
|
2367
3218
|
const config = await loadConfig(rootDir);
|
|
2368
3219
|
const introspection = new IntrospectionIndex(rootDir);
|
|
2369
3220
|
await introspection.initialize();
|
|
@@ -2405,11 +3256,11 @@ async function indexDirectory(rootDir, options = {}) {
|
|
|
2405
3256
|
rootDir,
|
|
2406
3257
|
config,
|
|
2407
3258
|
readFile: async (filepath) => {
|
|
2408
|
-
const fullPath =
|
|
3259
|
+
const fullPath = path12.isAbsolute(filepath) ? filepath : path12.join(rootDir, filepath);
|
|
2409
3260
|
return fs6.readFile(fullPath, "utf-8");
|
|
2410
3261
|
},
|
|
2411
3262
|
getFileStats: async (filepath) => {
|
|
2412
|
-
const fullPath =
|
|
3263
|
+
const fullPath = path12.isAbsolute(filepath) ? filepath : path12.join(rootDir, filepath);
|
|
2413
3264
|
const stats = await fs6.stat(fullPath);
|
|
2414
3265
|
return { lastModified: stats.mtime.toISOString() };
|
|
2415
3266
|
}
|
|
@@ -2434,18 +3285,18 @@ async function indexWithModule(rootDir, files, module, config, verbose, introspe
|
|
|
2434
3285
|
rootDir,
|
|
2435
3286
|
config,
|
|
2436
3287
|
readFile: async (filepath) => {
|
|
2437
|
-
const fullPath =
|
|
3288
|
+
const fullPath = path12.isAbsolute(filepath) ? filepath : path12.join(rootDir, filepath);
|
|
2438
3289
|
return fs6.readFile(fullPath, "utf-8");
|
|
2439
3290
|
},
|
|
2440
3291
|
getFileStats: async (filepath) => {
|
|
2441
|
-
const fullPath =
|
|
3292
|
+
const fullPath = path12.isAbsolute(filepath) ? filepath : path12.join(rootDir, filepath);
|
|
2442
3293
|
const stats = await fs6.stat(fullPath);
|
|
2443
3294
|
return { lastModified: stats.mtime.toISOString() };
|
|
2444
3295
|
},
|
|
2445
3296
|
getIntrospection: (filepath) => introspection.getFile(filepath)
|
|
2446
3297
|
};
|
|
2447
3298
|
for (const filepath of files) {
|
|
2448
|
-
const relativePath =
|
|
3299
|
+
const relativePath = path12.relative(rootDir, filepath);
|
|
2449
3300
|
try {
|
|
2450
3301
|
const stats = await fs6.stat(filepath);
|
|
2451
3302
|
const lastModified = stats.mtime.toISOString();
|
|
@@ -2515,13 +3366,13 @@ async function loadModuleManifest(rootDir, moduleId, config) {
|
|
|
2515
3366
|
}
|
|
2516
3367
|
async function writeModuleManifest(rootDir, moduleId, manifest, config) {
|
|
2517
3368
|
const manifestPath = getModuleManifestPath(rootDir, moduleId, config);
|
|
2518
|
-
await fs6.mkdir(
|
|
3369
|
+
await fs6.mkdir(path12.dirname(manifestPath), { recursive: true });
|
|
2519
3370
|
await fs6.writeFile(manifestPath, JSON.stringify(manifest, null, 2));
|
|
2520
3371
|
}
|
|
2521
3372
|
async function writeFileIndex(rootDir, moduleId, filepath, fileIndex, config) {
|
|
2522
3373
|
const indexPath = getModuleIndexPath(rootDir, moduleId, config);
|
|
2523
|
-
const indexFilePath =
|
|
2524
|
-
await fs6.mkdir(
|
|
3374
|
+
const indexFilePath = path12.join(indexPath, filepath.replace(/\.[^.]+$/, ".json"));
|
|
3375
|
+
await fs6.mkdir(path12.dirname(indexFilePath), { recursive: true });
|
|
2525
3376
|
await fs6.writeFile(indexFilePath, JSON.stringify(fileIndex, null, 2));
|
|
2526
3377
|
}
|
|
2527
3378
|
async function updateGlobalManifest(rootDir, modules, config) {
|
|
@@ -2531,12 +3382,12 @@ async function updateGlobalManifest(rootDir, modules, config) {
|
|
|
2531
3382
|
lastUpdated: new Date().toISOString(),
|
|
2532
3383
|
modules: modules.map((m) => m.id)
|
|
2533
3384
|
};
|
|
2534
|
-
await fs6.mkdir(
|
|
3385
|
+
await fs6.mkdir(path12.dirname(manifestPath), { recursive: true });
|
|
2535
3386
|
await fs6.writeFile(manifestPath, JSON.stringify(manifest, null, 2));
|
|
2536
3387
|
}
|
|
2537
3388
|
async function cleanupIndex(rootDir, options = {}) {
|
|
2538
3389
|
const verbose = options.verbose ?? false;
|
|
2539
|
-
rootDir =
|
|
3390
|
+
rootDir = path12.resolve(rootDir);
|
|
2540
3391
|
console.log(`Cleaning up index in: ${rootDir}`);
|
|
2541
3392
|
const config = await loadConfig(rootDir);
|
|
2542
3393
|
await registerBuiltInModules();
|
|
@@ -2566,7 +3417,7 @@ async function cleanupModuleIndex(rootDir, moduleId, config, verbose) {
|
|
|
2566
3417
|
const filesToRemove = [];
|
|
2567
3418
|
const updatedFiles = {};
|
|
2568
3419
|
for (const [filepath, entry] of Object.entries(manifest.files)) {
|
|
2569
|
-
const fullPath =
|
|
3420
|
+
const fullPath = path12.join(rootDir, filepath);
|
|
2570
3421
|
try {
|
|
2571
3422
|
await fs6.access(fullPath);
|
|
2572
3423
|
updatedFiles[filepath] = entry;
|
|
@@ -2580,7 +3431,7 @@ async function cleanupModuleIndex(rootDir, moduleId, config, verbose) {
|
|
|
2580
3431
|
}
|
|
2581
3432
|
}
|
|
2582
3433
|
for (const filepath of filesToRemove) {
|
|
2583
|
-
const indexFilePath =
|
|
3434
|
+
const indexFilePath = path12.join(indexPath, filepath.replace(/\.[^.]+$/, ".json"));
|
|
2584
3435
|
try {
|
|
2585
3436
|
await fs6.unlink(indexFilePath);
|
|
2586
3437
|
} catch {}
|
|
@@ -2596,7 +3447,7 @@ async function cleanupEmptyDirectories(dir) {
|
|
|
2596
3447
|
const entries = await fs6.readdir(dir, { withFileTypes: true });
|
|
2597
3448
|
for (const entry of entries) {
|
|
2598
3449
|
if (entry.isDirectory()) {
|
|
2599
|
-
const subDir =
|
|
3450
|
+
const subDir = path12.join(dir, entry.name);
|
|
2600
3451
|
await cleanupEmptyDirectories(subDir);
|
|
2601
3452
|
}
|
|
2602
3453
|
}
|
|
@@ -2611,9 +3462,10 @@ async function cleanupEmptyDirectories(dir) {
|
|
|
2611
3462
|
}
|
|
2612
3463
|
}
|
|
2613
3464
|
async function getIndexStatus(rootDir) {
|
|
2614
|
-
rootDir =
|
|
3465
|
+
rootDir = path12.resolve(rootDir);
|
|
2615
3466
|
const config = await loadConfig(rootDir);
|
|
2616
|
-
const
|
|
3467
|
+
const location = getIndexLocation(rootDir);
|
|
3468
|
+
const indexDir = location.indexDir;
|
|
2617
3469
|
const status = {
|
|
2618
3470
|
exists: false,
|
|
2619
3471
|
rootDir,
|
|
@@ -2646,7 +3498,7 @@ async function getIndexStatus(rootDir) {
|
|
|
2646
3498
|
}
|
|
2647
3499
|
} catch {
|
|
2648
3500
|
try {
|
|
2649
|
-
const entries = await fs6.readdir(
|
|
3501
|
+
const entries = await fs6.readdir(path12.join(indexDir, "index"));
|
|
2650
3502
|
if (entries.length > 0) {
|
|
2651
3503
|
status.exists = true;
|
|
2652
3504
|
for (const entry of entries) {
|
|
@@ -2680,9 +3532,9 @@ __export(exports_search, {
|
|
|
2680
3532
|
formatSearchResults: () => formatSearchResults
|
|
2681
3533
|
});
|
|
2682
3534
|
import * as fs7 from "fs/promises";
|
|
2683
|
-
import * as
|
|
3535
|
+
import * as path13 from "path";
|
|
2684
3536
|
async function search(rootDir, query, options = {}) {
|
|
2685
|
-
rootDir =
|
|
3537
|
+
rootDir = path13.resolve(rootDir);
|
|
2686
3538
|
console.log(`Searching for: "${query}"`);
|
|
2687
3539
|
const config = await loadConfig(rootDir);
|
|
2688
3540
|
await registerBuiltInModules();
|
|
@@ -2723,7 +3575,7 @@ function createSearchContext(rootDir, moduleId, config) {
|
|
|
2723
3575
|
config,
|
|
2724
3576
|
loadFileIndex: async (filepath) => {
|
|
2725
3577
|
const hasExtension = /\.[^./]+$/.test(filepath);
|
|
2726
|
-
const indexFilePath = hasExtension ?
|
|
3578
|
+
const indexFilePath = hasExtension ? path13.join(indexPath, filepath.replace(/\.[^.]+$/, ".json")) : path13.join(indexPath, filepath + ".json");
|
|
2727
3579
|
try {
|
|
2728
3580
|
const content = await fs7.readFile(indexFilePath, "utf-8");
|
|
2729
3581
|
return JSON.parse(content);
|
|
@@ -2735,7 +3587,7 @@ function createSearchContext(rootDir, moduleId, config) {
|
|
|
2735
3587
|
const files = [];
|
|
2736
3588
|
await traverseDirectory(indexPath, files, indexPath);
|
|
2737
3589
|
return files.filter((f) => f.endsWith(".json") && !f.endsWith("manifest.json")).map((f) => {
|
|
2738
|
-
const relative4 =
|
|
3590
|
+
const relative4 = path13.relative(indexPath, f);
|
|
2739
3591
|
return relative4.replace(/\.json$/, "");
|
|
2740
3592
|
});
|
|
2741
3593
|
}
|
|
@@ -2745,7 +3597,7 @@ async function traverseDirectory(dir, files, basePath) {
|
|
|
2745
3597
|
try {
|
|
2746
3598
|
const entries = await fs7.readdir(dir, { withFileTypes: true });
|
|
2747
3599
|
for (const entry of entries) {
|
|
2748
|
-
const fullPath =
|
|
3600
|
+
const fullPath = path13.join(dir, entry.name);
|
|
2749
3601
|
if (entry.isDirectory()) {
|
|
2750
3602
|
await traverseDirectory(fullPath, files, basePath);
|
|
2751
3603
|
} else if (entry.isFile()) {
|
|
@@ -2802,10 +3654,77 @@ var init_search = __esm(() => {
|
|
|
2802
3654
|
|
|
2803
3655
|
// src/app/cli/main.ts
|
|
2804
3656
|
init_embeddings();
|
|
2805
|
-
|
|
2806
|
-
var
|
|
2807
|
-
|
|
2808
|
-
|
|
3657
|
+
// package.json
|
|
3658
|
+
var package_default = {
|
|
3659
|
+
name: "raggrep",
|
|
3660
|
+
version: "0.1.6",
|
|
3661
|
+
description: "Local filesystem-based RAG system for codebases - semantic search using local embeddings",
|
|
3662
|
+
type: "module",
|
|
3663
|
+
main: "./dist/index.js",
|
|
3664
|
+
types: "./dist/index.d.ts",
|
|
3665
|
+
exports: {
|
|
3666
|
+
".": {
|
|
3667
|
+
import: "./dist/index.js",
|
|
3668
|
+
types: "./dist/index.d.ts"
|
|
3669
|
+
}
|
|
3670
|
+
},
|
|
3671
|
+
bin: {
|
|
3672
|
+
raggrep: "dist/cli/main.js"
|
|
3673
|
+
},
|
|
3674
|
+
files: [
|
|
3675
|
+
"dist",
|
|
3676
|
+
"README.md",
|
|
3677
|
+
"LICENSE"
|
|
3678
|
+
],
|
|
3679
|
+
scripts: {
|
|
3680
|
+
build: "bun run build:clean && bun run build:bundle && bun run build:types && bun run build:shebang",
|
|
3681
|
+
"build:clean": "rm -rf dist",
|
|
3682
|
+
"build:bundle": "bun build src/index.ts --outdir dist --target node --sourcemap=external --external '@xenova/transformers' --external 'glob' --external 'typescript' --external 'chokidar' && bun build src/app/cli/main.ts --outdir dist/cli --target node --sourcemap=external --external '@xenova/transformers' --external 'glob' --external 'typescript' --external 'chokidar'",
|
|
3683
|
+
"build:types": "tsc --emitDeclarationOnly --outDir dist",
|
|
3684
|
+
"build:shebang": "echo '#!/usr/bin/env node' | cat - dist/cli/main.js > temp && mv temp dist/cli/main.js && chmod +x dist/cli/main.js",
|
|
3685
|
+
prepublishOnly: "bun run build",
|
|
3686
|
+
raggrep: "bun run src/app/cli/main.ts",
|
|
3687
|
+
test: "bun test",
|
|
3688
|
+
dev: "bun run src/app/cli/main.ts"
|
|
3689
|
+
},
|
|
3690
|
+
keywords: [
|
|
3691
|
+
"rag",
|
|
3692
|
+
"search",
|
|
3693
|
+
"semantic-search",
|
|
3694
|
+
"embeddings",
|
|
3695
|
+
"codebase",
|
|
3696
|
+
"local",
|
|
3697
|
+
"ai",
|
|
3698
|
+
"code-search",
|
|
3699
|
+
"transformers"
|
|
3700
|
+
],
|
|
3701
|
+
author: "",
|
|
3702
|
+
license: "MIT",
|
|
3703
|
+
repository: {
|
|
3704
|
+
type: "git",
|
|
3705
|
+
url: "git+https://github.com/conradkoh/raggrep.git"
|
|
3706
|
+
},
|
|
3707
|
+
bugs: {
|
|
3708
|
+
url: "https://github.com/conradkoh/raggrep/issues"
|
|
3709
|
+
},
|
|
3710
|
+
homepage: "https://github.com/conradkoh/raggrep#readme",
|
|
3711
|
+
engines: {
|
|
3712
|
+
node: ">=18.0.0"
|
|
3713
|
+
},
|
|
3714
|
+
dependencies: {
|
|
3715
|
+
"@xenova/transformers": "^2.17.0",
|
|
3716
|
+
chokidar: "^5.0.0",
|
|
3717
|
+
glob: "^10.0.0",
|
|
3718
|
+
typescript: "^5.0.0"
|
|
3719
|
+
},
|
|
3720
|
+
devDependencies: {
|
|
3721
|
+
"@types/bun": "latest",
|
|
3722
|
+
"@types/node": "^20.0.0"
|
|
3723
|
+
}
|
|
3724
|
+
};
|
|
3725
|
+
|
|
3726
|
+
// src/app/cli/main.ts
|
|
3727
|
+
var VERSION = package_default.version;
|
|
2809
3728
|
var args = process.argv.slice(2);
|
|
2810
3729
|
var command = args[0];
|
|
2811
3730
|
if (command === "--version" || command === "-v") {
|
|
@@ -3173,4 +4092,4 @@ Run 'raggrep <command> --help' for more information.
|
|
|
3173
4092
|
}
|
|
3174
4093
|
main();
|
|
3175
4094
|
|
|
3176
|
-
//# debugId=
|
|
4095
|
+
//# debugId=03A02811A6080C5964756E2164756E21
|