raggrep 0.1.5 → 0.1.7
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/app/indexer/index.d.ts +2 -2
- package/dist/cli/main.js +1964 -918
- package/dist/cli/main.js.map +21 -14
- package/dist/domain/entities/conventions.d.ts +63 -0
- package/dist/domain/entities/index.d.ts +2 -0
- package/dist/domain/services/conventions/configFiles.d.ts +10 -0
- package/dist/domain/services/conventions/conventions.test.d.ts +4 -0
- package/dist/domain/services/conventions/entryPoints.d.ts +10 -0
- package/dist/domain/services/conventions/frameworks/convex.d.ts +11 -0
- package/dist/domain/services/conventions/frameworks/index.d.ts +22 -0
- package/dist/domain/services/conventions/frameworks/nextjs.d.ts +10 -0
- package/dist/domain/services/conventions/index.d.ts +39 -0
- package/dist/domain/services/introspection.d.ts +31 -0
- package/dist/index.js +1452 -416
- package/dist/index.js.map +20 -14
- package/dist/infrastructure/config/configLoader.d.ts +22 -3
- package/dist/infrastructure/config/index.d.ts +1 -1
- package/dist/{introspection/index.d.ts → infrastructure/introspection/IntrospectionIndex.d.ts} +3 -14
- package/dist/infrastructure/introspection/index.d.ts +9 -0
- package/dist/{introspection → infrastructure/introspection}/projectDetector.d.ts +3 -12
- package/dist/tests/integration.test.d.ts +9 -0
- package/dist/types.d.ts +4 -4
- package/package.json +1 -1
- package/dist/introspection/fileIntrospector.d.ts +0 -14
- /package/dist/{introspection/types.d.ts → domain/entities/introspection.d.ts} +0 -0
- /package/dist/{introspection → domain/services}/introspection.test.d.ts +0 -0
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,405 +429,1712 @@ 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
|
-
const
|
|
414
|
-
|
|
415
|
-
`);
|
|
416
|
-
for (const { type, pattern, exported } of SYMBOL_PATTERNS) {
|
|
417
|
-
pattern.lastIndex = 0;
|
|
418
|
-
let match;
|
|
419
|
-
while ((match = pattern.exec(content)) !== null) {
|
|
420
|
-
const name = match[1];
|
|
421
|
-
const symbolKey = `${name}:${type}`;
|
|
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
|
-
});
|
|
434
|
-
}
|
|
435
|
-
}
|
|
436
|
-
return symbols.sort((a, b) => a.line - b.line);
|
|
432
|
+
// src/domain/services/conventions/entryPoints.ts
|
|
433
|
+
import * as path3 from "path";
|
|
434
|
+
function getParentFolder(filepath) {
|
|
435
|
+
const dir = path3.dirname(filepath);
|
|
436
|
+
return path3.basename(dir);
|
|
437
437
|
}
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
438
|
+
var entryPointConventions;
|
|
439
|
+
var init_entryPoints = __esm(() => {
|
|
440
|
+
entryPointConventions = [
|
|
441
|
+
{
|
|
442
|
+
id: "index-file",
|
|
443
|
+
name: "Index/Barrel File",
|
|
444
|
+
description: "Module entry point that typically re-exports from other files",
|
|
445
|
+
category: "entry-point",
|
|
446
|
+
match: (filepath, filename) => {
|
|
447
|
+
return /^index\.(ts|tsx|js|jsx|mjs|cjs)$/.test(filename);
|
|
448
|
+
},
|
|
449
|
+
keywords: ["entry", "barrel", "exports", "module"],
|
|
450
|
+
dynamicKeywords: (filepath) => {
|
|
451
|
+
const parent = getParentFolder(filepath);
|
|
452
|
+
if (["src", "lib", "dist", "build", ".", ""].includes(parent)) {
|
|
453
|
+
return [];
|
|
454
|
+
}
|
|
455
|
+
return [parent.toLowerCase()];
|
|
456
|
+
}
|
|
457
|
+
},
|
|
458
|
+
{
|
|
459
|
+
id: "main-file",
|
|
460
|
+
name: "Main Entry Point",
|
|
461
|
+
description: "Application main entry point",
|
|
462
|
+
category: "entry-point",
|
|
463
|
+
match: (filepath, filename) => {
|
|
464
|
+
return /^main\.(ts|tsx|js|jsx|mjs|cjs)$/.test(filename);
|
|
465
|
+
},
|
|
466
|
+
keywords: ["entry", "main", "entrypoint", "bootstrap", "startup"]
|
|
467
|
+
},
|
|
468
|
+
{
|
|
469
|
+
id: "app-component",
|
|
470
|
+
name: "Root App Component",
|
|
471
|
+
description: "Root application component (React, Vue, etc.)",
|
|
472
|
+
category: "entry-point",
|
|
473
|
+
match: (filepath, filename) => {
|
|
474
|
+
return /^App\.(tsx|jsx|vue|svelte)$/.test(filename);
|
|
475
|
+
},
|
|
476
|
+
keywords: ["root", "app", "application", "component", "main"]
|
|
477
|
+
},
|
|
478
|
+
{
|
|
479
|
+
id: "deno-mod",
|
|
480
|
+
name: "Deno Module Entry",
|
|
481
|
+
description: "Deno module entry point",
|
|
482
|
+
category: "entry-point",
|
|
483
|
+
match: (filepath, filename) => {
|
|
484
|
+
return filename === "mod.ts";
|
|
485
|
+
},
|
|
486
|
+
keywords: ["entry", "module", "deno", "exports"],
|
|
487
|
+
dynamicKeywords: (filepath) => {
|
|
488
|
+
const parent = getParentFolder(filepath);
|
|
489
|
+
if (["src", "lib", ".", ""].includes(parent)) {
|
|
490
|
+
return [];
|
|
491
|
+
}
|
|
492
|
+
return [parent.toLowerCase()];
|
|
493
|
+
}
|
|
494
|
+
},
|
|
495
|
+
{
|
|
496
|
+
id: "python-init",
|
|
497
|
+
name: "Python Package Init",
|
|
498
|
+
description: "Python package initialization file",
|
|
499
|
+
category: "entry-point",
|
|
500
|
+
match: (filepath, filename) => {
|
|
501
|
+
return filename === "__init__.py";
|
|
502
|
+
},
|
|
503
|
+
keywords: ["entry", "package", "init", "python", "module"],
|
|
504
|
+
dynamicKeywords: (filepath) => {
|
|
505
|
+
const parent = getParentFolder(filepath);
|
|
506
|
+
if (["src", "lib", ".", ""].includes(parent)) {
|
|
507
|
+
return [];
|
|
508
|
+
}
|
|
509
|
+
return [parent.toLowerCase()];
|
|
510
|
+
}
|
|
511
|
+
},
|
|
512
|
+
{
|
|
513
|
+
id: "rust-lib",
|
|
514
|
+
name: "Rust Library Entry",
|
|
515
|
+
description: "Rust library crate entry point",
|
|
516
|
+
category: "entry-point",
|
|
517
|
+
match: (filepath, filename) => {
|
|
518
|
+
return filename === "lib.rs" || filename === "main.rs";
|
|
519
|
+
},
|
|
520
|
+
keywords: ["entry", "crate", "rust", "module"]
|
|
521
|
+
},
|
|
522
|
+
{
|
|
523
|
+
id: "go-main",
|
|
524
|
+
name: "Go Main Entry",
|
|
525
|
+
description: "Go application main entry point",
|
|
526
|
+
category: "entry-point",
|
|
527
|
+
match: (filepath, filename) => {
|
|
528
|
+
return filename === "main.go";
|
|
529
|
+
},
|
|
530
|
+
keywords: ["entry", "main", "go", "golang", "entrypoint"],
|
|
531
|
+
dynamicKeywords: (filepath) => {
|
|
532
|
+
const parent = getParentFolder(filepath);
|
|
533
|
+
if (parent && !["cmd", "src", ".", ""].includes(parent)) {
|
|
534
|
+
return [parent.toLowerCase()];
|
|
535
|
+
}
|
|
536
|
+
return [];
|
|
537
|
+
}
|
|
538
|
+
},
|
|
539
|
+
{
|
|
540
|
+
id: "python-main",
|
|
541
|
+
name: "Python Main Module",
|
|
542
|
+
description: "Python package main entry point",
|
|
543
|
+
category: "entry-point",
|
|
544
|
+
match: (filepath, filename) => {
|
|
545
|
+
return filename === "__main__.py";
|
|
546
|
+
},
|
|
547
|
+
keywords: ["entry", "main", "python", "entrypoint", "cli"],
|
|
548
|
+
dynamicKeywords: (filepath) => {
|
|
549
|
+
const parent = getParentFolder(filepath);
|
|
550
|
+
if (["src", "lib", ".", ""].includes(parent)) {
|
|
551
|
+
return [];
|
|
552
|
+
}
|
|
553
|
+
return [parent.toLowerCase()];
|
|
446
554
|
}
|
|
555
|
+
},
|
|
556
|
+
{
|
|
557
|
+
id: "python-app",
|
|
558
|
+
name: "Python App Entry",
|
|
559
|
+
description: "Common Python application entry points",
|
|
560
|
+
category: "entry-point",
|
|
561
|
+
match: (filepath, filename) => {
|
|
562
|
+
return filename === "app.py" || filename === "main.py" || filename === "run.py";
|
|
563
|
+
},
|
|
564
|
+
keywords: ["entry", "main", "python", "app", "entrypoint"]
|
|
565
|
+
},
|
|
566
|
+
{
|
|
567
|
+
id: "python-manage",
|
|
568
|
+
name: "Django Manage",
|
|
569
|
+
description: "Django management script",
|
|
570
|
+
category: "entry-point",
|
|
571
|
+
match: (filepath, filename) => {
|
|
572
|
+
return filename === "manage.py";
|
|
573
|
+
},
|
|
574
|
+
keywords: ["entry", "django", "python", "manage", "cli", "admin"]
|
|
575
|
+
},
|
|
576
|
+
{
|
|
577
|
+
id: "python-wsgi",
|
|
578
|
+
name: "Python WSGI Entry",
|
|
579
|
+
description: "Python WSGI application entry point",
|
|
580
|
+
category: "entry-point",
|
|
581
|
+
match: (filepath, filename) => {
|
|
582
|
+
return filename === "wsgi.py" || filename === "asgi.py";
|
|
583
|
+
},
|
|
584
|
+
keywords: ["entry", "wsgi", "asgi", "python", "server", "web"]
|
|
447
585
|
}
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
var
|
|
453
|
-
|
|
586
|
+
];
|
|
587
|
+
});
|
|
588
|
+
|
|
589
|
+
// src/domain/services/conventions/configFiles.ts
|
|
590
|
+
var configFileConventions;
|
|
591
|
+
var init_configFiles = __esm(() => {
|
|
592
|
+
configFileConventions = [
|
|
454
593
|
{
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
594
|
+
id: "package-json",
|
|
595
|
+
name: "Package.json",
|
|
596
|
+
description: "Node.js package manifest",
|
|
597
|
+
category: "configuration",
|
|
598
|
+
match: (filepath, filename) => filename === "package.json",
|
|
599
|
+
keywords: ["package", "dependencies", "npm", "scripts", "manifest", "node"]
|
|
458
600
|
},
|
|
459
601
|
{
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
602
|
+
id: "pnpm-workspace",
|
|
603
|
+
name: "PNPM Workspace",
|
|
604
|
+
description: "PNPM monorepo workspace configuration",
|
|
605
|
+
category: "configuration",
|
|
606
|
+
match: (filepath, filename) => filename === "pnpm-workspace.yaml" || filename === "pnpm-workspace.yml",
|
|
607
|
+
keywords: ["workspace", "monorepo", "pnpm", "packages"]
|
|
463
608
|
},
|
|
464
609
|
{
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
610
|
+
id: "yarn-lock",
|
|
611
|
+
name: "Yarn Lock",
|
|
612
|
+
description: "Yarn dependency lock file",
|
|
613
|
+
category: "configuration",
|
|
614
|
+
match: (filepath, filename) => filename === "yarn.lock",
|
|
615
|
+
keywords: ["dependencies", "lock", "yarn", "versions"]
|
|
468
616
|
},
|
|
469
617
|
{
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
618
|
+
id: "package-lock",
|
|
619
|
+
name: "Package Lock",
|
|
620
|
+
description: "NPM dependency lock file",
|
|
621
|
+
category: "configuration",
|
|
622
|
+
match: (filepath, filename) => filename === "package-lock.json",
|
|
623
|
+
keywords: ["dependencies", "lock", "npm", "versions"]
|
|
473
624
|
},
|
|
474
625
|
{
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
626
|
+
id: "bun-lockb",
|
|
627
|
+
name: "Bun Lock",
|
|
628
|
+
description: "Bun dependency lock file",
|
|
629
|
+
category: "configuration",
|
|
630
|
+
match: (filepath, filename) => filename === "bun.lockb" || filename === "bun.lock",
|
|
631
|
+
keywords: ["dependencies", "lock", "bun", "versions"]
|
|
478
632
|
},
|
|
479
633
|
{
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
634
|
+
id: "go-mod",
|
|
635
|
+
name: "Go Module",
|
|
636
|
+
description: "Go module definition file",
|
|
637
|
+
category: "configuration",
|
|
638
|
+
match: (filepath, filename) => filename === "go.mod",
|
|
639
|
+
keywords: [
|
|
640
|
+
"go",
|
|
641
|
+
"golang",
|
|
642
|
+
"module",
|
|
643
|
+
"dependencies",
|
|
644
|
+
"package",
|
|
645
|
+
"workspace"
|
|
646
|
+
]
|
|
483
647
|
},
|
|
484
648
|
{
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
649
|
+
id: "go-sum",
|
|
650
|
+
name: "Go Sum",
|
|
651
|
+
description: "Go module checksum file",
|
|
652
|
+
category: "configuration",
|
|
653
|
+
match: (filepath, filename) => filename === "go.sum",
|
|
654
|
+
keywords: ["go", "golang", "dependencies", "checksum", "lock", "versions"]
|
|
488
655
|
},
|
|
489
656
|
{
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
657
|
+
id: "go-work",
|
|
658
|
+
name: "Go Workspace",
|
|
659
|
+
description: "Go workspace configuration for multi-module development",
|
|
660
|
+
category: "configuration",
|
|
661
|
+
match: (filepath, filename) => filename === "go.work" || filename === "go.work.sum",
|
|
662
|
+
keywords: ["go", "golang", "workspace", "monorepo", "modules"]
|
|
493
663
|
},
|
|
494
664
|
{
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
665
|
+
id: "makefile",
|
|
666
|
+
name: "Makefile",
|
|
667
|
+
description: "Make build automation file",
|
|
668
|
+
category: "build",
|
|
669
|
+
match: (filepath, filename) => filename === "Makefile" || filename === "makefile" || filename === "GNUmakefile",
|
|
670
|
+
keywords: ["make", "build", "automation", "tasks", "compile"]
|
|
498
671
|
},
|
|
499
672
|
{
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
673
|
+
id: "requirements-txt",
|
|
674
|
+
name: "Python Requirements",
|
|
675
|
+
description: "Python pip requirements file",
|
|
676
|
+
category: "configuration",
|
|
677
|
+
match: (filepath, filename) => filename === "requirements.txt" || filename.startsWith("requirements-") || filename.startsWith("requirements_"),
|
|
678
|
+
keywords: ["python", "pip", "dependencies", "packages", "requirements"]
|
|
503
679
|
},
|
|
504
680
|
{
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
681
|
+
id: "pyproject-toml",
|
|
682
|
+
name: "Python Project",
|
|
683
|
+
description: "Python project configuration (PEP 518/621)",
|
|
684
|
+
category: "configuration",
|
|
685
|
+
match: (filepath, filename) => filename === "pyproject.toml",
|
|
686
|
+
keywords: [
|
|
687
|
+
"python",
|
|
688
|
+
"project",
|
|
689
|
+
"config",
|
|
690
|
+
"poetry",
|
|
691
|
+
"build",
|
|
692
|
+
"dependencies",
|
|
693
|
+
"package"
|
|
694
|
+
]
|
|
508
695
|
},
|
|
509
696
|
{
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
697
|
+
id: "setup-py",
|
|
698
|
+
name: "Python Setup",
|
|
699
|
+
description: "Python package setup script",
|
|
700
|
+
category: "configuration",
|
|
701
|
+
match: (filepath, filename) => filename === "setup.py",
|
|
702
|
+
keywords: ["python", "setup", "package", "install", "distribution"]
|
|
513
703
|
},
|
|
514
704
|
{
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
705
|
+
id: "setup-cfg",
|
|
706
|
+
name: "Python Setup Config",
|
|
707
|
+
description: "Python setup configuration file",
|
|
708
|
+
category: "configuration",
|
|
709
|
+
match: (filepath, filename) => filename === "setup.cfg",
|
|
710
|
+
keywords: ["python", "setup", "config", "package", "metadata"]
|
|
518
711
|
},
|
|
519
712
|
{
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
713
|
+
id: "pipfile",
|
|
714
|
+
name: "Pipfile",
|
|
715
|
+
description: "Pipenv dependency file",
|
|
716
|
+
category: "configuration",
|
|
717
|
+
match: (filepath, filename) => filename === "Pipfile" || filename === "Pipfile.lock",
|
|
718
|
+
keywords: ["python", "pipenv", "dependencies", "packages", "virtualenv"]
|
|
523
719
|
},
|
|
524
720
|
{
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
721
|
+
id: "poetry-lock",
|
|
722
|
+
name: "Poetry Lock",
|
|
723
|
+
description: "Poetry dependency lock file",
|
|
724
|
+
category: "configuration",
|
|
725
|
+
match: (filepath, filename) => filename === "poetry.lock",
|
|
726
|
+
keywords: ["python", "poetry", "dependencies", "lock", "versions"]
|
|
528
727
|
},
|
|
529
728
|
{
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
729
|
+
id: "tox-ini",
|
|
730
|
+
name: "Tox Config",
|
|
731
|
+
description: "Tox testing automation configuration",
|
|
732
|
+
category: "test",
|
|
733
|
+
match: (filepath, filename) => filename === "tox.ini",
|
|
734
|
+
keywords: ["python", "tox", "testing", "automation", "environments"]
|
|
533
735
|
},
|
|
534
736
|
{
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
737
|
+
id: "pytest-ini",
|
|
738
|
+
name: "Pytest Config",
|
|
739
|
+
description: "Pytest configuration file",
|
|
740
|
+
category: "test",
|
|
741
|
+
match: (filepath, filename) => filename === "pytest.ini" || filename === "conftest.py",
|
|
742
|
+
keywords: ["python", "pytest", "testing", "test", "fixtures"]
|
|
538
743
|
},
|
|
539
744
|
{
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
745
|
+
id: "mypy-ini",
|
|
746
|
+
name: "Mypy Config",
|
|
747
|
+
description: "Mypy type checker configuration",
|
|
748
|
+
category: "configuration",
|
|
749
|
+
match: (filepath, filename) => filename === "mypy.ini" || filename === ".mypy.ini",
|
|
750
|
+
keywords: ["python", "mypy", "types", "type checking", "static analysis"]
|
|
543
751
|
},
|
|
544
752
|
{
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
753
|
+
id: "flake8",
|
|
754
|
+
name: "Flake8 Config",
|
|
755
|
+
description: "Flake8 linter configuration",
|
|
756
|
+
category: "configuration",
|
|
757
|
+
match: (filepath, filename) => filename === ".flake8",
|
|
758
|
+
keywords: ["python", "flake8", "linting", "lint", "style"]
|
|
548
759
|
},
|
|
549
760
|
{
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
761
|
+
id: "pylintrc",
|
|
762
|
+
name: "Pylint Config",
|
|
763
|
+
description: "Pylint linter configuration",
|
|
764
|
+
category: "configuration",
|
|
765
|
+
match: (filepath, filename) => filename === ".pylintrc" || filename === "pylintrc" || filename === "pylint.toml",
|
|
766
|
+
keywords: ["python", "pylint", "linting", "lint", "code quality"]
|
|
553
767
|
},
|
|
554
768
|
{
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
769
|
+
id: "ruff-toml",
|
|
770
|
+
name: "Ruff Config",
|
|
771
|
+
description: "Ruff linter/formatter configuration",
|
|
772
|
+
category: "configuration",
|
|
773
|
+
match: (filepath, filename) => filename === "ruff.toml" || filename === ".ruff.toml",
|
|
774
|
+
keywords: ["python", "ruff", "linting", "formatting", "fast"]
|
|
558
775
|
},
|
|
559
776
|
{
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
777
|
+
id: "black-toml",
|
|
778
|
+
name: "Black Config",
|
|
779
|
+
description: "Black formatter configuration",
|
|
780
|
+
category: "configuration",
|
|
781
|
+
match: (filepath, filename) => filename === ".black.toml",
|
|
782
|
+
keywords: ["python", "black", "formatting", "format", "style"]
|
|
563
783
|
},
|
|
564
784
|
{
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
785
|
+
id: "tsconfig",
|
|
786
|
+
name: "TypeScript Config",
|
|
787
|
+
description: "TypeScript compiler configuration",
|
|
788
|
+
category: "configuration",
|
|
789
|
+
match: (filepath, filename) => filename === "tsconfig.json" || filename.startsWith("tsconfig.") && filename.endsWith(".json"),
|
|
790
|
+
keywords: [
|
|
791
|
+
"typescript",
|
|
792
|
+
"config",
|
|
793
|
+
"compiler",
|
|
794
|
+
"ts",
|
|
795
|
+
"settings",
|
|
796
|
+
"paths",
|
|
797
|
+
"types"
|
|
798
|
+
]
|
|
799
|
+
},
|
|
800
|
+
{
|
|
801
|
+
id: "jsconfig",
|
|
802
|
+
name: "JavaScript Config",
|
|
803
|
+
description: "JavaScript project configuration",
|
|
804
|
+
category: "configuration",
|
|
805
|
+
match: (filepath, filename) => filename === "jsconfig.json",
|
|
806
|
+
keywords: ["javascript", "config", "compiler", "js", "settings", "paths"]
|
|
807
|
+
},
|
|
808
|
+
{
|
|
809
|
+
id: "eslint-config",
|
|
810
|
+
name: "ESLint Config",
|
|
811
|
+
description: "ESLint linting configuration",
|
|
812
|
+
category: "configuration",
|
|
813
|
+
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",
|
|
814
|
+
keywords: ["eslint", "linting", "lint", "rules", "code quality"]
|
|
815
|
+
},
|
|
816
|
+
{
|
|
817
|
+
id: "prettier-config",
|
|
818
|
+
name: "Prettier Config",
|
|
819
|
+
description: "Prettier code formatting configuration",
|
|
820
|
+
category: "configuration",
|
|
821
|
+
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",
|
|
822
|
+
keywords: ["prettier", "formatting", "format", "code style", "style"]
|
|
823
|
+
},
|
|
824
|
+
{
|
|
825
|
+
id: "biome-config",
|
|
826
|
+
name: "Biome Config",
|
|
827
|
+
description: "Biome linting and formatting configuration",
|
|
828
|
+
category: "configuration",
|
|
829
|
+
match: (filepath, filename) => filename === "biome.json" || filename === "biome.jsonc",
|
|
830
|
+
keywords: ["biome", "linting", "formatting", "lint", "format"]
|
|
831
|
+
},
|
|
832
|
+
{
|
|
833
|
+
id: "vite-config",
|
|
834
|
+
name: "Vite Config",
|
|
835
|
+
description: "Vite build tool configuration",
|
|
836
|
+
category: "build",
|
|
837
|
+
match: (filepath, filename) => filename === "vite.config.ts" || filename === "vite.config.js" || filename === "vite.config.mjs",
|
|
838
|
+
keywords: ["vite", "bundler", "build", "dev server", "hmr"]
|
|
839
|
+
},
|
|
840
|
+
{
|
|
841
|
+
id: "webpack-config",
|
|
842
|
+
name: "Webpack Config",
|
|
843
|
+
description: "Webpack bundler configuration",
|
|
844
|
+
category: "build",
|
|
845
|
+
match: (filepath, filename) => filename === "webpack.config.js" || filename === "webpack.config.ts" || filename.startsWith("webpack.") && (filename.endsWith(".js") || filename.endsWith(".ts")),
|
|
846
|
+
keywords: ["webpack", "bundler", "build", "loaders", "plugins"]
|
|
847
|
+
},
|
|
848
|
+
{
|
|
849
|
+
id: "rollup-config",
|
|
850
|
+
name: "Rollup Config",
|
|
851
|
+
description: "Rollup bundler configuration",
|
|
852
|
+
category: "build",
|
|
853
|
+
match: (filepath, filename) => filename === "rollup.config.js" || filename === "rollup.config.ts" || filename === "rollup.config.mjs",
|
|
854
|
+
keywords: ["rollup", "bundler", "build", "esm", "bundle"]
|
|
855
|
+
},
|
|
856
|
+
{
|
|
857
|
+
id: "esbuild-config",
|
|
858
|
+
name: "esbuild Config",
|
|
859
|
+
description: "esbuild bundler configuration",
|
|
860
|
+
category: "build",
|
|
861
|
+
match: (filepath, filename) => filename === "esbuild.config.js" || filename === "esbuild.config.ts" || filename === "esbuild.config.mjs",
|
|
862
|
+
keywords: ["esbuild", "bundler", "build", "fast"]
|
|
863
|
+
},
|
|
864
|
+
{
|
|
865
|
+
id: "jest-config",
|
|
866
|
+
name: "Jest Config",
|
|
867
|
+
description: "Jest testing framework configuration",
|
|
868
|
+
category: "test",
|
|
869
|
+
match: (filepath, filename) => filename === "jest.config.js" || filename === "jest.config.ts" || filename === "jest.config.mjs" || filename === "jest.config.cjs" || filename === "jest.config.json",
|
|
870
|
+
keywords: ["jest", "testing", "test", "unit test", "config"]
|
|
871
|
+
},
|
|
872
|
+
{
|
|
873
|
+
id: "vitest-config",
|
|
874
|
+
name: "Vitest Config",
|
|
875
|
+
description: "Vitest testing framework configuration",
|
|
876
|
+
category: "test",
|
|
877
|
+
match: (filepath, filename) => filename === "vitest.config.ts" || filename === "vitest.config.js" || filename === "vitest.config.mts",
|
|
878
|
+
keywords: ["vitest", "testing", "test", "unit test", "config"]
|
|
879
|
+
},
|
|
880
|
+
{
|
|
881
|
+
id: "playwright-config",
|
|
882
|
+
name: "Playwright Config",
|
|
883
|
+
description: "Playwright E2E testing configuration",
|
|
884
|
+
category: "test",
|
|
885
|
+
match: (filepath, filename) => filename === "playwright.config.ts" || filename === "playwright.config.js",
|
|
886
|
+
keywords: ["playwright", "testing", "e2e", "end-to-end", "browser test"]
|
|
887
|
+
},
|
|
888
|
+
{
|
|
889
|
+
id: "cypress-config",
|
|
890
|
+
name: "Cypress Config",
|
|
891
|
+
description: "Cypress E2E testing configuration",
|
|
892
|
+
category: "test",
|
|
893
|
+
match: (filepath, filename) => filename === "cypress.config.ts" || filename === "cypress.config.js" || filename === "cypress.json",
|
|
894
|
+
keywords: ["cypress", "testing", "e2e", "end-to-end", "browser test"]
|
|
895
|
+
},
|
|
896
|
+
{
|
|
897
|
+
id: "tailwind-config",
|
|
898
|
+
name: "Tailwind Config",
|
|
899
|
+
description: "Tailwind CSS configuration",
|
|
900
|
+
category: "configuration",
|
|
901
|
+
match: (filepath, filename) => filename === "tailwind.config.js" || filename === "tailwind.config.ts" || filename === "tailwind.config.cjs" || filename === "tailwind.config.mjs",
|
|
902
|
+
keywords: ["tailwind", "css", "styling", "utility", "design"]
|
|
903
|
+
},
|
|
904
|
+
{
|
|
905
|
+
id: "postcss-config",
|
|
906
|
+
name: "PostCSS Config",
|
|
907
|
+
description: "PostCSS configuration",
|
|
908
|
+
category: "configuration",
|
|
909
|
+
match: (filepath, filename) => filename === "postcss.config.js" || filename === "postcss.config.cjs" || filename === "postcss.config.mjs" || filename === ".postcssrc" || filename === ".postcssrc.json",
|
|
910
|
+
keywords: ["postcss", "css", "styling", "transforms"]
|
|
911
|
+
},
|
|
912
|
+
{
|
|
913
|
+
id: "env-file",
|
|
914
|
+
name: "Environment File",
|
|
915
|
+
description: "Environment variables file",
|
|
916
|
+
category: "configuration",
|
|
917
|
+
match: (filepath, filename) => filename === ".env" || filename === ".env.local" || filename === ".env.development" || filename === ".env.production" || filename === ".env.test" || filename.startsWith(".env."),
|
|
918
|
+
keywords: ["environment", "env", "variables", "secrets", "config"]
|
|
919
|
+
},
|
|
920
|
+
{
|
|
921
|
+
id: "env-example",
|
|
922
|
+
name: "Environment Example",
|
|
923
|
+
description: "Example environment variables file",
|
|
924
|
+
category: "documentation",
|
|
925
|
+
match: (filepath, filename) => filename === ".env.example" || filename === ".env.sample" || filename === ".env.template",
|
|
926
|
+
keywords: ["environment", "env", "example", "template", "setup"]
|
|
927
|
+
},
|
|
928
|
+
{
|
|
929
|
+
id: "dockerfile",
|
|
930
|
+
name: "Dockerfile",
|
|
931
|
+
description: "Docker container image definition",
|
|
932
|
+
category: "deployment",
|
|
933
|
+
match: (filepath, filename) => filename === "Dockerfile" || filename.startsWith("Dockerfile."),
|
|
934
|
+
keywords: ["docker", "container", "image", "deployment", "build"]
|
|
935
|
+
},
|
|
936
|
+
{
|
|
937
|
+
id: "docker-compose",
|
|
938
|
+
name: "Docker Compose",
|
|
939
|
+
description: "Docker Compose multi-container configuration",
|
|
940
|
+
category: "deployment",
|
|
941
|
+
match: (filepath, filename) => filename === "docker-compose.yml" || filename === "docker-compose.yaml" || filename === "compose.yml" || filename === "compose.yaml" || filename.startsWith("docker-compose."),
|
|
942
|
+
keywords: ["docker", "compose", "containers", "services", "deployment"]
|
|
943
|
+
},
|
|
944
|
+
{
|
|
945
|
+
id: "github-actions",
|
|
946
|
+
name: "GitHub Actions Workflow",
|
|
947
|
+
description: "GitHub Actions CI/CD workflow",
|
|
948
|
+
category: "deployment",
|
|
949
|
+
match: (filepath) => filepath.includes(".github/workflows/") && filepath.endsWith(".yml"),
|
|
950
|
+
keywords: ["github", "actions", "ci", "cd", "workflow", "automation"]
|
|
951
|
+
},
|
|
952
|
+
{
|
|
953
|
+
id: "vercel-config",
|
|
954
|
+
name: "Vercel Config",
|
|
955
|
+
description: "Vercel deployment configuration",
|
|
956
|
+
category: "deployment",
|
|
957
|
+
match: (filepath, filename) => filename === "vercel.json",
|
|
958
|
+
keywords: ["vercel", "deployment", "hosting", "serverless"]
|
|
959
|
+
},
|
|
960
|
+
{
|
|
961
|
+
id: "netlify-config",
|
|
962
|
+
name: "Netlify Config",
|
|
963
|
+
description: "Netlify deployment configuration",
|
|
964
|
+
category: "deployment",
|
|
965
|
+
match: (filepath, filename) => filename === "netlify.toml",
|
|
966
|
+
keywords: ["netlify", "deployment", "hosting", "functions"]
|
|
967
|
+
},
|
|
968
|
+
{
|
|
969
|
+
id: "gitignore",
|
|
970
|
+
name: "Git Ignore",
|
|
971
|
+
description: "Git ignored files configuration",
|
|
972
|
+
category: "configuration",
|
|
973
|
+
match: (filepath, filename) => filename === ".gitignore",
|
|
974
|
+
keywords: ["git", "ignore", "version control", "excluded"]
|
|
975
|
+
},
|
|
976
|
+
{
|
|
977
|
+
id: "gitattributes",
|
|
978
|
+
name: "Git Attributes",
|
|
979
|
+
description: "Git file attributes configuration",
|
|
980
|
+
category: "configuration",
|
|
981
|
+
match: (filepath, filename) => filename === ".gitattributes",
|
|
982
|
+
keywords: ["git", "attributes", "version control", "line endings"]
|
|
983
|
+
},
|
|
984
|
+
{
|
|
985
|
+
id: "readme",
|
|
986
|
+
name: "README",
|
|
987
|
+
description: "Project documentation",
|
|
988
|
+
category: "documentation",
|
|
989
|
+
match: (filepath, filename) => filename.toLowerCase() === "readme.md" || filename.toLowerCase() === "readme",
|
|
990
|
+
keywords: [
|
|
991
|
+
"readme",
|
|
992
|
+
"documentation",
|
|
993
|
+
"docs",
|
|
994
|
+
"overview",
|
|
995
|
+
"getting started"
|
|
996
|
+
]
|
|
997
|
+
},
|
|
998
|
+
{
|
|
999
|
+
id: "changelog",
|
|
1000
|
+
name: "Changelog",
|
|
1001
|
+
description: "Project changelog",
|
|
1002
|
+
category: "documentation",
|
|
1003
|
+
match: (filepath, filename) => filename.toLowerCase() === "changelog.md" || filename.toLowerCase() === "changelog",
|
|
1004
|
+
keywords: ["changelog", "changes", "releases", "history", "versions"]
|
|
1005
|
+
},
|
|
1006
|
+
{
|
|
1007
|
+
id: "contributing",
|
|
1008
|
+
name: "Contributing Guide",
|
|
1009
|
+
description: "Contribution guidelines",
|
|
1010
|
+
category: "documentation",
|
|
1011
|
+
match: (filepath, filename) => filename.toLowerCase() === "contributing.md" || filename.toLowerCase() === "contributing",
|
|
1012
|
+
keywords: ["contributing", "contribution", "guidelines", "development"]
|
|
1013
|
+
},
|
|
1014
|
+
{
|
|
1015
|
+
id: "license",
|
|
1016
|
+
name: "License",
|
|
1017
|
+
description: "Project license",
|
|
1018
|
+
category: "documentation",
|
|
1019
|
+
match: (filepath, filename) => filename.toLowerCase() === "license" || filename.toLowerCase() === "license.md" || filename.toLowerCase() === "license.txt",
|
|
1020
|
+
keywords: ["license", "legal", "copyright", "terms"]
|
|
568
1021
|
}
|
|
569
1022
|
];
|
|
570
1023
|
});
|
|
571
1024
|
|
|
572
|
-
// src/
|
|
573
|
-
var
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
chunks,
|
|
610
|
-
moduleData
|
|
611
|
-
};
|
|
612
|
-
}
|
|
613
|
-
createChunks(filepath, content, symbols) {
|
|
614
|
-
const lines = content.split(`
|
|
615
|
-
`);
|
|
616
|
-
const chunks = [];
|
|
617
|
-
for (let start = 0;start < lines.length; start += LINES_PER_CHUNK - CHUNK_OVERLAP) {
|
|
618
|
-
const end = Math.min(start + LINES_PER_CHUNK, lines.length);
|
|
619
|
-
const chunkLines = lines.slice(start, end);
|
|
620
|
-
const chunkContent = chunkLines.join(`
|
|
621
|
-
`);
|
|
622
|
-
const chunkSymbols = symbols.filter((s) => s.line >= start + 1 && s.line <= end);
|
|
623
|
-
let chunkType = "block";
|
|
624
|
-
let chunkName;
|
|
625
|
-
let isExported = false;
|
|
626
|
-
if (chunkSymbols.length > 0) {
|
|
627
|
-
const primarySymbol = chunkSymbols[0];
|
|
628
|
-
chunkType = this.symbolTypeToChunkType(primarySymbol.type);
|
|
629
|
-
chunkName = primarySymbol.name;
|
|
630
|
-
isExported = primarySymbol.isExported;
|
|
1025
|
+
// src/domain/services/conventions/frameworks/nextjs.ts
|
|
1026
|
+
var nextjsConventions, nextjsFramework;
|
|
1027
|
+
var init_nextjs = __esm(() => {
|
|
1028
|
+
nextjsConventions = [
|
|
1029
|
+
{
|
|
1030
|
+
id: "next-config",
|
|
1031
|
+
name: "Next.js Config",
|
|
1032
|
+
description: "Next.js framework configuration",
|
|
1033
|
+
category: "configuration",
|
|
1034
|
+
match: (filepath, filename) => filename === "next.config.js" || filename === "next.config.mjs" || filename === "next.config.ts",
|
|
1035
|
+
keywords: ["nextjs", "next", "config", "framework", "settings"]
|
|
1036
|
+
},
|
|
1037
|
+
{
|
|
1038
|
+
id: "next-env",
|
|
1039
|
+
name: "Next.js Environment Types",
|
|
1040
|
+
description: "Next.js TypeScript environment declarations",
|
|
1041
|
+
category: "types",
|
|
1042
|
+
match: (filepath, filename) => filename === "next-env.d.ts",
|
|
1043
|
+
keywords: ["nextjs", "types", "typescript", "declarations"]
|
|
1044
|
+
},
|
|
1045
|
+
{
|
|
1046
|
+
id: "next-layout",
|
|
1047
|
+
name: "Next.js Layout",
|
|
1048
|
+
description: "Next.js layout component (App Router)",
|
|
1049
|
+
category: "framework",
|
|
1050
|
+
match: (filepath, filename) => (filename === "layout.tsx" || filename === "layout.js") && (filepath.includes("/app/") || filepath.startsWith("app/")),
|
|
1051
|
+
keywords: ["nextjs", "layout", "wrapper", "template", "app router"],
|
|
1052
|
+
dynamicKeywords: (filepath) => {
|
|
1053
|
+
const match = filepath.match(/app\/(.+?)\/layout\./);
|
|
1054
|
+
if (match) {
|
|
1055
|
+
const segments = match[1].split("/").filter((s) => !s.startsWith("(") && !s.startsWith("["));
|
|
1056
|
+
return segments.map((s) => s.toLowerCase());
|
|
1057
|
+
}
|
|
1058
|
+
if (filepath === "app/layout.tsx" || filepath === "app/layout.js") {
|
|
1059
|
+
return ["root", "main"];
|
|
1060
|
+
}
|
|
1061
|
+
return [];
|
|
631
1062
|
}
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
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)
|
|
708
|
-
continue;
|
|
709
|
-
const bestChunk = this.findBestChunk(fileIndex.chunks, queryTokens, entry.symbols);
|
|
710
|
-
results.push({
|
|
711
|
-
filepath,
|
|
712
|
-
chunk: bestChunk,
|
|
713
|
-
score: combinedScore,
|
|
714
|
-
moduleId: this.id,
|
|
715
|
-
context: {
|
|
716
|
-
bm25Score: normalizeScore(bm25Score),
|
|
717
|
-
symbolScore
|
|
718
|
-
}
|
|
719
|
-
});
|
|
1063
|
+
},
|
|
1064
|
+
{
|
|
1065
|
+
id: "next-page",
|
|
1066
|
+
name: "Next.js Page",
|
|
1067
|
+
description: "Next.js page component (App Router)",
|
|
1068
|
+
category: "framework",
|
|
1069
|
+
match: (filepath, filename) => (filename === "page.tsx" || filename === "page.js") && (filepath.includes("/app/") || filepath.startsWith("app/")),
|
|
1070
|
+
keywords: ["nextjs", "page", "route", "view", "app router"],
|
|
1071
|
+
dynamicKeywords: (filepath) => {
|
|
1072
|
+
const match = filepath.match(/app\/(.+?)\/page\./);
|
|
1073
|
+
if (match) {
|
|
1074
|
+
const segments = match[1].split("/").filter((s) => !s.startsWith("(")).map((s) => s.replace(/^\[(.+?)\]$/, "$1"));
|
|
1075
|
+
return segments.map((s) => s.toLowerCase());
|
|
1076
|
+
}
|
|
1077
|
+
if (filepath === "app/page.tsx" || filepath === "app/page.js") {
|
|
1078
|
+
return ["home", "index", "root"];
|
|
1079
|
+
}
|
|
1080
|
+
return [];
|
|
720
1081
|
}
|
|
721
|
-
}
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
1082
|
+
},
|
|
1083
|
+
{
|
|
1084
|
+
id: "next-loading",
|
|
1085
|
+
name: "Next.js Loading",
|
|
1086
|
+
description: "Next.js loading UI component",
|
|
1087
|
+
category: "framework",
|
|
1088
|
+
match: (filepath, filename) => (filename === "loading.tsx" || filename === "loading.js") && (filepath.includes("/app/") || filepath.startsWith("app/")),
|
|
1089
|
+
keywords: ["nextjs", "loading", "suspense", "skeleton", "spinner"]
|
|
1090
|
+
},
|
|
1091
|
+
{
|
|
1092
|
+
id: "next-error",
|
|
1093
|
+
name: "Next.js Error",
|
|
1094
|
+
description: "Next.js error boundary component",
|
|
1095
|
+
category: "framework",
|
|
1096
|
+
match: (filepath, filename) => (filename === "error.tsx" || filename === "error.js") && (filepath.includes("/app/") || filepath.startsWith("app/")),
|
|
1097
|
+
keywords: ["nextjs", "error", "boundary", "fallback", "catch"]
|
|
1098
|
+
},
|
|
1099
|
+
{
|
|
1100
|
+
id: "next-not-found",
|
|
1101
|
+
name: "Next.js Not Found",
|
|
1102
|
+
description: "Next.js 404 page component",
|
|
1103
|
+
category: "framework",
|
|
1104
|
+
match: (filepath, filename) => (filename === "not-found.tsx" || filename === "not-found.js") && (filepath.includes("/app/") || filepath.startsWith("app/")),
|
|
1105
|
+
keywords: ["nextjs", "404", "not found", "missing", "error"]
|
|
1106
|
+
},
|
|
1107
|
+
{
|
|
1108
|
+
id: "next-template",
|
|
1109
|
+
name: "Next.js Template",
|
|
1110
|
+
description: "Next.js template component",
|
|
1111
|
+
category: "framework",
|
|
1112
|
+
match: (filepath, filename) => (filename === "template.tsx" || filename === "template.js") && (filepath.includes("/app/") || filepath.startsWith("app/")),
|
|
1113
|
+
keywords: ["nextjs", "template", "wrapper", "app router"]
|
|
1114
|
+
},
|
|
1115
|
+
{
|
|
1116
|
+
id: "next-route-handler",
|
|
1117
|
+
name: "Next.js Route Handler",
|
|
1118
|
+
description: "Next.js API route handler (App Router)",
|
|
1119
|
+
category: "framework",
|
|
1120
|
+
match: (filepath, filename) => (filename === "route.ts" || filename === "route.js") && (filepath.includes("/app/") || filepath.startsWith("app/")),
|
|
1121
|
+
keywords: ["nextjs", "api", "route", "handler", "endpoint", "rest"],
|
|
1122
|
+
dynamicKeywords: (filepath) => {
|
|
1123
|
+
const match = filepath.match(/app\/api\/(.+?)\/route\./);
|
|
1124
|
+
if (match) {
|
|
1125
|
+
const segments = match[1].split("/").filter((s) => !s.startsWith("(")).map((s) => s.replace(/^\[(.+?)\]$/, "$1"));
|
|
1126
|
+
return ["api", ...segments.map((s) => s.toLowerCase())];
|
|
739
1127
|
}
|
|
1128
|
+
return ["api"];
|
|
740
1129
|
}
|
|
741
|
-
|
|
742
|
-
|
|
1130
|
+
},
|
|
1131
|
+
{
|
|
1132
|
+
id: "next-middleware",
|
|
1133
|
+
name: "Next.js Middleware",
|
|
1134
|
+
description: "Next.js edge middleware",
|
|
1135
|
+
category: "framework",
|
|
1136
|
+
match: (filepath, filename) => filename === "middleware.ts" || filename === "middleware.js",
|
|
1137
|
+
keywords: ["nextjs", "middleware", "edge", "request", "interceptor"]
|
|
1138
|
+
},
|
|
1139
|
+
{
|
|
1140
|
+
id: "next-global-error",
|
|
1141
|
+
name: "Next.js Global Error",
|
|
1142
|
+
description: "Next.js global error handler",
|
|
1143
|
+
category: "framework",
|
|
1144
|
+
match: (filepath, filename) => filename === "global-error.tsx" || filename === "global-error.js",
|
|
1145
|
+
keywords: ["nextjs", "error", "global", "boundary", "catch"]
|
|
1146
|
+
},
|
|
1147
|
+
{
|
|
1148
|
+
id: "next-pages-api",
|
|
1149
|
+
name: "Next.js API Route (Pages)",
|
|
1150
|
+
description: "Next.js API route (Pages Router)",
|
|
1151
|
+
category: "framework",
|
|
1152
|
+
match: (filepath) => filepath.includes("/pages/api/") || filepath.startsWith("pages/api/"),
|
|
1153
|
+
keywords: ["nextjs", "api", "route", "handler", "endpoint", "pages router"],
|
|
1154
|
+
dynamicKeywords: (filepath) => {
|
|
1155
|
+
const match = filepath.match(/pages\/api\/(.+?)\.(ts|js)/);
|
|
1156
|
+
if (match) {
|
|
1157
|
+
const segments = match[1].split("/").map((s) => s.replace(/^\[(.+?)\]$/, "$1"));
|
|
1158
|
+
return ["api", ...segments.map((s) => s.toLowerCase())];
|
|
1159
|
+
}
|
|
1160
|
+
return ["api"];
|
|
743
1161
|
}
|
|
1162
|
+
},
|
|
1163
|
+
{
|
|
1164
|
+
id: "next-pages-document",
|
|
1165
|
+
name: "Next.js Document",
|
|
1166
|
+
description: "Next.js custom document (Pages Router)",
|
|
1167
|
+
category: "framework",
|
|
1168
|
+
match: (filepath, filename) => (filename === "_document.tsx" || filename === "_document.js") && (filepath.includes("/pages/") || filepath.startsWith("pages/")),
|
|
1169
|
+
keywords: ["nextjs", "document", "html", "head", "body", "pages router"]
|
|
1170
|
+
},
|
|
1171
|
+
{
|
|
1172
|
+
id: "next-pages-app",
|
|
1173
|
+
name: "Next.js App (Pages)",
|
|
1174
|
+
description: "Next.js custom app (Pages Router)",
|
|
1175
|
+
category: "framework",
|
|
1176
|
+
match: (filepath, filename) => (filename === "_app.tsx" || filename === "_app.js") && (filepath.includes("/pages/") || filepath.startsWith("pages/")),
|
|
1177
|
+
keywords: ["nextjs", "app", "wrapper", "provider", "pages router"]
|
|
744
1178
|
}
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
1179
|
+
];
|
|
1180
|
+
nextjsFramework = {
|
|
1181
|
+
id: "nextjs",
|
|
1182
|
+
name: "Next.js",
|
|
1183
|
+
detect: (filepath) => {
|
|
1184
|
+
return filepath === "next.config.js" || filepath === "next.config.mjs" || filepath === "next.config.ts" || filepath.includes("/app/page.") || filepath.includes("/pages/_app.");
|
|
1185
|
+
},
|
|
1186
|
+
conventions: nextjsConventions
|
|
1187
|
+
};
|
|
1188
|
+
});
|
|
1189
|
+
|
|
1190
|
+
// src/domain/services/conventions/frameworks/convex.ts
|
|
1191
|
+
var convexConventions, convexFramework;
|
|
1192
|
+
var init_convex = __esm(() => {
|
|
1193
|
+
convexConventions = [
|
|
1194
|
+
{
|
|
1195
|
+
id: "convex-config",
|
|
1196
|
+
name: "Convex Config",
|
|
1197
|
+
description: "Convex project configuration",
|
|
1198
|
+
category: "configuration",
|
|
1199
|
+
match: (filepath, filename) => filename === "convex.json",
|
|
1200
|
+
keywords: ["convex", "config", "backend", "settings"]
|
|
1201
|
+
},
|
|
1202
|
+
{
|
|
1203
|
+
id: "convex-schema",
|
|
1204
|
+
name: "Convex Schema",
|
|
1205
|
+
description: "Convex database schema definition",
|
|
1206
|
+
category: "framework",
|
|
1207
|
+
match: (filepath, filename) => filename === "schema.ts" && (filepath.includes("/convex/") || filepath.startsWith("convex/")),
|
|
1208
|
+
keywords: ["convex", "schema", "database", "tables", "types", "model"]
|
|
1209
|
+
},
|
|
1210
|
+
{
|
|
1211
|
+
id: "convex-function",
|
|
1212
|
+
name: "Convex Function File",
|
|
1213
|
+
description: "Convex backend function file",
|
|
1214
|
+
category: "framework",
|
|
1215
|
+
match: (filepath, filename, extension) => (extension === ".ts" || extension === ".js") && (filepath.includes("/convex/") || filepath.startsWith("convex/")) && !filepath.includes("/_generated/") && filename !== "schema.ts" && !filename.startsWith("_"),
|
|
1216
|
+
keywords: ["convex", "function", "backend", "query", "mutation", "action"],
|
|
1217
|
+
dynamicKeywords: (filepath) => {
|
|
1218
|
+
const match = filepath.match(/convex\/(.+?)\.(ts|js)/);
|
|
1219
|
+
if (match) {
|
|
1220
|
+
const name = match[1].replace(/\//g, " ").split(" ").pop() || "";
|
|
1221
|
+
if (name && !["schema", "http", "crons"].includes(name)) {
|
|
1222
|
+
return [name.toLowerCase()];
|
|
1223
|
+
}
|
|
756
1224
|
}
|
|
1225
|
+
return [];
|
|
757
1226
|
}
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
1227
|
+
},
|
|
1228
|
+
{
|
|
1229
|
+
id: "convex-http",
|
|
1230
|
+
name: "Convex HTTP Routes",
|
|
1231
|
+
description: "Convex HTTP endpoint definitions",
|
|
1232
|
+
category: "framework",
|
|
1233
|
+
match: (filepath, filename) => filename === "http.ts" && (filepath.includes("/convex/") || filepath.startsWith("convex/")),
|
|
1234
|
+
keywords: ["convex", "http", "routes", "api", "endpoints", "rest"]
|
|
1235
|
+
},
|
|
1236
|
+
{
|
|
1237
|
+
id: "convex-crons",
|
|
1238
|
+
name: "Convex Cron Jobs",
|
|
1239
|
+
description: "Convex scheduled function definitions",
|
|
1240
|
+
category: "framework",
|
|
1241
|
+
match: (filepath, filename) => filename === "crons.ts" && (filepath.includes("/convex/") || filepath.startsWith("convex/")),
|
|
1242
|
+
keywords: [
|
|
1243
|
+
"convex",
|
|
1244
|
+
"crons",
|
|
1245
|
+
"scheduled",
|
|
1246
|
+
"jobs",
|
|
1247
|
+
"background",
|
|
1248
|
+
"recurring"
|
|
1249
|
+
]
|
|
1250
|
+
},
|
|
1251
|
+
{
|
|
1252
|
+
id: "convex-generated",
|
|
1253
|
+
name: "Convex Generated",
|
|
1254
|
+
description: "Convex auto-generated files",
|
|
1255
|
+
category: "framework",
|
|
1256
|
+
match: (filepath) => filepath.includes("/convex/_generated/") || filepath.startsWith("convex/_generated/"),
|
|
1257
|
+
keywords: ["convex", "generated", "types", "api"]
|
|
1258
|
+
},
|
|
1259
|
+
{
|
|
1260
|
+
id: "convex-auth",
|
|
1261
|
+
name: "Convex Auth",
|
|
1262
|
+
description: "Convex authentication configuration",
|
|
1263
|
+
category: "framework",
|
|
1264
|
+
match: (filepath, filename) => filename === "auth.ts" && (filepath.includes("/convex/") || filepath.startsWith("convex/")),
|
|
1265
|
+
keywords: ["convex", "auth", "authentication", "login", "users"]
|
|
1266
|
+
},
|
|
1267
|
+
{
|
|
1268
|
+
id: "convex-auth-config",
|
|
1269
|
+
name: "Convex Auth Config",
|
|
1270
|
+
description: "Convex auth configuration file",
|
|
1271
|
+
category: "configuration",
|
|
1272
|
+
match: (filepath, filename) => filename === "auth.config.ts",
|
|
1273
|
+
keywords: ["convex", "auth", "config", "providers", "oauth"]
|
|
1274
|
+
}
|
|
1275
|
+
];
|
|
1276
|
+
convexFramework = {
|
|
1277
|
+
id: "convex",
|
|
1278
|
+
name: "Convex",
|
|
1279
|
+
detect: (filepath) => {
|
|
1280
|
+
return filepath === "convex.json" || filepath.startsWith("convex/") || filepath.includes("/convex/");
|
|
1281
|
+
},
|
|
1282
|
+
conventions: convexConventions
|
|
1283
|
+
};
|
|
1284
|
+
});
|
|
1285
|
+
|
|
1286
|
+
// src/domain/services/conventions/frameworks/index.ts
|
|
1287
|
+
function getAllFrameworkConventions() {
|
|
1288
|
+
return frameworkProviders.flatMap((f) => f.conventions);
|
|
1289
|
+
}
|
|
1290
|
+
var frameworkProviders;
|
|
1291
|
+
var init_frameworks = __esm(() => {
|
|
1292
|
+
init_nextjs();
|
|
1293
|
+
init_convex();
|
|
1294
|
+
init_nextjs();
|
|
1295
|
+
init_convex();
|
|
1296
|
+
frameworkProviders = [
|
|
1297
|
+
nextjsFramework,
|
|
1298
|
+
convexFramework
|
|
1299
|
+
];
|
|
1300
|
+
});
|
|
1301
|
+
|
|
1302
|
+
// src/domain/services/conventions/index.ts
|
|
1303
|
+
import * as path4 from "path";
|
|
1304
|
+
function getConventions() {
|
|
1305
|
+
return [
|
|
1306
|
+
...entryPointConventions,
|
|
1307
|
+
...configFileConventions,
|
|
1308
|
+
...getAllFrameworkConventions(),
|
|
1309
|
+
...typeDefinitionConventions,
|
|
1310
|
+
...testFileConventions
|
|
1311
|
+
];
|
|
1312
|
+
}
|
|
1313
|
+
function getConventionKeywords(filepath) {
|
|
1314
|
+
const conventions = getConventions();
|
|
1315
|
+
const filename = path4.basename(filepath);
|
|
1316
|
+
const extension = path4.extname(filepath);
|
|
1317
|
+
const keywords = new Set;
|
|
1318
|
+
for (const convention of conventions) {
|
|
1319
|
+
try {
|
|
1320
|
+
if (convention.match(filepath, filename, extension)) {
|
|
1321
|
+
for (const keyword of convention.keywords) {
|
|
1322
|
+
keywords.add(keyword.toLowerCase());
|
|
1323
|
+
}
|
|
1324
|
+
if (convention.dynamicKeywords) {
|
|
1325
|
+
const dynamicKws = convention.dynamicKeywords(filepath);
|
|
1326
|
+
for (const kw of dynamicKws) {
|
|
1327
|
+
if (kw && kw.length > 1) {
|
|
1328
|
+
keywords.add(kw.toLowerCase());
|
|
1329
|
+
}
|
|
763
1330
|
}
|
|
764
1331
|
}
|
|
765
1332
|
}
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
1333
|
+
} catch {}
|
|
1334
|
+
}
|
|
1335
|
+
return Array.from(keywords);
|
|
1336
|
+
}
|
|
1337
|
+
var typeDefinitionConventions, testFileConventions;
|
|
1338
|
+
var init_conventions = __esm(() => {
|
|
1339
|
+
init_entryPoints();
|
|
1340
|
+
init_configFiles();
|
|
1341
|
+
init_frameworks();
|
|
1342
|
+
init_entryPoints();
|
|
1343
|
+
init_configFiles();
|
|
1344
|
+
init_frameworks();
|
|
1345
|
+
typeDefinitionConventions = [
|
|
1346
|
+
{
|
|
1347
|
+
id: "dts-file",
|
|
1348
|
+
name: "TypeScript Declaration",
|
|
1349
|
+
description: "TypeScript type declaration file",
|
|
1350
|
+
category: "types",
|
|
1351
|
+
match: (filepath, filename) => filename.endsWith(".d.ts"),
|
|
1352
|
+
keywords: ["types", "declarations", "typescript", "definitions"]
|
|
1353
|
+
},
|
|
1354
|
+
{
|
|
1355
|
+
id: "types-file",
|
|
1356
|
+
name: "Types File",
|
|
1357
|
+
description: "TypeScript types file",
|
|
1358
|
+
category: "types",
|
|
1359
|
+
match: (filepath, filename) => filename.endsWith(".types.ts") || filename === "types.ts",
|
|
1360
|
+
keywords: ["types", "definitions", "typescript", "interfaces"],
|
|
1361
|
+
dynamicKeywords: (filepath) => {
|
|
1362
|
+
const match = filepath.match(/([^/]+)\.types\.ts$/);
|
|
1363
|
+
if (match)
|
|
1364
|
+
return [match[1].toLowerCase()];
|
|
1365
|
+
return [];
|
|
772
1366
|
}
|
|
1367
|
+
},
|
|
1368
|
+
{
|
|
1369
|
+
id: "types-folder",
|
|
1370
|
+
name: "Types Folder File",
|
|
1371
|
+
description: "File in a types folder",
|
|
1372
|
+
category: "types",
|
|
1373
|
+
match: (filepath) => filepath.includes("/types/") || filepath.startsWith("types/"),
|
|
1374
|
+
keywords: ["types", "definitions"]
|
|
773
1375
|
}
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
1376
|
+
];
|
|
1377
|
+
testFileConventions = [
|
|
1378
|
+
{
|
|
1379
|
+
id: "test-file",
|
|
1380
|
+
name: "Test File",
|
|
1381
|
+
description: "Unit/integration test file",
|
|
1382
|
+
category: "test",
|
|
1383
|
+
match: (filepath, filename) => filename.includes(".test.") || filename.includes(".spec.") || filename.includes("_test."),
|
|
1384
|
+
keywords: ["test", "spec", "unit test"],
|
|
1385
|
+
dynamicKeywords: (filepath) => {
|
|
1386
|
+
const match = filepath.match(/([^/]+)\.(test|spec)\./);
|
|
1387
|
+
if (match)
|
|
1388
|
+
return [match[1].toLowerCase()];
|
|
1389
|
+
return [];
|
|
785
1390
|
}
|
|
786
|
-
}
|
|
787
|
-
|
|
788
|
-
|
|
1391
|
+
},
|
|
1392
|
+
{
|
|
1393
|
+
id: "test-folder",
|
|
1394
|
+
name: "Test Folder File",
|
|
1395
|
+
description: "File in a test folder",
|
|
1396
|
+
category: "test",
|
|
1397
|
+
match: (filepath) => filepath.includes("/__tests__/") || filepath.includes("/test/") || filepath.includes("/tests/") || filepath.startsWith("__tests__/") || filepath.startsWith("test/") || filepath.startsWith("tests/"),
|
|
1398
|
+
keywords: ["test", "testing"]
|
|
789
1399
|
}
|
|
790
|
-
|
|
791
|
-
async dispose() {
|
|
792
|
-
this.symbolIndex.clear();
|
|
793
|
-
this.bm25Index = null;
|
|
794
|
-
}
|
|
795
|
-
}
|
|
796
|
-
var DEFAULT_MIN_SCORE = 0.1, DEFAULT_TOP_K = 20, LINES_PER_CHUNK = 50, CHUNK_OVERLAP = 10;
|
|
797
|
-
var init_core = __esm(() => {
|
|
798
|
-
init_config2();
|
|
799
|
-
init_symbols();
|
|
1400
|
+
];
|
|
800
1401
|
});
|
|
801
1402
|
|
|
802
|
-
// src/domain/services/
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
1403
|
+
// src/domain/services/introspection.ts
|
|
1404
|
+
import * as path5 from "path";
|
|
1405
|
+
function introspectFile(filepath, structure, fileContent) {
|
|
1406
|
+
const normalizedPath = filepath.replace(/\\/g, "/");
|
|
1407
|
+
const segments = normalizedPath.split("/").filter((s) => s.length > 0);
|
|
1408
|
+
const filename = segments[segments.length - 1] || "";
|
|
1409
|
+
const ext = path5.extname(filename);
|
|
1410
|
+
const project = findProjectForFile(normalizedPath, structure);
|
|
1411
|
+
const language = EXTENSION_TO_LANGUAGE[ext] || "unknown";
|
|
1412
|
+
const layer = detectLayer(segments, filename);
|
|
1413
|
+
const domain = detectDomain(segments);
|
|
1414
|
+
const scope = detectScope(segments, project, layer);
|
|
1415
|
+
const framework = fileContent ? detectFramework(fileContent) : undefined;
|
|
1416
|
+
return {
|
|
1417
|
+
filepath: normalizedPath,
|
|
1418
|
+
project,
|
|
1419
|
+
scope,
|
|
1420
|
+
layer,
|
|
1421
|
+
domain,
|
|
1422
|
+
language,
|
|
1423
|
+
framework,
|
|
1424
|
+
depth: segments.length - 1,
|
|
1425
|
+
pathSegments: segments.slice(0, -1)
|
|
1426
|
+
};
|
|
1427
|
+
}
|
|
1428
|
+
function introspectionToKeywords(intro) {
|
|
1429
|
+
const keywords = [];
|
|
1430
|
+
const filename = path5.basename(intro.filepath);
|
|
1431
|
+
const filenameWithoutExt = filename.replace(/\.[^.]+$/, "");
|
|
1432
|
+
const filenameParts = filenameWithoutExt.split(/[-_.]/).flatMap((part) => part.split(/(?=[A-Z])/)).map((part) => part.toLowerCase()).filter((part) => part.length > 1);
|
|
1433
|
+
keywords.push(...filenameParts);
|
|
1434
|
+
keywords.push(filenameWithoutExt.toLowerCase());
|
|
1435
|
+
if (intro.project.name && intro.project.name !== "root") {
|
|
1436
|
+
keywords.push(intro.project.name.toLowerCase());
|
|
1437
|
+
}
|
|
1438
|
+
if (intro.scope !== "unknown")
|
|
1439
|
+
keywords.push(intro.scope);
|
|
1440
|
+
if (intro.layer)
|
|
1441
|
+
keywords.push(intro.layer);
|
|
1442
|
+
if (intro.domain)
|
|
1443
|
+
keywords.push(intro.domain);
|
|
1444
|
+
if (intro.language !== "unknown")
|
|
1445
|
+
keywords.push(intro.language);
|
|
1446
|
+
if (intro.framework)
|
|
1447
|
+
keywords.push(intro.framework);
|
|
1448
|
+
const skipSegments = new Set(["src", "lib", "index"]);
|
|
1449
|
+
for (const segment of intro.pathSegments) {
|
|
1450
|
+
if (!skipSegments.has(segment.toLowerCase()) && segment.length > 2) {
|
|
1451
|
+
keywords.push(segment.toLowerCase());
|
|
1452
|
+
}
|
|
1453
|
+
}
|
|
1454
|
+
const conventionKeywords = getConventionKeywords(intro.filepath);
|
|
1455
|
+
keywords.push(...conventionKeywords);
|
|
1456
|
+
return [...new Set(keywords)];
|
|
1457
|
+
}
|
|
1458
|
+
function detectScopeFromName(name) {
|
|
1459
|
+
const nameLower = name.toLowerCase();
|
|
1460
|
+
for (const [scope, keywords] of Object.entries(SCOPE_KEYWORDS)) {
|
|
1461
|
+
if (scope === "unknown")
|
|
1462
|
+
continue;
|
|
1463
|
+
for (const keyword of keywords) {
|
|
1464
|
+
if (nameLower.includes(keyword)) {
|
|
1465
|
+
return scope;
|
|
1466
|
+
}
|
|
1467
|
+
}
|
|
1468
|
+
}
|
|
1469
|
+
return "unknown";
|
|
1470
|
+
}
|
|
1471
|
+
function findProjectForFile(filepath, structure) {
|
|
1472
|
+
const normalizedPath = filepath.replace(/\\/g, "/");
|
|
1473
|
+
const matches = [];
|
|
1474
|
+
for (const project of structure.projects) {
|
|
1475
|
+
if (normalizedPath === project.root || normalizedPath.startsWith(project.root + "/")) {
|
|
1476
|
+
matches.push(project);
|
|
1477
|
+
}
|
|
1478
|
+
}
|
|
1479
|
+
if (matches.length > 0) {
|
|
1480
|
+
return matches.reduce((best, current) => current.root.length > best.root.length ? current : best);
|
|
1481
|
+
}
|
|
1482
|
+
for (const { pattern, type } of PROJECT_PATTERNS) {
|
|
1483
|
+
const match = normalizedPath.match(pattern);
|
|
1484
|
+
if (match) {
|
|
1485
|
+
return { name: match[1], root: match[0], type };
|
|
1486
|
+
}
|
|
1487
|
+
}
|
|
1488
|
+
return { name: "root", root: "", type: structure.rootType ?? "unknown" };
|
|
1489
|
+
}
|
|
1490
|
+
function detectLayer(segments, filename) {
|
|
1491
|
+
const filenameLower = filename.toLowerCase();
|
|
1492
|
+
for (const [layer, patterns] of Object.entries(LAYER_PATTERNS)) {
|
|
1493
|
+
for (const pattern of patterns) {
|
|
1494
|
+
if (filenameLower.includes(pattern))
|
|
1495
|
+
return layer;
|
|
1496
|
+
}
|
|
1497
|
+
}
|
|
1498
|
+
for (let i = segments.length - 2;i >= 0; i--) {
|
|
1499
|
+
const segment = segments[i].toLowerCase();
|
|
1500
|
+
for (const [layer, patterns] of Object.entries(LAYER_PATTERNS)) {
|
|
1501
|
+
if (patterns.includes(segment))
|
|
1502
|
+
return layer;
|
|
1503
|
+
}
|
|
1504
|
+
}
|
|
1505
|
+
return;
|
|
1506
|
+
}
|
|
1507
|
+
function detectDomain(segments) {
|
|
1508
|
+
const skipSegments = new Set([
|
|
1509
|
+
"src",
|
|
1510
|
+
"lib",
|
|
1511
|
+
"app",
|
|
1512
|
+
"apps",
|
|
1513
|
+
"packages",
|
|
1514
|
+
"services",
|
|
1515
|
+
"modules",
|
|
1516
|
+
"features",
|
|
1517
|
+
...Object.values(LAYER_PATTERNS).flat()
|
|
1518
|
+
]);
|
|
1519
|
+
for (const segment of segments) {
|
|
1520
|
+
const segmentLower = segment.toLowerCase();
|
|
1521
|
+
if (skipSegments.has(segmentLower))
|
|
1522
|
+
continue;
|
|
1523
|
+
if (DOMAIN_PATTERNS.includes(segmentLower))
|
|
1524
|
+
return segmentLower;
|
|
1525
|
+
for (const domain of DOMAIN_PATTERNS) {
|
|
1526
|
+
if (segmentLower.startsWith(domain) || segmentLower.endsWith(domain)) {
|
|
1527
|
+
return domain;
|
|
1528
|
+
}
|
|
1529
|
+
}
|
|
1530
|
+
}
|
|
1531
|
+
return;
|
|
1532
|
+
}
|
|
1533
|
+
function detectScope(segments, project, layer) {
|
|
1534
|
+
const projectScope = detectScopeFromName(project.name);
|
|
1535
|
+
if (projectScope !== "unknown")
|
|
1536
|
+
return projectScope;
|
|
1537
|
+
if (layer) {
|
|
1538
|
+
switch (layer) {
|
|
1539
|
+
case "controller":
|
|
1540
|
+
case "repository":
|
|
1541
|
+
case "middleware":
|
|
1542
|
+
return "backend";
|
|
1543
|
+
case "presentation":
|
|
1544
|
+
return "frontend";
|
|
1545
|
+
case "util":
|
|
1546
|
+
case "model":
|
|
1547
|
+
return "shared";
|
|
1548
|
+
case "test":
|
|
1549
|
+
return "tooling";
|
|
1550
|
+
}
|
|
1551
|
+
}
|
|
1552
|
+
for (const segment of segments) {
|
|
1553
|
+
const segmentLower = segment.toLowerCase();
|
|
1554
|
+
if (["server", "api", "backend"].includes(segmentLower))
|
|
1555
|
+
return "backend";
|
|
1556
|
+
if (["client", "web", "frontend", "ui"].includes(segmentLower))
|
|
1557
|
+
return "frontend";
|
|
1558
|
+
if (["shared", "common", "lib", "libs"].includes(segmentLower))
|
|
1559
|
+
return "shared";
|
|
1560
|
+
}
|
|
1561
|
+
return "unknown";
|
|
1562
|
+
}
|
|
1563
|
+
function detectFramework(content) {
|
|
1564
|
+
for (const [framework, indicators] of Object.entries(FRAMEWORK_INDICATORS)) {
|
|
1565
|
+
for (const indicator of indicators) {
|
|
1566
|
+
if (content.includes(`from '${indicator}`) || content.includes(`from "${indicator}`) || content.includes(`require('${indicator}`) || content.includes(`require("${indicator}`)) {
|
|
1567
|
+
return framework;
|
|
1568
|
+
}
|
|
1569
|
+
}
|
|
1570
|
+
}
|
|
1571
|
+
return;
|
|
1572
|
+
}
|
|
1573
|
+
var LAYER_PATTERNS, DOMAIN_PATTERNS, FRAMEWORK_INDICATORS, EXTENSION_TO_LANGUAGE, SCOPE_KEYWORDS, PROJECT_PATTERNS;
|
|
1574
|
+
var init_introspection = __esm(() => {
|
|
1575
|
+
init_conventions();
|
|
1576
|
+
LAYER_PATTERNS = {
|
|
1577
|
+
controller: ["controller", "api", "routes", "route", "handler"],
|
|
1578
|
+
service: ["service", "logic", "usecase", "usecases", "handler"],
|
|
1579
|
+
repository: ["repository", "repo", "dao", "store", "persistence"],
|
|
1580
|
+
model: [
|
|
1581
|
+
"model",
|
|
1582
|
+
"models",
|
|
1583
|
+
"entity",
|
|
1584
|
+
"entities",
|
|
1585
|
+
"schema",
|
|
1586
|
+
"schemas",
|
|
1587
|
+
"types",
|
|
1588
|
+
"type"
|
|
1589
|
+
],
|
|
1590
|
+
util: ["util", "utils", "helper", "helpers", "common", "lib"],
|
|
1591
|
+
config: ["config", "configuration", "settings"],
|
|
1592
|
+
middleware: ["middleware", "middlewares"],
|
|
1593
|
+
domain: ["domain"],
|
|
1594
|
+
infrastructure: ["infrastructure", "infra"],
|
|
1595
|
+
application: ["application", "app"],
|
|
1596
|
+
presentation: [
|
|
1597
|
+
"presentation",
|
|
1598
|
+
"ui",
|
|
1599
|
+
"views",
|
|
1600
|
+
"view",
|
|
1601
|
+
"component",
|
|
1602
|
+
"components"
|
|
1603
|
+
],
|
|
1604
|
+
test: ["test", "tests", "spec", "specs", "__tests__", "e2e"]
|
|
1605
|
+
};
|
|
1606
|
+
DOMAIN_PATTERNS = [
|
|
1607
|
+
"auth",
|
|
1608
|
+
"authentication",
|
|
1609
|
+
"user",
|
|
1610
|
+
"users",
|
|
1611
|
+
"account",
|
|
1612
|
+
"accounts",
|
|
1613
|
+
"profile",
|
|
1614
|
+
"profiles",
|
|
1615
|
+
"product",
|
|
1616
|
+
"products",
|
|
1617
|
+
"item",
|
|
1618
|
+
"items",
|
|
1619
|
+
"catalog",
|
|
1620
|
+
"order",
|
|
1621
|
+
"orders",
|
|
1622
|
+
"cart",
|
|
1623
|
+
"checkout",
|
|
1624
|
+
"payment",
|
|
1625
|
+
"payments",
|
|
1626
|
+
"billing",
|
|
1627
|
+
"subscription",
|
|
1628
|
+
"subscriptions",
|
|
1629
|
+
"notification",
|
|
1630
|
+
"notifications",
|
|
1631
|
+
"email",
|
|
1632
|
+
"sms",
|
|
1633
|
+
"report",
|
|
1634
|
+
"reports",
|
|
1635
|
+
"analytics",
|
|
1636
|
+
"metrics",
|
|
1637
|
+
"dashboard",
|
|
1638
|
+
"admin",
|
|
1639
|
+
"settings",
|
|
1640
|
+
"search",
|
|
1641
|
+
"chat",
|
|
1642
|
+
"message",
|
|
1643
|
+
"messages",
|
|
1644
|
+
"feed",
|
|
1645
|
+
"post",
|
|
1646
|
+
"posts",
|
|
1647
|
+
"comment",
|
|
1648
|
+
"comments",
|
|
1649
|
+
"media",
|
|
1650
|
+
"upload",
|
|
1651
|
+
"file",
|
|
1652
|
+
"files",
|
|
1653
|
+
"storage",
|
|
1654
|
+
"cache",
|
|
1655
|
+
"session",
|
|
1656
|
+
"log",
|
|
1657
|
+
"logs",
|
|
1658
|
+
"audit"
|
|
1659
|
+
];
|
|
1660
|
+
FRAMEWORK_INDICATORS = {
|
|
1661
|
+
nextjs: ["next", "next/"],
|
|
1662
|
+
express: ["express"],
|
|
1663
|
+
fastify: ["fastify"],
|
|
1664
|
+
react: ["react"],
|
|
1665
|
+
vue: ["vue"],
|
|
1666
|
+
angular: ["@angular/"],
|
|
1667
|
+
nestjs: ["@nestjs/"],
|
|
1668
|
+
koa: ["koa"]
|
|
1669
|
+
};
|
|
1670
|
+
EXTENSION_TO_LANGUAGE = {
|
|
1671
|
+
".ts": "typescript",
|
|
1672
|
+
".tsx": "typescript",
|
|
1673
|
+
".js": "javascript",
|
|
1674
|
+
".jsx": "javascript",
|
|
1675
|
+
".mjs": "javascript",
|
|
1676
|
+
".cjs": "javascript",
|
|
1677
|
+
".py": "python",
|
|
1678
|
+
".go": "go",
|
|
1679
|
+
".rs": "rust",
|
|
1680
|
+
".java": "java",
|
|
1681
|
+
".kt": "kotlin",
|
|
1682
|
+
".swift": "swift",
|
|
1683
|
+
".rb": "ruby",
|
|
1684
|
+
".php": "php",
|
|
1685
|
+
".cs": "csharp",
|
|
1686
|
+
".cpp": "cpp",
|
|
1687
|
+
".c": "c",
|
|
1688
|
+
".h": "c",
|
|
1689
|
+
".hpp": "cpp",
|
|
1690
|
+
".md": "markdown",
|
|
1691
|
+
".json": "json",
|
|
1692
|
+
".yaml": "yaml",
|
|
1693
|
+
".yml": "yaml",
|
|
1694
|
+
".txt": "text"
|
|
1695
|
+
};
|
|
1696
|
+
SCOPE_KEYWORDS = {
|
|
1697
|
+
frontend: [
|
|
1698
|
+
"web",
|
|
1699
|
+
"webapp",
|
|
1700
|
+
"frontend",
|
|
1701
|
+
"client",
|
|
1702
|
+
"ui",
|
|
1703
|
+
"app",
|
|
1704
|
+
"mobile",
|
|
1705
|
+
"react",
|
|
1706
|
+
"vue",
|
|
1707
|
+
"angular",
|
|
1708
|
+
"next",
|
|
1709
|
+
"nuxt"
|
|
1710
|
+
],
|
|
1711
|
+
backend: [
|
|
1712
|
+
"api",
|
|
1713
|
+
"server",
|
|
1714
|
+
"backend",
|
|
1715
|
+
"service",
|
|
1716
|
+
"worker",
|
|
1717
|
+
"lambda",
|
|
1718
|
+
"functions"
|
|
1719
|
+
],
|
|
1720
|
+
shared: ["shared", "common", "utils", "lib", "core", "types", "models"],
|
|
1721
|
+
tooling: ["scripts", "tools", "cli", "devtools", "build", "config", "infra"],
|
|
1722
|
+
unknown: []
|
|
1723
|
+
};
|
|
1724
|
+
PROJECT_PATTERNS = [
|
|
1725
|
+
{ pattern: /^apps\/([^/]+)/, type: "app", defaultScope: "unknown" },
|
|
1726
|
+
{ pattern: /^packages\/([^/]+)/, type: "library", defaultScope: "shared" },
|
|
1727
|
+
{ pattern: /^libs\/([^/]+)/, type: "library", defaultScope: "shared" },
|
|
1728
|
+
{ pattern: /^services\/([^/]+)/, type: "service", defaultScope: "backend" },
|
|
1729
|
+
{ pattern: /^scripts\/([^/]+)/, type: "script", defaultScope: "tooling" },
|
|
1730
|
+
{ pattern: /^tools\/([^/]+)/, type: "script", defaultScope: "tooling" }
|
|
1731
|
+
];
|
|
1732
|
+
});
|
|
1733
|
+
|
|
1734
|
+
// src/modules/core/symbols.ts
|
|
1735
|
+
function extractSymbols(content) {
|
|
1736
|
+
const symbols = [];
|
|
1737
|
+
const seenSymbols = new Set;
|
|
1738
|
+
const lines = content.split(`
|
|
1739
|
+
`);
|
|
1740
|
+
for (const { type, pattern, exported } of SYMBOL_PATTERNS) {
|
|
1741
|
+
pattern.lastIndex = 0;
|
|
1742
|
+
let match;
|
|
1743
|
+
while ((match = pattern.exec(content)) !== null) {
|
|
1744
|
+
const name = match[1];
|
|
1745
|
+
const symbolKey = `${name}:${type}`;
|
|
1746
|
+
if (seenSymbols.has(symbolKey))
|
|
1747
|
+
continue;
|
|
1748
|
+
seenSymbols.add(symbolKey);
|
|
1749
|
+
const beforeMatch = content.substring(0, match.index);
|
|
1750
|
+
const line = beforeMatch.split(`
|
|
1751
|
+
`).length;
|
|
1752
|
+
symbols.push({
|
|
1753
|
+
name,
|
|
1754
|
+
type,
|
|
1755
|
+
line,
|
|
1756
|
+
isExported: exported
|
|
1757
|
+
});
|
|
1758
|
+
}
|
|
1759
|
+
}
|
|
1760
|
+
return symbols.sort((a, b) => a.line - b.line);
|
|
1761
|
+
}
|
|
1762
|
+
function symbolsToKeywords(symbols) {
|
|
1763
|
+
const keywords = new Set;
|
|
1764
|
+
for (const symbol of symbols) {
|
|
1765
|
+
keywords.add(symbol.name.toLowerCase());
|
|
1766
|
+
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+/);
|
|
1767
|
+
for (const part of parts) {
|
|
1768
|
+
if (part.length > 2) {
|
|
1769
|
+
keywords.add(part);
|
|
1770
|
+
}
|
|
1771
|
+
}
|
|
1772
|
+
}
|
|
1773
|
+
return Array.from(keywords);
|
|
1774
|
+
}
|
|
1775
|
+
var SYMBOL_PATTERNS;
|
|
1776
|
+
var init_symbols = __esm(() => {
|
|
1777
|
+
SYMBOL_PATTERNS = [
|
|
1778
|
+
{
|
|
1779
|
+
type: "function",
|
|
1780
|
+
pattern: /^export\s+(?:async\s+)?function\s+(\w+)/gm,
|
|
1781
|
+
exported: true
|
|
1782
|
+
},
|
|
1783
|
+
{
|
|
1784
|
+
type: "function",
|
|
1785
|
+
pattern: /^export\s+(?:const|let)\s+(\w+)\s*=\s*(?:async\s*)?\(/gm,
|
|
1786
|
+
exported: true
|
|
1787
|
+
},
|
|
1788
|
+
{
|
|
1789
|
+
type: "class",
|
|
1790
|
+
pattern: /^export\s+(?:abstract\s+)?class\s+(\w+)/gm,
|
|
1791
|
+
exported: true
|
|
1792
|
+
},
|
|
1793
|
+
{
|
|
1794
|
+
type: "interface",
|
|
1795
|
+
pattern: /^export\s+interface\s+(\w+)/gm,
|
|
1796
|
+
exported: true
|
|
1797
|
+
},
|
|
1798
|
+
{
|
|
1799
|
+
type: "type",
|
|
1800
|
+
pattern: /^export\s+type\s+(\w+)/gm,
|
|
1801
|
+
exported: true
|
|
1802
|
+
},
|
|
1803
|
+
{
|
|
1804
|
+
type: "enum",
|
|
1805
|
+
pattern: /^export\s+(?:const\s+)?enum\s+(\w+)/gm,
|
|
1806
|
+
exported: true
|
|
1807
|
+
},
|
|
1808
|
+
{
|
|
1809
|
+
type: "variable",
|
|
1810
|
+
pattern: /^export\s+(?:const|let|var)\s+(\w+)\s*(?::|=)/gm,
|
|
1811
|
+
exported: true
|
|
1812
|
+
},
|
|
1813
|
+
{
|
|
1814
|
+
type: "function",
|
|
1815
|
+
pattern: /^export\s+default\s+(?:async\s+)?function\s+(\w+)/gm,
|
|
1816
|
+
exported: true
|
|
1817
|
+
},
|
|
1818
|
+
{
|
|
1819
|
+
type: "class",
|
|
1820
|
+
pattern: /^export\s+default\s+class\s+(\w+)/gm,
|
|
1821
|
+
exported: true
|
|
1822
|
+
},
|
|
1823
|
+
{
|
|
1824
|
+
type: "function",
|
|
1825
|
+
pattern: /^(?:async\s+)?function\s+(\w+)/gm,
|
|
1826
|
+
exported: false
|
|
1827
|
+
},
|
|
1828
|
+
{
|
|
1829
|
+
type: "function",
|
|
1830
|
+
pattern: /^(?:const|let)\s+(\w+)\s*=\s*(?:async\s*)?\(/gm,
|
|
1831
|
+
exported: false
|
|
1832
|
+
},
|
|
1833
|
+
{
|
|
1834
|
+
type: "class",
|
|
1835
|
+
pattern: /^(?:abstract\s+)?class\s+(\w+)/gm,
|
|
1836
|
+
exported: false
|
|
1837
|
+
},
|
|
1838
|
+
{
|
|
1839
|
+
type: "interface",
|
|
1840
|
+
pattern: /^interface\s+(\w+)/gm,
|
|
1841
|
+
exported: false
|
|
1842
|
+
},
|
|
1843
|
+
{
|
|
1844
|
+
type: "type",
|
|
1845
|
+
pattern: /^type\s+(\w+)/gm,
|
|
1846
|
+
exported: false
|
|
1847
|
+
},
|
|
1848
|
+
{
|
|
1849
|
+
type: "enum",
|
|
1850
|
+
pattern: /^(?:const\s+)?enum\s+(\w+)/gm,
|
|
1851
|
+
exported: false
|
|
1852
|
+
},
|
|
1853
|
+
{
|
|
1854
|
+
type: "function",
|
|
1855
|
+
pattern: /^def\s+(\w+)\s*\(/gm,
|
|
1856
|
+
exported: false
|
|
1857
|
+
},
|
|
1858
|
+
{
|
|
1859
|
+
type: "class",
|
|
1860
|
+
pattern: /^class\s+(\w+)(?:\s*\(|:)/gm,
|
|
1861
|
+
exported: false
|
|
1862
|
+
},
|
|
1863
|
+
{
|
|
1864
|
+
type: "function",
|
|
1865
|
+
pattern: /^func\s+(?:\([^)]+\)\s+)?(\w+)\s*\(/gm,
|
|
1866
|
+
exported: false
|
|
1867
|
+
},
|
|
1868
|
+
{
|
|
1869
|
+
type: "type",
|
|
1870
|
+
pattern: /^type\s+(\w+)\s+(?:struct|interface)/gm,
|
|
1871
|
+
exported: false
|
|
1872
|
+
},
|
|
1873
|
+
{
|
|
1874
|
+
type: "function",
|
|
1875
|
+
pattern: /^(?:pub\s+)?(?:async\s+)?fn\s+(\w+)/gm,
|
|
1876
|
+
exported: false
|
|
1877
|
+
},
|
|
1878
|
+
{
|
|
1879
|
+
type: "type",
|
|
1880
|
+
pattern: /^(?:pub\s+)?struct\s+(\w+)/gm,
|
|
1881
|
+
exported: false
|
|
1882
|
+
},
|
|
1883
|
+
{
|
|
1884
|
+
type: "enum",
|
|
1885
|
+
pattern: /^(?:pub\s+)?enum\s+(\w+)/gm,
|
|
1886
|
+
exported: false
|
|
1887
|
+
},
|
|
1888
|
+
{
|
|
1889
|
+
type: "interface",
|
|
1890
|
+
pattern: /^(?:pub\s+)?trait\s+(\w+)/gm,
|
|
1891
|
+
exported: false
|
|
1892
|
+
}
|
|
1893
|
+
];
|
|
1894
|
+
});
|
|
1895
|
+
|
|
1896
|
+
// src/modules/core/index.ts
|
|
1897
|
+
var exports_core = {};
|
|
1898
|
+
__export(exports_core, {
|
|
1899
|
+
CoreModule: () => CoreModule
|
|
1900
|
+
});
|
|
1901
|
+
import * as path6 from "path";
|
|
1902
|
+
import * as fs2 from "fs/promises";
|
|
1903
|
+
|
|
1904
|
+
class CoreModule {
|
|
1905
|
+
id = "core";
|
|
1906
|
+
name = "Core Search";
|
|
1907
|
+
description = "Language-agnostic text search with symbol extraction";
|
|
1908
|
+
version = "1.0.0";
|
|
1909
|
+
symbolIndex = new Map;
|
|
1910
|
+
bm25Index = null;
|
|
1911
|
+
rootDir = "";
|
|
1912
|
+
async initialize(_config) {}
|
|
1913
|
+
async indexFile(filepath, content, ctx) {
|
|
1914
|
+
this.rootDir = ctx.rootDir;
|
|
1915
|
+
const symbols = extractSymbols(content);
|
|
1916
|
+
const symbolKeywords = symbolsToKeywords(symbols);
|
|
1917
|
+
const contentTokens = tokenize(content);
|
|
1918
|
+
const intro = ctx.getIntrospection?.(filepath);
|
|
1919
|
+
const introKeywords = intro ? introspectionToKeywords(intro) : [];
|
|
1920
|
+
const allTokens = [
|
|
1921
|
+
...new Set([...contentTokens, ...symbolKeywords, ...introKeywords])
|
|
1922
|
+
];
|
|
1923
|
+
const chunks = this.createChunks(filepath, content, symbols);
|
|
1924
|
+
const stats = await ctx.getFileStats(filepath);
|
|
1925
|
+
this.symbolIndex.set(filepath, {
|
|
1926
|
+
filepath,
|
|
1927
|
+
symbols,
|
|
1928
|
+
tokens: allTokens
|
|
1929
|
+
});
|
|
1930
|
+
const moduleData = {
|
|
1931
|
+
symbols,
|
|
1932
|
+
tokens: allTokens
|
|
1933
|
+
};
|
|
1934
|
+
return {
|
|
1935
|
+
filepath,
|
|
1936
|
+
lastModified: stats.lastModified,
|
|
1937
|
+
chunks,
|
|
1938
|
+
moduleData
|
|
1939
|
+
};
|
|
1940
|
+
}
|
|
1941
|
+
createChunks(filepath, content, symbols) {
|
|
1942
|
+
const lines = content.split(`
|
|
1943
|
+
`);
|
|
1944
|
+
const chunks = [];
|
|
1945
|
+
for (let start = 0;start < lines.length; start += LINES_PER_CHUNK - CHUNK_OVERLAP) {
|
|
1946
|
+
const end = Math.min(start + LINES_PER_CHUNK, lines.length);
|
|
1947
|
+
const chunkLines = lines.slice(start, end);
|
|
1948
|
+
const chunkContent = chunkLines.join(`
|
|
1949
|
+
`);
|
|
1950
|
+
const chunkSymbols = symbols.filter((s) => s.line >= start + 1 && s.line <= end);
|
|
1951
|
+
let chunkType = "block";
|
|
1952
|
+
let chunkName;
|
|
1953
|
+
let isExported = false;
|
|
1954
|
+
if (chunkSymbols.length > 0) {
|
|
1955
|
+
const primarySymbol = chunkSymbols[0];
|
|
1956
|
+
chunkType = this.symbolTypeToChunkType(primarySymbol.type);
|
|
1957
|
+
chunkName = primarySymbol.name;
|
|
1958
|
+
isExported = primarySymbol.isExported;
|
|
1959
|
+
}
|
|
1960
|
+
const chunkId = `${filepath}:${start + 1}-${end}`;
|
|
1961
|
+
chunks.push({
|
|
1962
|
+
id: chunkId,
|
|
1963
|
+
content: chunkContent,
|
|
1964
|
+
startLine: start + 1,
|
|
1965
|
+
endLine: end,
|
|
1966
|
+
type: chunkType,
|
|
1967
|
+
name: chunkName,
|
|
1968
|
+
isExported
|
|
1969
|
+
});
|
|
1970
|
+
if (end >= lines.length)
|
|
1971
|
+
break;
|
|
1972
|
+
}
|
|
1973
|
+
return chunks;
|
|
1974
|
+
}
|
|
1975
|
+
symbolTypeToChunkType(symbolType) {
|
|
1976
|
+
switch (symbolType) {
|
|
1977
|
+
case "function":
|
|
1978
|
+
case "method":
|
|
1979
|
+
return "function";
|
|
1980
|
+
case "class":
|
|
1981
|
+
return "class";
|
|
1982
|
+
case "interface":
|
|
1983
|
+
return "interface";
|
|
1984
|
+
case "type":
|
|
1985
|
+
return "type";
|
|
1986
|
+
case "enum":
|
|
1987
|
+
return "enum";
|
|
1988
|
+
case "variable":
|
|
1989
|
+
return "variable";
|
|
1990
|
+
default:
|
|
1991
|
+
return "block";
|
|
1992
|
+
}
|
|
1993
|
+
}
|
|
1994
|
+
async finalize(ctx) {
|
|
1995
|
+
const config = ctx.config;
|
|
1996
|
+
const coreDir = path6.join(getRaggrepDir(ctx.rootDir, config), "index", "core");
|
|
1997
|
+
await fs2.mkdir(coreDir, { recursive: true });
|
|
1998
|
+
this.bm25Index = new BM25Index;
|
|
1999
|
+
for (const [filepath, entry] of this.symbolIndex) {
|
|
2000
|
+
this.bm25Index.addDocument(filepath, entry.tokens);
|
|
2001
|
+
}
|
|
2002
|
+
const symbolIndexData = {
|
|
2003
|
+
version: this.version,
|
|
2004
|
+
lastUpdated: new Date().toISOString(),
|
|
2005
|
+
files: Object.fromEntries(this.symbolIndex),
|
|
2006
|
+
bm25Data: this.bm25Index.serialize()
|
|
2007
|
+
};
|
|
2008
|
+
await fs2.writeFile(path6.join(coreDir, "symbols.json"), JSON.stringify(symbolIndexData, null, 2));
|
|
2009
|
+
console.log(` [Core] Symbol index built with ${this.symbolIndex.size} files`);
|
|
2010
|
+
}
|
|
2011
|
+
async search(query, ctx, options) {
|
|
2012
|
+
const config = ctx.config;
|
|
2013
|
+
const topK = options?.topK ?? DEFAULT_TOP_K;
|
|
2014
|
+
const minScore = options?.minScore ?? DEFAULT_MIN_SCORE;
|
|
2015
|
+
if (this.symbolIndex.size === 0) {
|
|
2016
|
+
await this.loadSymbolIndex(ctx.rootDir, config);
|
|
2017
|
+
}
|
|
2018
|
+
if (!this.bm25Index || this.symbolIndex.size === 0) {
|
|
2019
|
+
return [];
|
|
2020
|
+
}
|
|
2021
|
+
const queryTokens = tokenize(query);
|
|
2022
|
+
const bm25Results = this.bm25Index.search(query, topK * 2);
|
|
2023
|
+
const bm25Scores = new Map(bm25Results.map((r) => [r.id, r.score]));
|
|
2024
|
+
const symbolMatches = this.findSymbolMatches(queryTokens);
|
|
2025
|
+
const results = [];
|
|
2026
|
+
for (const filepath of this.symbolIndex.keys()) {
|
|
2027
|
+
const entry = this.symbolIndex.get(filepath);
|
|
2028
|
+
const bm25Score = bm25Scores.get(filepath) ?? 0;
|
|
2029
|
+
const symbolScore = symbolMatches.get(filepath) ?? 0;
|
|
2030
|
+
if (bm25Score === 0 && symbolScore === 0)
|
|
2031
|
+
continue;
|
|
2032
|
+
const combinedScore = 0.6 * normalizeScore(bm25Score) + 0.4 * symbolScore;
|
|
2033
|
+
if (combinedScore >= minScore) {
|
|
2034
|
+
const fileIndex = await ctx.loadFileIndex(filepath);
|
|
2035
|
+
if (!fileIndex)
|
|
2036
|
+
continue;
|
|
2037
|
+
const bestChunk = this.findBestChunk(fileIndex.chunks, queryTokens, entry.symbols);
|
|
2038
|
+
results.push({
|
|
2039
|
+
filepath,
|
|
2040
|
+
chunk: bestChunk,
|
|
2041
|
+
score: combinedScore,
|
|
2042
|
+
moduleId: this.id,
|
|
2043
|
+
context: {
|
|
2044
|
+
bm25Score: normalizeScore(bm25Score),
|
|
2045
|
+
symbolScore
|
|
2046
|
+
}
|
|
2047
|
+
});
|
|
2048
|
+
}
|
|
2049
|
+
}
|
|
2050
|
+
return results.sort((a, b) => b.score - a.score).slice(0, topK);
|
|
2051
|
+
}
|
|
2052
|
+
findSymbolMatches(queryTokens) {
|
|
2053
|
+
const matches = new Map;
|
|
2054
|
+
for (const [filepath, entry] of this.symbolIndex) {
|
|
2055
|
+
let matchScore = 0;
|
|
2056
|
+
for (const symbol of entry.symbols) {
|
|
2057
|
+
const symbolName = symbol.name.toLowerCase();
|
|
2058
|
+
const symbolParts = symbolsToKeywords([symbol]);
|
|
2059
|
+
for (const token of queryTokens) {
|
|
2060
|
+
if (symbolName === token) {
|
|
2061
|
+
matchScore += symbol.isExported ? 1 : 0.8;
|
|
2062
|
+
} else if (symbolName.includes(token) || token.includes(symbolName)) {
|
|
2063
|
+
matchScore += symbol.isExported ? 0.5 : 0.4;
|
|
2064
|
+
} else if (symbolParts.some((p) => p === token)) {
|
|
2065
|
+
matchScore += symbol.isExported ? 0.3 : 0.2;
|
|
2066
|
+
}
|
|
2067
|
+
}
|
|
2068
|
+
}
|
|
2069
|
+
if (matchScore > 0) {
|
|
2070
|
+
matches.set(filepath, Math.min(1, matchScore / queryTokens.length));
|
|
2071
|
+
}
|
|
2072
|
+
}
|
|
2073
|
+
return matches;
|
|
2074
|
+
}
|
|
2075
|
+
findBestChunk(chunks, queryTokens, symbols) {
|
|
2076
|
+
let bestChunk = chunks[0];
|
|
2077
|
+
let bestScore = 0;
|
|
2078
|
+
for (const chunk of chunks) {
|
|
2079
|
+
let score = 0;
|
|
2080
|
+
const chunkContent = chunk.content.toLowerCase();
|
|
2081
|
+
for (const token of queryTokens) {
|
|
2082
|
+
if (chunkContent.includes(token)) {
|
|
2083
|
+
score += 1;
|
|
2084
|
+
}
|
|
2085
|
+
}
|
|
2086
|
+
if (chunk.name) {
|
|
2087
|
+
const nameLower = chunk.name.toLowerCase();
|
|
2088
|
+
for (const token of queryTokens) {
|
|
2089
|
+
if (nameLower.includes(token)) {
|
|
2090
|
+
score += 2;
|
|
2091
|
+
}
|
|
2092
|
+
}
|
|
2093
|
+
}
|
|
2094
|
+
if (chunk.isExported) {
|
|
2095
|
+
score += 0.5;
|
|
2096
|
+
}
|
|
2097
|
+
if (score > bestScore) {
|
|
2098
|
+
bestScore = score;
|
|
2099
|
+
bestChunk = chunk;
|
|
2100
|
+
}
|
|
2101
|
+
}
|
|
2102
|
+
return bestChunk;
|
|
2103
|
+
}
|
|
2104
|
+
async loadSymbolIndex(rootDir, config) {
|
|
2105
|
+
const coreDir = path6.join(getRaggrepDir(rootDir, config), "index", "core");
|
|
2106
|
+
const symbolsPath = path6.join(coreDir, "symbols.json");
|
|
2107
|
+
try {
|
|
2108
|
+
const content = await fs2.readFile(symbolsPath, "utf-8");
|
|
2109
|
+
const data = JSON.parse(content);
|
|
2110
|
+
this.symbolIndex = new Map(Object.entries(data.files));
|
|
2111
|
+
if (data.bm25Data) {
|
|
2112
|
+
this.bm25Index = BM25Index.deserialize(data.bm25Data);
|
|
2113
|
+
}
|
|
2114
|
+
} catch (error) {
|
|
2115
|
+
this.symbolIndex = new Map;
|
|
2116
|
+
this.bm25Index = null;
|
|
2117
|
+
}
|
|
2118
|
+
}
|
|
2119
|
+
async dispose() {
|
|
2120
|
+
this.symbolIndex.clear();
|
|
2121
|
+
this.bm25Index = null;
|
|
2122
|
+
}
|
|
2123
|
+
}
|
|
2124
|
+
var DEFAULT_MIN_SCORE = 0.1, DEFAULT_TOP_K = 20, LINES_PER_CHUNK = 50, CHUNK_OVERLAP = 10;
|
|
2125
|
+
var init_core = __esm(() => {
|
|
2126
|
+
init_config2();
|
|
2127
|
+
init_introspection();
|
|
2128
|
+
init_symbols();
|
|
2129
|
+
});
|
|
2130
|
+
|
|
2131
|
+
// src/domain/services/similarity.ts
|
|
2132
|
+
function cosineSimilarity(a, b) {
|
|
2133
|
+
if (a.length !== b.length) {
|
|
2134
|
+
throw new Error(`Vector length mismatch: ${a.length} vs ${b.length}`);
|
|
2135
|
+
}
|
|
2136
|
+
let dotProduct = 0;
|
|
2137
|
+
let normA = 0;
|
|
809
2138
|
let normB = 0;
|
|
810
2139
|
for (let i = 0;i < a.length; i++) {
|
|
811
2140
|
dotProduct += a[i] * b[i];
|
|
@@ -1064,7 +2393,7 @@ function parsePathContext(filepath) {
|
|
|
1064
2393
|
let layer;
|
|
1065
2394
|
const allLower = [...dirSegments, filename].map((s) => s.toLowerCase()).join(" ");
|
|
1066
2395
|
const filenameLower = filename.toLowerCase();
|
|
1067
|
-
for (const [layerName, patterns] of Object.entries(
|
|
2396
|
+
for (const [layerName, patterns] of Object.entries(LAYER_PATTERNS2)) {
|
|
1068
2397
|
for (const pattern of patterns) {
|
|
1069
2398
|
if (filenameLower.includes(pattern)) {
|
|
1070
2399
|
layer = layerName;
|
|
@@ -1079,7 +2408,7 @@ function parsePathContext(filepath) {
|
|
|
1079
2408
|
break;
|
|
1080
2409
|
}
|
|
1081
2410
|
let domain;
|
|
1082
|
-
const layerPatternSet = new Set(Object.values(
|
|
2411
|
+
const layerPatternSet = new Set(Object.values(LAYER_PATTERNS2).flat());
|
|
1083
2412
|
const reversedSegments = [...dirSegments].reverse();
|
|
1084
2413
|
for (const segment of reversedSegments) {
|
|
1085
2414
|
const lower = segment.toLowerCase();
|
|
@@ -1117,7 +2446,7 @@ function formatPathContextForEmbedding(pathContext) {
|
|
|
1117
2446
|
const unique = [...new Set(parts)];
|
|
1118
2447
|
return `[${unique.join(" ")}]`;
|
|
1119
2448
|
}
|
|
1120
|
-
var COMMON_KEYWORDS,
|
|
2449
|
+
var COMMON_KEYWORDS, LAYER_PATTERNS2;
|
|
1121
2450
|
var init_keywords = __esm(() => {
|
|
1122
2451
|
COMMON_KEYWORDS = new Set([
|
|
1123
2452
|
"const",
|
|
@@ -1187,7 +2516,7 @@ var init_keywords = __esm(() => {
|
|
|
1187
2516
|
"has",
|
|
1188
2517
|
"have"
|
|
1189
2518
|
]);
|
|
1190
|
-
|
|
2519
|
+
LAYER_PATTERNS2 = {
|
|
1191
2520
|
controller: ["controller", "controllers", "handler", "handlers", "route", "routes", "api"],
|
|
1192
2521
|
service: ["service", "services", "usecase", "usecases", "application"],
|
|
1193
2522
|
repository: ["repository", "repositories", "repo", "repos", "dao", "store", "storage"],
|
|
@@ -1204,7 +2533,7 @@ var init_keywords = __esm(() => {
|
|
|
1204
2533
|
|
|
1205
2534
|
// src/infrastructure/storage/symbolicIndex.ts
|
|
1206
2535
|
import * as fs3 from "fs/promises";
|
|
1207
|
-
import * as
|
|
2536
|
+
import * as path7 from "path";
|
|
1208
2537
|
|
|
1209
2538
|
class SymbolicIndex {
|
|
1210
2539
|
meta = null;
|
|
@@ -1213,7 +2542,7 @@ class SymbolicIndex {
|
|
|
1213
2542
|
symbolicPath;
|
|
1214
2543
|
moduleId;
|
|
1215
2544
|
constructor(indexDir, moduleId) {
|
|
1216
|
-
this.symbolicPath =
|
|
2545
|
+
this.symbolicPath = path7.join(indexDir, "index", moduleId, "symbolic");
|
|
1217
2546
|
this.moduleId = moduleId;
|
|
1218
2547
|
}
|
|
1219
2548
|
async initialize() {
|
|
@@ -1274,16 +2603,16 @@ class SymbolicIndex {
|
|
|
1274
2603
|
this.meta.lastUpdated = new Date().toISOString();
|
|
1275
2604
|
this.meta.fileCount = this.fileSummaries.size;
|
|
1276
2605
|
await fs3.mkdir(this.symbolicPath, { recursive: true });
|
|
1277
|
-
const metaPath =
|
|
2606
|
+
const metaPath = path7.join(this.symbolicPath, "_meta.json");
|
|
1278
2607
|
await fs3.writeFile(metaPath, JSON.stringify(this.meta, null, 2));
|
|
1279
2608
|
for (const [filepath, summary] of this.fileSummaries) {
|
|
1280
2609
|
const summaryPath = this.getFileSummaryPath(filepath);
|
|
1281
|
-
await fs3.mkdir(
|
|
2610
|
+
await fs3.mkdir(path7.dirname(summaryPath), { recursive: true });
|
|
1282
2611
|
await fs3.writeFile(summaryPath, JSON.stringify(summary, null, 2));
|
|
1283
2612
|
}
|
|
1284
2613
|
}
|
|
1285
2614
|
async load() {
|
|
1286
|
-
const metaPath =
|
|
2615
|
+
const metaPath = path7.join(this.symbolicPath, "_meta.json");
|
|
1287
2616
|
const metaContent = await fs3.readFile(metaPath, "utf-8");
|
|
1288
2617
|
this.meta = JSON.parse(metaContent);
|
|
1289
2618
|
this.fileSummaries.clear();
|
|
@@ -1294,7 +2623,7 @@ class SymbolicIndex {
|
|
|
1294
2623
|
try {
|
|
1295
2624
|
const entries = await fs3.readdir(dir, { withFileTypes: true });
|
|
1296
2625
|
for (const entry of entries) {
|
|
1297
|
-
const fullPath =
|
|
2626
|
+
const fullPath = path7.join(dir, entry.name);
|
|
1298
2627
|
if (entry.isDirectory()) {
|
|
1299
2628
|
await this.loadFileSummariesRecursive(fullPath);
|
|
1300
2629
|
} else if (entry.name.endsWith(".json") && entry.name !== "_meta.json") {
|
|
@@ -1311,7 +2640,7 @@ class SymbolicIndex {
|
|
|
1311
2640
|
}
|
|
1312
2641
|
getFileSummaryPath(filepath) {
|
|
1313
2642
|
const jsonPath = filepath.replace(/\.[^.]+$/, ".json");
|
|
1314
|
-
return
|
|
2643
|
+
return path7.join(this.symbolicPath, jsonPath);
|
|
1315
2644
|
}
|
|
1316
2645
|
async deleteFileSummary(filepath) {
|
|
1317
2646
|
try {
|
|
@@ -1321,7 +2650,7 @@ class SymbolicIndex {
|
|
|
1321
2650
|
}
|
|
1322
2651
|
async exists() {
|
|
1323
2652
|
try {
|
|
1324
|
-
const metaPath =
|
|
2653
|
+
const metaPath = path7.join(this.symbolicPath, "_meta.json");
|
|
1325
2654
|
await fs3.access(metaPath);
|
|
1326
2655
|
return true;
|
|
1327
2656
|
} catch {
|
|
@@ -1361,7 +2690,7 @@ __export(exports_typescript, {
|
|
|
1361
2690
|
DEFAULT_TOP_K: () => DEFAULT_TOP_K2,
|
|
1362
2691
|
DEFAULT_MIN_SCORE: () => DEFAULT_MIN_SCORE2
|
|
1363
2692
|
});
|
|
1364
|
-
import * as
|
|
2693
|
+
import * as path8 from "path";
|
|
1365
2694
|
|
|
1366
2695
|
class TypeScriptModule {
|
|
1367
2696
|
id = "language/typescript";
|
|
@@ -1533,549 +2862,235 @@ class TypeScriptModule {
|
|
|
1533
2862
|
if (hybridScore >= minScore || bm25Score > 0.3) {
|
|
1534
2863
|
results.push({
|
|
1535
2864
|
filepath,
|
|
1536
|
-
chunk,
|
|
1537
|
-
score: hybridScore,
|
|
1538
|
-
moduleId: this.id,
|
|
1539
|
-
context: {
|
|
1540
|
-
semanticScore,
|
|
1541
|
-
bm25Score,
|
|
1542
|
-
pathBoost
|
|
1543
|
-
}
|
|
1544
|
-
});
|
|
1545
|
-
}
|
|
1546
|
-
}
|
|
1547
|
-
results.sort((a, b) => b.score - a.score);
|
|
1548
|
-
return results.slice(0, topK);
|
|
1549
|
-
}
|
|
1550
|
-
extractReferences(content, filepath) {
|
|
1551
|
-
const references = [];
|
|
1552
|
-
const importRegex = /import\s+.*?\s+from\s+['"]([^'"]+)['"]/g;
|
|
1553
|
-
const requireRegex = /require\s*\(\s*['"]([^'"]+)['"]\s*\)/g;
|
|
1554
|
-
let match;
|
|
1555
|
-
while ((match = importRegex.exec(content)) !== null) {
|
|
1556
|
-
const importPath = match[1];
|
|
1557
|
-
if (importPath.startsWith(".")) {
|
|
1558
|
-
const dir = path5.dirname(filepath);
|
|
1559
|
-
const resolved = path5.normalize(path5.join(dir, importPath));
|
|
1560
|
-
references.push(resolved);
|
|
1561
|
-
}
|
|
1562
|
-
}
|
|
1563
|
-
while ((match = requireRegex.exec(content)) !== null) {
|
|
1564
|
-
const importPath = match[1];
|
|
1565
|
-
if (importPath.startsWith(".")) {
|
|
1566
|
-
const dir = path5.dirname(filepath);
|
|
1567
|
-
const resolved = path5.normalize(path5.join(dir, importPath));
|
|
1568
|
-
references.push(resolved);
|
|
1569
|
-
}
|
|
1570
|
-
}
|
|
1571
|
-
return references;
|
|
1572
|
-
}
|
|
1573
|
-
}
|
|
1574
|
-
var DEFAULT_MIN_SCORE2 = 0.15, DEFAULT_TOP_K2 = 10, SEMANTIC_WEIGHT = 0.7, BM25_WEIGHT = 0.3, TIER1_CANDIDATE_MULTIPLIER = 3;
|
|
1575
|
-
var init_typescript = __esm(() => {
|
|
1576
|
-
init_embeddings();
|
|
1577
|
-
init_config2();
|
|
1578
|
-
init_parseCode();
|
|
1579
|
-
init_storage();
|
|
1580
|
-
init_keywords();
|
|
1581
|
-
init_keywords();
|
|
1582
|
-
});
|
|
1583
|
-
|
|
1584
|
-
// src/modules/registry.ts
|
|
1585
|
-
class ModuleRegistryImpl {
|
|
1586
|
-
modules = new Map;
|
|
1587
|
-
register(module) {
|
|
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());
|
|
1598
|
-
}
|
|
1599
|
-
getEnabled(config) {
|
|
1600
|
-
const enabledIds = new Set(config.modules.filter((m) => m.enabled).map((m) => m.id));
|
|
1601
|
-
return this.list().filter((m) => enabledIds.has(m.id));
|
|
1602
|
-
}
|
|
1603
|
-
}
|
|
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
|
-
|
|
1615
|
-
// src/introspection/projectDetector.ts
|
|
1616
|
-
import * as path6 from "path";
|
|
1617
|
-
import * as fs4 from "fs/promises";
|
|
1618
|
-
function detectScopeFromName(name) {
|
|
1619
|
-
const nameLower = name.toLowerCase();
|
|
1620
|
-
for (const [scope, keywords] of Object.entries(SCOPE_KEYWORDS)) {
|
|
1621
|
-
if (scope === "unknown")
|
|
1622
|
-
continue;
|
|
1623
|
-
for (const keyword of keywords) {
|
|
1624
|
-
if (nameLower.includes(keyword)) {
|
|
1625
|
-
return scope;
|
|
1626
|
-
}
|
|
1627
|
-
}
|
|
1628
|
-
}
|
|
1629
|
-
return "unknown";
|
|
1630
|
-
}
|
|
1631
|
-
async function scanForPackageJsons(rootDir, currentDir = "", depth = 0) {
|
|
1632
|
-
if (depth > MAX_SCAN_DEPTH)
|
|
1633
|
-
return [];
|
|
1634
|
-
const results = [];
|
|
1635
|
-
const fullDir = currentDir ? path6.join(rootDir, currentDir) : rootDir;
|
|
1636
|
-
try {
|
|
1637
|
-
const entries = await fs4.readdir(fullDir, { withFileTypes: true });
|
|
1638
|
-
const hasPackageJson = entries.some((e) => e.isFile() && e.name === "package.json");
|
|
1639
|
-
if (hasPackageJson && currentDir) {
|
|
1640
|
-
const info = await parsePackageJson(rootDir, currentDir);
|
|
1641
|
-
if (info) {
|
|
1642
|
-
results.push(info);
|
|
1643
|
-
}
|
|
1644
|
-
}
|
|
1645
|
-
for (const entry of entries) {
|
|
1646
|
-
if (!entry.isDirectory())
|
|
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);
|
|
1653
|
-
}
|
|
1654
|
-
} catch {}
|
|
1655
|
-
return results;
|
|
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";
|
|
1671
|
-
}
|
|
1672
|
-
const hasWorkspaces = Boolean(pkg.workspaces);
|
|
1673
|
-
return { name, relativePath, type, hasWorkspaces };
|
|
1674
|
-
} catch {
|
|
1675
|
-
return null;
|
|
1676
|
-
}
|
|
1677
|
-
}
|
|
1678
|
-
async function detectProjectStructure(rootDir) {
|
|
1679
|
-
const projectMap = new Map;
|
|
1680
|
-
let isMonorepo = false;
|
|
1681
|
-
try {
|
|
1682
|
-
const entries = await fs4.readdir(rootDir, { withFileTypes: true });
|
|
1683
|
-
const dirNames = entries.filter((e) => e.isDirectory()).map((e) => e.name);
|
|
1684
|
-
const monorepoPatterns = ["apps", "packages", "libs", "services"];
|
|
1685
|
-
const hasMonorepoStructure = monorepoPatterns.some((p) => dirNames.includes(p));
|
|
1686
|
-
if (hasMonorepoStructure) {
|
|
1687
|
-
isMonorepo = true;
|
|
1688
|
-
for (const pattern of monorepoPatterns) {
|
|
1689
|
-
if (!dirNames.includes(pattern))
|
|
1690
|
-
continue;
|
|
1691
|
-
const patternDir = path6.join(rootDir, pattern);
|
|
1692
|
-
try {
|
|
1693
|
-
const subDirs = await fs4.readdir(patternDir, { withFileTypes: true });
|
|
1694
|
-
for (const subDir of subDirs) {
|
|
1695
|
-
if (!subDir.isDirectory())
|
|
1696
|
-
continue;
|
|
1697
|
-
const projectRoot = `${pattern}/${subDir.name}`;
|
|
1698
|
-
const type = getProjectType(pattern);
|
|
1699
|
-
projectMap.set(projectRoot, {
|
|
1700
|
-
name: subDir.name,
|
|
1701
|
-
root: projectRoot,
|
|
1702
|
-
type
|
|
1703
|
-
});
|
|
2865
|
+
chunk,
|
|
2866
|
+
score: hybridScore,
|
|
2867
|
+
moduleId: this.id,
|
|
2868
|
+
context: {
|
|
2869
|
+
semanticScore,
|
|
2870
|
+
bm25Score,
|
|
2871
|
+
pathBoost
|
|
1704
2872
|
}
|
|
1705
|
-
}
|
|
2873
|
+
});
|
|
1706
2874
|
}
|
|
1707
2875
|
}
|
|
1708
|
-
|
|
1709
|
-
|
|
1710
|
-
|
|
1711
|
-
|
|
1712
|
-
|
|
1713
|
-
|
|
1714
|
-
|
|
2876
|
+
results.sort((a, b) => b.score - a.score);
|
|
2877
|
+
return results.slice(0, topK);
|
|
2878
|
+
}
|
|
2879
|
+
extractReferences(content, filepath) {
|
|
2880
|
+
const references = [];
|
|
2881
|
+
const importRegex = /import\s+.*?\s+from\s+['"]([^'"]+)['"]/g;
|
|
2882
|
+
const requireRegex = /require\s*\(\s*['"]([^'"]+)['"]\s*\)/g;
|
|
2883
|
+
let match;
|
|
2884
|
+
while ((match = importRegex.exec(content)) !== null) {
|
|
2885
|
+
const importPath = match[1];
|
|
2886
|
+
if (importPath.startsWith(".")) {
|
|
2887
|
+
const dir = path8.dirname(filepath);
|
|
2888
|
+
const resolved = path8.normalize(path8.join(dir, importPath));
|
|
2889
|
+
references.push(resolved);
|
|
1715
2890
|
}
|
|
1716
|
-
projectMap.set(pkg.relativePath, {
|
|
1717
|
-
name: pkg.name,
|
|
1718
|
-
root: pkg.relativePath,
|
|
1719
|
-
type: pkg.type
|
|
1720
|
-
});
|
|
1721
2891
|
}
|
|
1722
|
-
|
|
1723
|
-
|
|
1724
|
-
|
|
1725
|
-
|
|
1726
|
-
|
|
1727
|
-
|
|
1728
|
-
}
|
|
1729
|
-
const deps = { ...rootPkg.dependencies, ...rootPkg.devDependencies };
|
|
1730
|
-
if (deps["next"] || deps["react"] || deps["vue"]) {
|
|
1731
|
-
rootType = "app";
|
|
1732
|
-
} else if (deps["express"] || deps["fastify"] || deps["koa"]) {
|
|
1733
|
-
rootType = "service";
|
|
2892
|
+
while ((match = requireRegex.exec(content)) !== null) {
|
|
2893
|
+
const importPath = match[1];
|
|
2894
|
+
if (importPath.startsWith(".")) {
|
|
2895
|
+
const dir = path8.dirname(filepath);
|
|
2896
|
+
const resolved = path8.normalize(path8.join(dir, importPath));
|
|
2897
|
+
references.push(resolved);
|
|
1734
2898
|
}
|
|
1735
|
-
} catch {}
|
|
1736
|
-
const projects = Array.from(projectMap.values()).sort((a, b) => a.root.length - b.root.length);
|
|
1737
|
-
return {
|
|
1738
|
-
projects,
|
|
1739
|
-
isMonorepo,
|
|
1740
|
-
rootType: isMonorepo ? undefined : rootType
|
|
1741
|
-
};
|
|
1742
|
-
} catch {
|
|
1743
|
-
return {
|
|
1744
|
-
projects: [],
|
|
1745
|
-
isMonorepo: false,
|
|
1746
|
-
rootType: "unknown"
|
|
1747
|
-
};
|
|
1748
|
-
}
|
|
1749
|
-
}
|
|
1750
|
-
function getProjectType(patternDir) {
|
|
1751
|
-
switch (patternDir) {
|
|
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";
|
|
1764
|
-
}
|
|
1765
|
-
}
|
|
1766
|
-
function findProjectForFile(filepath, structure) {
|
|
1767
|
-
const normalizedPath = filepath.replace(/\\/g, "/");
|
|
1768
|
-
const matches = [];
|
|
1769
|
-
for (const project of structure.projects) {
|
|
1770
|
-
if (normalizedPath === project.root || normalizedPath.startsWith(project.root + "/")) {
|
|
1771
|
-
matches.push(project);
|
|
1772
|
-
}
|
|
1773
|
-
}
|
|
1774
|
-
if (matches.length > 0) {
|
|
1775
|
-
return matches.reduce((best, current) => current.root.length > best.root.length ? current : best);
|
|
1776
|
-
}
|
|
1777
|
-
for (const { pattern, type } of PROJECT_PATTERNS) {
|
|
1778
|
-
const match = normalizedPath.match(pattern);
|
|
1779
|
-
if (match) {
|
|
1780
|
-
return {
|
|
1781
|
-
name: match[1],
|
|
1782
|
-
root: match[0],
|
|
1783
|
-
type
|
|
1784
|
-
};
|
|
1785
2899
|
}
|
|
2900
|
+
return references;
|
|
1786
2901
|
}
|
|
1787
|
-
return {
|
|
1788
|
-
name: "root",
|
|
1789
|
-
root: "",
|
|
1790
|
-
type: structure.rootType ?? "unknown"
|
|
1791
|
-
};
|
|
1792
2902
|
}
|
|
1793
|
-
var
|
|
1794
|
-
var
|
|
1795
|
-
|
|
1796
|
-
|
|
1797
|
-
|
|
1798
|
-
|
|
1799
|
-
|
|
1800
|
-
|
|
1801
|
-
".nuxt",
|
|
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
|
-
};
|
|
2903
|
+
var DEFAULT_MIN_SCORE2 = 0.15, DEFAULT_TOP_K2 = 10, SEMANTIC_WEIGHT = 0.7, BM25_WEIGHT = 0.3, TIER1_CANDIDATE_MULTIPLIER = 3;
|
|
2904
|
+
var init_typescript = __esm(() => {
|
|
2905
|
+
init_embeddings();
|
|
2906
|
+
init_config2();
|
|
2907
|
+
init_parseCode();
|
|
2908
|
+
init_storage();
|
|
2909
|
+
init_keywords();
|
|
2910
|
+
init_keywords();
|
|
1849
2911
|
});
|
|
1850
2912
|
|
|
1851
|
-
// src/
|
|
1852
|
-
|
|
1853
|
-
|
|
1854
|
-
|
|
1855
|
-
|
|
1856
|
-
|
|
1857
|
-
const ext = path7.extname(filename);
|
|
1858
|
-
const project = findProjectForFile(normalizedPath, structure);
|
|
1859
|
-
const language = EXTENSION_TO_LANGUAGE[ext] || "unknown";
|
|
1860
|
-
const layer = detectLayer(segments, filename);
|
|
1861
|
-
const domain = detectDomain(segments);
|
|
1862
|
-
const scope = detectScope(segments, project, layer);
|
|
1863
|
-
let framework;
|
|
1864
|
-
if (fileContent) {
|
|
1865
|
-
framework = detectFramework(fileContent);
|
|
1866
|
-
}
|
|
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
|
-
};
|
|
1878
|
-
}
|
|
1879
|
-
function detectLayer(segments, filename) {
|
|
1880
|
-
const filenameLower = filename.toLowerCase();
|
|
1881
|
-
for (const [layer, patterns] of Object.entries(LAYER_PATTERNS2)) {
|
|
1882
|
-
for (const pattern of patterns) {
|
|
1883
|
-
if (filenameLower.includes(pattern)) {
|
|
1884
|
-
return layer;
|
|
1885
|
-
}
|
|
1886
|
-
}
|
|
1887
|
-
}
|
|
1888
|
-
for (let i = segments.length - 2;i >= 0; i--) {
|
|
1889
|
-
const segment = segments[i].toLowerCase();
|
|
1890
|
-
for (const [layer, patterns] of Object.entries(LAYER_PATTERNS2)) {
|
|
1891
|
-
if (patterns.includes(segment)) {
|
|
1892
|
-
return layer;
|
|
1893
|
-
}
|
|
2913
|
+
// src/modules/registry.ts
|
|
2914
|
+
class ModuleRegistryImpl {
|
|
2915
|
+
modules = new Map;
|
|
2916
|
+
register(module) {
|
|
2917
|
+
if (this.modules.has(module.id)) {
|
|
2918
|
+
console.warn(`Module '${module.id}' is already registered, overwriting...`);
|
|
1894
2919
|
}
|
|
2920
|
+
this.modules.set(module.id, module);
|
|
1895
2921
|
}
|
|
1896
|
-
|
|
1897
|
-
|
|
1898
|
-
function detectDomain(segments) {
|
|
1899
|
-
const skipSegments = new Set([
|
|
1900
|
-
"src",
|
|
1901
|
-
"lib",
|
|
1902
|
-
"app",
|
|
1903
|
-
"apps",
|
|
1904
|
-
"packages",
|
|
1905
|
-
"services",
|
|
1906
|
-
"modules",
|
|
1907
|
-
"features",
|
|
1908
|
-
...Object.values(LAYER_PATTERNS2).flat()
|
|
1909
|
-
]);
|
|
1910
|
-
for (const segment of segments) {
|
|
1911
|
-
const segmentLower = segment.toLowerCase();
|
|
1912
|
-
if (skipSegments.has(segmentLower))
|
|
1913
|
-
continue;
|
|
1914
|
-
if (DOMAIN_PATTERNS.includes(segmentLower)) {
|
|
1915
|
-
return segmentLower;
|
|
1916
|
-
}
|
|
1917
|
-
for (const domain of DOMAIN_PATTERNS) {
|
|
1918
|
-
if (segmentLower.startsWith(domain) || segmentLower.endsWith(domain)) {
|
|
1919
|
-
return domain;
|
|
1920
|
-
}
|
|
1921
|
-
}
|
|
2922
|
+
get(id) {
|
|
2923
|
+
return this.modules.get(id);
|
|
1922
2924
|
}
|
|
1923
|
-
|
|
1924
|
-
|
|
1925
|
-
function detectScope(segments, project, layer) {
|
|
1926
|
-
const projectScope = detectScopeFromName(project.name);
|
|
1927
|
-
if (projectScope !== "unknown") {
|
|
1928
|
-
return projectScope;
|
|
2925
|
+
list() {
|
|
2926
|
+
return Array.from(this.modules.values());
|
|
1929
2927
|
}
|
|
1930
|
-
|
|
1931
|
-
|
|
1932
|
-
|
|
1933
|
-
case "repository":
|
|
1934
|
-
case "middleware":
|
|
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
|
-
}
|
|
2928
|
+
getEnabled(config) {
|
|
2929
|
+
const enabledIds = new Set(config.modules.filter((m) => m.enabled).map((m) => m.id));
|
|
2930
|
+
return this.list().filter((m) => enabledIds.has(m.id));
|
|
1944
2931
|
}
|
|
1945
|
-
|
|
1946
|
-
|
|
1947
|
-
|
|
1948
|
-
|
|
2932
|
+
}
|
|
2933
|
+
async function registerBuiltInModules() {
|
|
2934
|
+
const { CoreModule: CoreModule2 } = await Promise.resolve().then(() => (init_core(), exports_core));
|
|
2935
|
+
const { TypeScriptModule: TypeScriptModule2 } = await Promise.resolve().then(() => (init_typescript(), exports_typescript));
|
|
2936
|
+
registry.register(new CoreModule2);
|
|
2937
|
+
registry.register(new TypeScriptModule2);
|
|
2938
|
+
}
|
|
2939
|
+
var registry;
|
|
2940
|
+
var init_registry = __esm(() => {
|
|
2941
|
+
registry = new ModuleRegistryImpl;
|
|
2942
|
+
});
|
|
2943
|
+
|
|
2944
|
+
// src/infrastructure/introspection/projectDetector.ts
|
|
2945
|
+
import * as path9 from "path";
|
|
2946
|
+
import * as fs4 from "fs/promises";
|
|
2947
|
+
async function scanForPackageJsons(rootDir, currentDir = "", depth = 0) {
|
|
2948
|
+
if (depth > MAX_SCAN_DEPTH)
|
|
2949
|
+
return [];
|
|
2950
|
+
const results = [];
|
|
2951
|
+
const fullDir = currentDir ? path9.join(rootDir, currentDir) : rootDir;
|
|
2952
|
+
try {
|
|
2953
|
+
const entries = await fs4.readdir(fullDir, { withFileTypes: true });
|
|
2954
|
+
const hasPackageJson = entries.some((e) => e.isFile() && e.name === "package.json");
|
|
2955
|
+
if (hasPackageJson && currentDir) {
|
|
2956
|
+
const info = await parsePackageJson(rootDir, currentDir);
|
|
2957
|
+
if (info)
|
|
2958
|
+
results.push(info);
|
|
1949
2959
|
}
|
|
1950
|
-
|
|
1951
|
-
|
|
2960
|
+
for (const entry of entries) {
|
|
2961
|
+
if (!entry.isDirectory())
|
|
2962
|
+
continue;
|
|
2963
|
+
if (SKIP_DIRS.has(entry.name))
|
|
2964
|
+
continue;
|
|
2965
|
+
const subPath = currentDir ? `${currentDir}/${entry.name}` : entry.name;
|
|
2966
|
+
const subResults = await scanForPackageJsons(rootDir, subPath, depth + 1);
|
|
2967
|
+
results.push(...subResults);
|
|
1952
2968
|
}
|
|
1953
|
-
|
|
1954
|
-
|
|
2969
|
+
} catch {}
|
|
2970
|
+
return results;
|
|
2971
|
+
}
|
|
2972
|
+
async function parsePackageJson(rootDir, relativePath) {
|
|
2973
|
+
try {
|
|
2974
|
+
const packageJsonPath = path9.join(rootDir, relativePath, "package.json");
|
|
2975
|
+
const content = await fs4.readFile(packageJsonPath, "utf-8");
|
|
2976
|
+
const pkg = JSON.parse(content);
|
|
2977
|
+
const name = pkg.name || path9.basename(relativePath);
|
|
2978
|
+
const deps = { ...pkg.dependencies, ...pkg.devDependencies };
|
|
2979
|
+
let type = "unknown";
|
|
2980
|
+
if (deps["next"] || deps["react"] || deps["vue"] || deps["svelte"]) {
|
|
2981
|
+
type = "app";
|
|
2982
|
+
} else if (deps["express"] || deps["fastify"] || deps["koa"] || deps["hono"]) {
|
|
2983
|
+
type = "service";
|
|
2984
|
+
} else if (pkg.main || pkg.exports) {
|
|
2985
|
+
type = "library";
|
|
1955
2986
|
}
|
|
2987
|
+
const hasWorkspaces = Boolean(pkg.workspaces);
|
|
2988
|
+
return { name, relativePath, type, hasWorkspaces };
|
|
2989
|
+
} catch {
|
|
2990
|
+
return null;
|
|
1956
2991
|
}
|
|
1957
|
-
return "unknown";
|
|
1958
2992
|
}
|
|
1959
|
-
function
|
|
1960
|
-
|
|
1961
|
-
|
|
1962
|
-
|
|
1963
|
-
|
|
2993
|
+
function getProjectType(patternDir) {
|
|
2994
|
+
switch (patternDir) {
|
|
2995
|
+
case "apps":
|
|
2996
|
+
return "app";
|
|
2997
|
+
case "packages":
|
|
2998
|
+
case "libs":
|
|
2999
|
+
return "library";
|
|
3000
|
+
case "services":
|
|
3001
|
+
return "service";
|
|
3002
|
+
case "scripts":
|
|
3003
|
+
case "tools":
|
|
3004
|
+
return "script";
|
|
3005
|
+
default:
|
|
3006
|
+
return "unknown";
|
|
3007
|
+
}
|
|
3008
|
+
}
|
|
3009
|
+
async function detectProjectStructure(rootDir) {
|
|
3010
|
+
const projectMap = new Map;
|
|
3011
|
+
let isMonorepo = false;
|
|
3012
|
+
try {
|
|
3013
|
+
const entries = await fs4.readdir(rootDir, { withFileTypes: true });
|
|
3014
|
+
const dirNames = entries.filter((e) => e.isDirectory()).map((e) => e.name);
|
|
3015
|
+
const monorepoPatterns = ["apps", "packages", "libs", "services"];
|
|
3016
|
+
const hasMonorepoStructure = monorepoPatterns.some((p) => dirNames.includes(p));
|
|
3017
|
+
if (hasMonorepoStructure) {
|
|
3018
|
+
isMonorepo = true;
|
|
3019
|
+
for (const pattern of monorepoPatterns) {
|
|
3020
|
+
if (!dirNames.includes(pattern))
|
|
3021
|
+
continue;
|
|
3022
|
+
const patternDir = path9.join(rootDir, pattern);
|
|
3023
|
+
try {
|
|
3024
|
+
const subDirs = await fs4.readdir(patternDir, { withFileTypes: true });
|
|
3025
|
+
for (const subDir of subDirs) {
|
|
3026
|
+
if (!subDir.isDirectory())
|
|
3027
|
+
continue;
|
|
3028
|
+
const projectRoot = `${pattern}/${subDir.name}`;
|
|
3029
|
+
const type = getProjectType(pattern);
|
|
3030
|
+
projectMap.set(projectRoot, {
|
|
3031
|
+
name: subDir.name,
|
|
3032
|
+
root: projectRoot,
|
|
3033
|
+
type
|
|
3034
|
+
});
|
|
3035
|
+
}
|
|
3036
|
+
} catch {}
|
|
1964
3037
|
}
|
|
1965
3038
|
}
|
|
3039
|
+
const packageJsons = await scanForPackageJsons(rootDir);
|
|
3040
|
+
for (const pkg of packageJsons) {
|
|
3041
|
+
if (pkg.hasWorkspaces)
|
|
3042
|
+
isMonorepo = true;
|
|
3043
|
+
if (packageJsons.length > 1)
|
|
3044
|
+
isMonorepo = true;
|
|
3045
|
+
projectMap.set(pkg.relativePath, {
|
|
3046
|
+
name: pkg.name,
|
|
3047
|
+
root: pkg.relativePath,
|
|
3048
|
+
type: pkg.type
|
|
3049
|
+
});
|
|
3050
|
+
}
|
|
3051
|
+
let rootType = "unknown";
|
|
3052
|
+
try {
|
|
3053
|
+
const rootPkgPath = path9.join(rootDir, "package.json");
|
|
3054
|
+
const rootPkg = JSON.parse(await fs4.readFile(rootPkgPath, "utf-8"));
|
|
3055
|
+
if (rootPkg.workspaces)
|
|
3056
|
+
isMonorepo = true;
|
|
3057
|
+
const deps = { ...rootPkg.dependencies, ...rootPkg.devDependencies };
|
|
3058
|
+
if (deps["next"] || deps["react"] || deps["vue"]) {
|
|
3059
|
+
rootType = "app";
|
|
3060
|
+
} else if (deps["express"] || deps["fastify"] || deps["koa"]) {
|
|
3061
|
+
rootType = "service";
|
|
3062
|
+
}
|
|
3063
|
+
} catch {}
|
|
3064
|
+
const projects = Array.from(projectMap.values()).sort((a, b) => a.root.length - b.root.length);
|
|
3065
|
+
return {
|
|
3066
|
+
projects,
|
|
3067
|
+
isMonorepo,
|
|
3068
|
+
rootType: isMonorepo ? undefined : rootType
|
|
3069
|
+
};
|
|
3070
|
+
} catch {
|
|
3071
|
+
return {
|
|
3072
|
+
projects: [],
|
|
3073
|
+
isMonorepo: false,
|
|
3074
|
+
rootType: "unknown"
|
|
3075
|
+
};
|
|
1966
3076
|
}
|
|
1967
|
-
return;
|
|
1968
3077
|
}
|
|
1969
|
-
var
|
|
1970
|
-
var
|
|
1971
|
-
|
|
1972
|
-
|
|
1973
|
-
|
|
1974
|
-
|
|
1975
|
-
|
|
1976
|
-
|
|
1977
|
-
|
|
1978
|
-
|
|
1979
|
-
|
|
1980
|
-
|
|
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
|
-
};
|
|
3078
|
+
var MAX_SCAN_DEPTH = 4, SKIP_DIRS;
|
|
3079
|
+
var init_projectDetector = __esm(() => {
|
|
3080
|
+
SKIP_DIRS = new Set([
|
|
3081
|
+
"node_modules",
|
|
3082
|
+
".git",
|
|
3083
|
+
"dist",
|
|
3084
|
+
"build",
|
|
3085
|
+
".next",
|
|
3086
|
+
".nuxt",
|
|
3087
|
+
"coverage",
|
|
3088
|
+
".raggrep"
|
|
3089
|
+
]);
|
|
2075
3090
|
});
|
|
2076
3091
|
|
|
2077
|
-
// src/introspection/
|
|
2078
|
-
import * as
|
|
3092
|
+
// src/infrastructure/introspection/IntrospectionIndex.ts
|
|
3093
|
+
import * as path10 from "path";
|
|
2079
3094
|
import * as fs5 from "fs/promises";
|
|
2080
3095
|
|
|
2081
3096
|
class IntrospectionIndex {
|
|
@@ -2089,7 +3104,7 @@ class IntrospectionIndex {
|
|
|
2089
3104
|
async initialize() {
|
|
2090
3105
|
this.structure = await detectProjectStructure(this.rootDir);
|
|
2091
3106
|
try {
|
|
2092
|
-
const configPath =
|
|
3107
|
+
const configPath = path10.join(this.rootDir, ".raggrep", "config.json");
|
|
2093
3108
|
const configContent = await fs5.readFile(configPath, "utf-8");
|
|
2094
3109
|
const config = JSON.parse(configContent);
|
|
2095
3110
|
this.config = config.introspection || {};
|
|
@@ -2129,29 +3144,29 @@ class IntrospectionIndex {
|
|
|
2129
3144
|
}
|
|
2130
3145
|
}
|
|
2131
3146
|
async save(config) {
|
|
2132
|
-
const introDir =
|
|
3147
|
+
const introDir = path10.join(getRaggrepDir(this.rootDir, config), "introspection");
|
|
2133
3148
|
await fs5.mkdir(introDir, { recursive: true });
|
|
2134
|
-
const projectPath =
|
|
3149
|
+
const projectPath = path10.join(introDir, "_project.json");
|
|
2135
3150
|
await fs5.writeFile(projectPath, JSON.stringify({
|
|
2136
3151
|
version: "1.0.0",
|
|
2137
3152
|
lastUpdated: new Date().toISOString(),
|
|
2138
3153
|
structure: this.structure
|
|
2139
3154
|
}, null, 2));
|
|
2140
3155
|
for (const [filepath, intro] of this.files) {
|
|
2141
|
-
const introFilePath =
|
|
2142
|
-
await fs5.mkdir(
|
|
3156
|
+
const introFilePath = path10.join(introDir, "files", filepath.replace(/\.[^.]+$/, ".json"));
|
|
3157
|
+
await fs5.mkdir(path10.dirname(introFilePath), { recursive: true });
|
|
2143
3158
|
await fs5.writeFile(introFilePath, JSON.stringify(intro, null, 2));
|
|
2144
3159
|
}
|
|
2145
3160
|
console.log(` [Introspection] Saved metadata for ${this.files.size} files`);
|
|
2146
3161
|
}
|
|
2147
3162
|
async load(config) {
|
|
2148
|
-
const introDir =
|
|
3163
|
+
const introDir = path10.join(getRaggrepDir(this.rootDir, config), "introspection");
|
|
2149
3164
|
try {
|
|
2150
|
-
const projectPath =
|
|
3165
|
+
const projectPath = path10.join(introDir, "_project.json");
|
|
2151
3166
|
const projectContent = await fs5.readFile(projectPath, "utf-8");
|
|
2152
3167
|
const projectData = JSON.parse(projectContent);
|
|
2153
3168
|
this.structure = projectData.structure;
|
|
2154
|
-
await this.loadFilesRecursive(
|
|
3169
|
+
await this.loadFilesRecursive(path10.join(introDir, "files"), "");
|
|
2155
3170
|
} catch {
|
|
2156
3171
|
this.structure = null;
|
|
2157
3172
|
this.files.clear();
|
|
@@ -2161,7 +3176,7 @@ class IntrospectionIndex {
|
|
|
2161
3176
|
try {
|
|
2162
3177
|
const entries = await fs5.readdir(basePath, { withFileTypes: true });
|
|
2163
3178
|
for (const entry of entries) {
|
|
2164
|
-
const entryPath =
|
|
3179
|
+
const entryPath = path10.join(basePath, entry.name);
|
|
2165
3180
|
const relativePath = prefix ? `${prefix}/${entry.name}` : entry.name;
|
|
2166
3181
|
if (entry.isDirectory()) {
|
|
2167
3182
|
await this.loadFilesRecursive(entryPath, relativePath);
|
|
@@ -2178,17 +3193,21 @@ class IntrospectionIndex {
|
|
|
2178
3193
|
this.structure = null;
|
|
2179
3194
|
}
|
|
2180
3195
|
}
|
|
2181
|
-
var
|
|
3196
|
+
var init_IntrospectionIndex = __esm(() => {
|
|
2182
3197
|
init_projectDetector();
|
|
2183
|
-
|
|
3198
|
+
init_introspection();
|
|
2184
3199
|
init_config2();
|
|
2185
|
-
|
|
3200
|
+
});
|
|
3201
|
+
|
|
3202
|
+
// src/infrastructure/introspection/index.ts
|
|
3203
|
+
var init_introspection2 = __esm(() => {
|
|
3204
|
+
init_IntrospectionIndex();
|
|
2186
3205
|
init_projectDetector();
|
|
2187
3206
|
});
|
|
2188
3207
|
|
|
2189
3208
|
// src/app/indexer/watcher.ts
|
|
2190
3209
|
import { watch } from "chokidar";
|
|
2191
|
-
import * as
|
|
3210
|
+
import * as path11 from "path";
|
|
2192
3211
|
async function watchDirectory(rootDir, options = {}) {
|
|
2193
3212
|
const {
|
|
2194
3213
|
debounceMs = DEFAULT_DEBOUNCE_MS,
|
|
@@ -2199,13 +3218,19 @@ async function watchDirectory(rootDir, options = {}) {
|
|
|
2199
3218
|
onFileChange,
|
|
2200
3219
|
onError
|
|
2201
3220
|
} = options;
|
|
2202
|
-
rootDir =
|
|
3221
|
+
rootDir = path11.resolve(rootDir);
|
|
2203
3222
|
const config = await loadConfig(rootDir);
|
|
2204
|
-
const
|
|
3223
|
+
const indexLocation = getIndexLocation(rootDir);
|
|
3224
|
+
const validExtensions = new Set(config.extensions);
|
|
2205
3225
|
const ignorePatterns = [
|
|
2206
3226
|
...config.ignorePaths.map((p) => `**/${p}/**`),
|
|
2207
|
-
|
|
3227
|
+
"**/node_modules/**",
|
|
3228
|
+
"**/.git/**"
|
|
2208
3229
|
];
|
|
3230
|
+
function shouldWatchFile(filepath) {
|
|
3231
|
+
const ext = path11.extname(filepath);
|
|
3232
|
+
return validExtensions.has(ext);
|
|
3233
|
+
}
|
|
2209
3234
|
let isRunning = true;
|
|
2210
3235
|
let isIndexing = false;
|
|
2211
3236
|
let pendingChanges = new Map;
|
|
@@ -2285,7 +3310,10 @@ async function watchDirectory(rootDir, options = {}) {
|
|
|
2285
3310
|
function handleFileEvent(event, filepath) {
|
|
2286
3311
|
if (!isRunning)
|
|
2287
3312
|
return;
|
|
2288
|
-
const relativePath =
|
|
3313
|
+
const relativePath = path11.relative(rootDir, filepath);
|
|
3314
|
+
if (!shouldWatchFile(filepath)) {
|
|
3315
|
+
return;
|
|
3316
|
+
}
|
|
2289
3317
|
for (const ignorePath of config.ignorePaths) {
|
|
2290
3318
|
if (relativePath.startsWith(ignorePath) || relativePath.includes(`/${ignorePath}/`)) {
|
|
2291
3319
|
return;
|
|
@@ -2301,8 +3329,7 @@ async function watchDirectory(rootDir, options = {}) {
|
|
|
2301
3329
|
pendingChanges.set(relativePath, event);
|
|
2302
3330
|
scheduleProcessing();
|
|
2303
3331
|
}
|
|
2304
|
-
watcher = watch(
|
|
2305
|
-
cwd: rootDir,
|
|
3332
|
+
watcher = watch(rootDir, {
|
|
2306
3333
|
ignored: ignorePatterns,
|
|
2307
3334
|
persistent: true,
|
|
2308
3335
|
ignoreInitial: true,
|
|
@@ -2311,11 +3338,12 @@ async function watchDirectory(rootDir, options = {}) {
|
|
|
2311
3338
|
pollInterval: 50
|
|
2312
3339
|
},
|
|
2313
3340
|
usePolling: false,
|
|
2314
|
-
atomic: true
|
|
3341
|
+
atomic: true,
|
|
3342
|
+
depth: 99
|
|
2315
3343
|
});
|
|
2316
|
-
watcher.on("add", (filepath) => handleFileEvent("add",
|
|
2317
|
-
watcher.on("change", (filepath) => handleFileEvent("change",
|
|
2318
|
-
watcher.on("unlink", (filepath) => handleFileEvent("unlink",
|
|
3344
|
+
watcher.on("add", (filepath) => handleFileEvent("add", filepath));
|
|
3345
|
+
watcher.on("change", (filepath) => handleFileEvent("change", filepath));
|
|
3346
|
+
watcher.on("unlink", (filepath) => handleFileEvent("unlink", filepath));
|
|
2319
3347
|
watcher.on("error", (error) => {
|
|
2320
3348
|
const err = error instanceof Error ? error : new Error(String(error));
|
|
2321
3349
|
console.error("[Watch] Watcher error:", err);
|
|
@@ -2323,9 +3351,9 @@ async function watchDirectory(rootDir, options = {}) {
|
|
|
2323
3351
|
onError(err);
|
|
2324
3352
|
}
|
|
2325
3353
|
});
|
|
2326
|
-
await new Promise((
|
|
3354
|
+
await new Promise((resolve3) => {
|
|
2327
3355
|
watcher.on("ready", () => {
|
|
2328
|
-
|
|
3356
|
+
resolve3();
|
|
2329
3357
|
});
|
|
2330
3358
|
});
|
|
2331
3359
|
return {
|
|
@@ -2359,11 +3387,13 @@ __export(exports_indexer, {
|
|
|
2359
3387
|
});
|
|
2360
3388
|
import { glob } from "glob";
|
|
2361
3389
|
import * as fs6 from "fs/promises";
|
|
2362
|
-
import * as
|
|
3390
|
+
import * as path12 from "path";
|
|
2363
3391
|
async function indexDirectory(rootDir, options = {}) {
|
|
2364
3392
|
const verbose = options.verbose ?? false;
|
|
2365
|
-
rootDir =
|
|
3393
|
+
rootDir = path12.resolve(rootDir);
|
|
3394
|
+
const location = getIndexLocation(rootDir);
|
|
2366
3395
|
console.log(`Indexing directory: ${rootDir}`);
|
|
3396
|
+
console.log(`Index location: ${location.indexDir}`);
|
|
2367
3397
|
const config = await loadConfig(rootDir);
|
|
2368
3398
|
const introspection = new IntrospectionIndex(rootDir);
|
|
2369
3399
|
await introspection.initialize();
|
|
@@ -2405,11 +3435,11 @@ async function indexDirectory(rootDir, options = {}) {
|
|
|
2405
3435
|
rootDir,
|
|
2406
3436
|
config,
|
|
2407
3437
|
readFile: async (filepath) => {
|
|
2408
|
-
const fullPath =
|
|
3438
|
+
const fullPath = path12.isAbsolute(filepath) ? filepath : path12.join(rootDir, filepath);
|
|
2409
3439
|
return fs6.readFile(fullPath, "utf-8");
|
|
2410
3440
|
},
|
|
2411
3441
|
getFileStats: async (filepath) => {
|
|
2412
|
-
const fullPath =
|
|
3442
|
+
const fullPath = path12.isAbsolute(filepath) ? filepath : path12.join(rootDir, filepath);
|
|
2413
3443
|
const stats = await fs6.stat(fullPath);
|
|
2414
3444
|
return { lastModified: stats.mtime.toISOString() };
|
|
2415
3445
|
}
|
|
@@ -2434,18 +3464,18 @@ async function indexWithModule(rootDir, files, module, config, verbose, introspe
|
|
|
2434
3464
|
rootDir,
|
|
2435
3465
|
config,
|
|
2436
3466
|
readFile: async (filepath) => {
|
|
2437
|
-
const fullPath =
|
|
3467
|
+
const fullPath = path12.isAbsolute(filepath) ? filepath : path12.join(rootDir, filepath);
|
|
2438
3468
|
return fs6.readFile(fullPath, "utf-8");
|
|
2439
3469
|
},
|
|
2440
3470
|
getFileStats: async (filepath) => {
|
|
2441
|
-
const fullPath =
|
|
3471
|
+
const fullPath = path12.isAbsolute(filepath) ? filepath : path12.join(rootDir, filepath);
|
|
2442
3472
|
const stats = await fs6.stat(fullPath);
|
|
2443
3473
|
return { lastModified: stats.mtime.toISOString() };
|
|
2444
3474
|
},
|
|
2445
3475
|
getIntrospection: (filepath) => introspection.getFile(filepath)
|
|
2446
3476
|
};
|
|
2447
3477
|
for (const filepath of files) {
|
|
2448
|
-
const relativePath =
|
|
3478
|
+
const relativePath = path12.relative(rootDir, filepath);
|
|
2449
3479
|
try {
|
|
2450
3480
|
const stats = await fs6.stat(filepath);
|
|
2451
3481
|
const lastModified = stats.mtime.toISOString();
|
|
@@ -2515,13 +3545,13 @@ async function loadModuleManifest(rootDir, moduleId, config) {
|
|
|
2515
3545
|
}
|
|
2516
3546
|
async function writeModuleManifest(rootDir, moduleId, manifest, config) {
|
|
2517
3547
|
const manifestPath = getModuleManifestPath(rootDir, moduleId, config);
|
|
2518
|
-
await fs6.mkdir(
|
|
3548
|
+
await fs6.mkdir(path12.dirname(manifestPath), { recursive: true });
|
|
2519
3549
|
await fs6.writeFile(manifestPath, JSON.stringify(manifest, null, 2));
|
|
2520
3550
|
}
|
|
2521
3551
|
async function writeFileIndex(rootDir, moduleId, filepath, fileIndex, config) {
|
|
2522
3552
|
const indexPath = getModuleIndexPath(rootDir, moduleId, config);
|
|
2523
|
-
const indexFilePath =
|
|
2524
|
-
await fs6.mkdir(
|
|
3553
|
+
const indexFilePath = path12.join(indexPath, filepath.replace(/\.[^.]+$/, ".json"));
|
|
3554
|
+
await fs6.mkdir(path12.dirname(indexFilePath), { recursive: true });
|
|
2525
3555
|
await fs6.writeFile(indexFilePath, JSON.stringify(fileIndex, null, 2));
|
|
2526
3556
|
}
|
|
2527
3557
|
async function updateGlobalManifest(rootDir, modules, config) {
|
|
@@ -2531,12 +3561,12 @@ async function updateGlobalManifest(rootDir, modules, config) {
|
|
|
2531
3561
|
lastUpdated: new Date().toISOString(),
|
|
2532
3562
|
modules: modules.map((m) => m.id)
|
|
2533
3563
|
};
|
|
2534
|
-
await fs6.mkdir(
|
|
3564
|
+
await fs6.mkdir(path12.dirname(manifestPath), { recursive: true });
|
|
2535
3565
|
await fs6.writeFile(manifestPath, JSON.stringify(manifest, null, 2));
|
|
2536
3566
|
}
|
|
2537
3567
|
async function cleanupIndex(rootDir, options = {}) {
|
|
2538
3568
|
const verbose = options.verbose ?? false;
|
|
2539
|
-
rootDir =
|
|
3569
|
+
rootDir = path12.resolve(rootDir);
|
|
2540
3570
|
console.log(`Cleaning up index in: ${rootDir}`);
|
|
2541
3571
|
const config = await loadConfig(rootDir);
|
|
2542
3572
|
await registerBuiltInModules();
|
|
@@ -2566,7 +3596,7 @@ async function cleanupModuleIndex(rootDir, moduleId, config, verbose) {
|
|
|
2566
3596
|
const filesToRemove = [];
|
|
2567
3597
|
const updatedFiles = {};
|
|
2568
3598
|
for (const [filepath, entry] of Object.entries(manifest.files)) {
|
|
2569
|
-
const fullPath =
|
|
3599
|
+
const fullPath = path12.join(rootDir, filepath);
|
|
2570
3600
|
try {
|
|
2571
3601
|
await fs6.access(fullPath);
|
|
2572
3602
|
updatedFiles[filepath] = entry;
|
|
@@ -2580,7 +3610,7 @@ async function cleanupModuleIndex(rootDir, moduleId, config, verbose) {
|
|
|
2580
3610
|
}
|
|
2581
3611
|
}
|
|
2582
3612
|
for (const filepath of filesToRemove) {
|
|
2583
|
-
const indexFilePath =
|
|
3613
|
+
const indexFilePath = path12.join(indexPath, filepath.replace(/\.[^.]+$/, ".json"));
|
|
2584
3614
|
try {
|
|
2585
3615
|
await fs6.unlink(indexFilePath);
|
|
2586
3616
|
} catch {}
|
|
@@ -2596,7 +3626,7 @@ async function cleanupEmptyDirectories(dir) {
|
|
|
2596
3626
|
const entries = await fs6.readdir(dir, { withFileTypes: true });
|
|
2597
3627
|
for (const entry of entries) {
|
|
2598
3628
|
if (entry.isDirectory()) {
|
|
2599
|
-
const subDir =
|
|
3629
|
+
const subDir = path12.join(dir, entry.name);
|
|
2600
3630
|
await cleanupEmptyDirectories(subDir);
|
|
2601
3631
|
}
|
|
2602
3632
|
}
|
|
@@ -2611,9 +3641,10 @@ async function cleanupEmptyDirectories(dir) {
|
|
|
2611
3641
|
}
|
|
2612
3642
|
}
|
|
2613
3643
|
async function getIndexStatus(rootDir) {
|
|
2614
|
-
rootDir =
|
|
3644
|
+
rootDir = path12.resolve(rootDir);
|
|
2615
3645
|
const config = await loadConfig(rootDir);
|
|
2616
|
-
const
|
|
3646
|
+
const location = getIndexLocation(rootDir);
|
|
3647
|
+
const indexDir = location.indexDir;
|
|
2617
3648
|
const status = {
|
|
2618
3649
|
exists: false,
|
|
2619
3650
|
rootDir,
|
|
@@ -2646,7 +3677,7 @@ async function getIndexStatus(rootDir) {
|
|
|
2646
3677
|
}
|
|
2647
3678
|
} catch {
|
|
2648
3679
|
try {
|
|
2649
|
-
const entries = await fs6.readdir(
|
|
3680
|
+
const entries = await fs6.readdir(path12.join(indexDir, "index"));
|
|
2650
3681
|
if (entries.length > 0) {
|
|
2651
3682
|
status.exists = true;
|
|
2652
3683
|
for (const entry of entries) {
|
|
@@ -2669,7 +3700,7 @@ async function getIndexStatus(rootDir) {
|
|
|
2669
3700
|
var init_indexer = __esm(() => {
|
|
2670
3701
|
init_config2();
|
|
2671
3702
|
init_registry();
|
|
2672
|
-
|
|
3703
|
+
init_introspection2();
|
|
2673
3704
|
init_watcher();
|
|
2674
3705
|
});
|
|
2675
3706
|
|
|
@@ -2680,9 +3711,9 @@ __export(exports_search, {
|
|
|
2680
3711
|
formatSearchResults: () => formatSearchResults
|
|
2681
3712
|
});
|
|
2682
3713
|
import * as fs7 from "fs/promises";
|
|
2683
|
-
import * as
|
|
3714
|
+
import * as path13 from "path";
|
|
2684
3715
|
async function search(rootDir, query, options = {}) {
|
|
2685
|
-
rootDir =
|
|
3716
|
+
rootDir = path13.resolve(rootDir);
|
|
2686
3717
|
console.log(`Searching for: "${query}"`);
|
|
2687
3718
|
const config = await loadConfig(rootDir);
|
|
2688
3719
|
await registerBuiltInModules();
|
|
@@ -2723,7 +3754,7 @@ function createSearchContext(rootDir, moduleId, config) {
|
|
|
2723
3754
|
config,
|
|
2724
3755
|
loadFileIndex: async (filepath) => {
|
|
2725
3756
|
const hasExtension = /\.[^./]+$/.test(filepath);
|
|
2726
|
-
const indexFilePath = hasExtension ?
|
|
3757
|
+
const indexFilePath = hasExtension ? path13.join(indexPath, filepath.replace(/\.[^.]+$/, ".json")) : path13.join(indexPath, filepath + ".json");
|
|
2727
3758
|
try {
|
|
2728
3759
|
const content = await fs7.readFile(indexFilePath, "utf-8");
|
|
2729
3760
|
return JSON.parse(content);
|
|
@@ -2735,7 +3766,7 @@ function createSearchContext(rootDir, moduleId, config) {
|
|
|
2735
3766
|
const files = [];
|
|
2736
3767
|
await traverseDirectory(indexPath, files, indexPath);
|
|
2737
3768
|
return files.filter((f) => f.endsWith(".json") && !f.endsWith("manifest.json")).map((f) => {
|
|
2738
|
-
const relative4 =
|
|
3769
|
+
const relative4 = path13.relative(indexPath, f);
|
|
2739
3770
|
return relative4.replace(/\.json$/, "");
|
|
2740
3771
|
});
|
|
2741
3772
|
}
|
|
@@ -2745,7 +3776,7 @@ async function traverseDirectory(dir, files, basePath) {
|
|
|
2745
3776
|
try {
|
|
2746
3777
|
const entries = await fs7.readdir(dir, { withFileTypes: true });
|
|
2747
3778
|
for (const entry of entries) {
|
|
2748
|
-
const fullPath =
|
|
3779
|
+
const fullPath = path13.join(dir, entry.name);
|
|
2749
3780
|
if (entry.isDirectory()) {
|
|
2750
3781
|
await traverseDirectory(fullPath, files, basePath);
|
|
2751
3782
|
} else if (entry.isFile()) {
|
|
@@ -2763,6 +3794,20 @@ async function loadGlobalManifest(rootDir, config) {
|
|
|
2763
3794
|
return null;
|
|
2764
3795
|
}
|
|
2765
3796
|
}
|
|
3797
|
+
function formatModuleName(moduleId) {
|
|
3798
|
+
switch (moduleId) {
|
|
3799
|
+
case "core":
|
|
3800
|
+
return "Core";
|
|
3801
|
+
case "language/typescript":
|
|
3802
|
+
return "TypeScript";
|
|
3803
|
+
default:
|
|
3804
|
+
if (moduleId.startsWith("language/")) {
|
|
3805
|
+
const lang = moduleId.replace("language/", "");
|
|
3806
|
+
return lang.charAt(0).toUpperCase() + lang.slice(1);
|
|
3807
|
+
}
|
|
3808
|
+
return moduleId;
|
|
3809
|
+
}
|
|
3810
|
+
}
|
|
2766
3811
|
function formatSearchResults(results) {
|
|
2767
3812
|
if (results.length === 0) {
|
|
2768
3813
|
return "No results found.";
|
|
@@ -2778,6 +3823,7 @@ function formatSearchResults(results) {
|
|
|
2778
3823
|
output += `${i + 1}. ${location}${nameInfo}
|
|
2779
3824
|
`;
|
|
2780
3825
|
output += ` Score: ${(result.score * 100).toFixed(1)}% | Type: ${chunk.type}`;
|
|
3826
|
+
output += ` | via ${formatModuleName(result.moduleId)}`;
|
|
2781
3827
|
if (chunk.isExported) {
|
|
2782
3828
|
output += " | exported";
|
|
2783
3829
|
}
|
|
@@ -2805,7 +3851,7 @@ init_embeddings();
|
|
|
2805
3851
|
// package.json
|
|
2806
3852
|
var package_default = {
|
|
2807
3853
|
name: "raggrep",
|
|
2808
|
-
version: "0.1.
|
|
3854
|
+
version: "0.1.7",
|
|
2809
3855
|
description: "Local filesystem-based RAG system for codebases - semantic search using local embeddings",
|
|
2810
3856
|
type: "module",
|
|
2811
3857
|
main: "./dist/index.js",
|
|
@@ -3240,4 +4286,4 @@ Run 'raggrep <command> --help' for more information.
|
|
|
3240
4286
|
}
|
|
3241
4287
|
main();
|
|
3242
4288
|
|
|
3243
|
-
//# debugId=
|
|
4289
|
+
//# debugId=C248CB1C621D0FC764756E2164756E21
|