raggrep 0.1.6 → 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.
Files changed (23) hide show
  1. package/dist/app/indexer/index.d.ts +2 -2
  2. package/dist/cli/main.js +683 -489
  3. package/dist/cli/main.js.map +17 -16
  4. package/dist/{introspection/conventions/types.d.ts → domain/entities/conventions.d.ts} +6 -5
  5. package/dist/domain/entities/index.d.ts +2 -0
  6. package/dist/{introspection → domain/services}/conventions/configFiles.d.ts +1 -1
  7. package/dist/{introspection → domain/services}/conventions/entryPoints.d.ts +1 -1
  8. package/dist/{introspection → domain/services}/conventions/frameworks/convex.d.ts +1 -1
  9. package/dist/{introspection → domain/services}/conventions/frameworks/index.d.ts +1 -1
  10. package/dist/{introspection → domain/services}/conventions/frameworks/nextjs.d.ts +1 -1
  11. package/dist/{introspection → domain/services}/conventions/index.d.ts +5 -5
  12. package/dist/domain/services/introspection.d.ts +31 -0
  13. package/dist/index.js +646 -465
  14. package/dist/index.js.map +16 -16
  15. package/dist/{introspection/index.d.ts → infrastructure/introspection/IntrospectionIndex.d.ts} +3 -14
  16. package/dist/infrastructure/introspection/index.d.ts +9 -0
  17. package/dist/{introspection → infrastructure/introspection}/projectDetector.d.ts +3 -12
  18. package/dist/types.d.ts +4 -4
  19. package/package.json +1 -1
  20. package/dist/introspection/fileIntrospector.d.ts +0 -14
  21. /package/dist/{introspection/types.d.ts → domain/entities/introspection.d.ts} +0 -0
  22. /package/dist/{introspection → domain/services}/conventions/conventions.test.d.ts +0 -0
  23. /package/dist/{introspection → domain/services}/introspection.test.d.ts +0 -0
package/dist/cli/main.js CHANGED
@@ -429,247 +429,11 @@ function normalizeScore(score, midpoint = 5) {
429
429
  }
430
430
  var BM25_K1 = 1.5, BM25_B = 0.75;
431
431
 
432
- // src/introspection/projectDetector.ts
432
+ // src/domain/services/conventions/entryPoints.ts
433
433
  import * as path3 from "path";
434
- import * as fs2 from "fs/promises";
435
- function detectScopeFromName(name) {
436
- const nameLower = name.toLowerCase();
437
- for (const [scope, keywords] of Object.entries(SCOPE_KEYWORDS)) {
438
- if (scope === "unknown")
439
- continue;
440
- for (const keyword of keywords) {
441
- if (nameLower.includes(keyword)) {
442
- return scope;
443
- }
444
- }
445
- }
446
- return "unknown";
447
- }
448
- async function scanForPackageJsons(rootDir, currentDir = "", depth = 0) {
449
- if (depth > MAX_SCAN_DEPTH)
450
- return [];
451
- const results = [];
452
- const fullDir = currentDir ? path3.join(rootDir, currentDir) : rootDir;
453
- try {
454
- const entries = await fs2.readdir(fullDir, { withFileTypes: true });
455
- const hasPackageJson = entries.some((e) => e.isFile() && e.name === "package.json");
456
- if (hasPackageJson && currentDir) {
457
- const info = await parsePackageJson(rootDir, currentDir);
458
- if (info) {
459
- results.push(info);
460
- }
461
- }
462
- for (const entry of entries) {
463
- if (!entry.isDirectory())
464
- continue;
465
- if (SKIP_DIRS.has(entry.name))
466
- continue;
467
- const subPath = currentDir ? `${currentDir}/${entry.name}` : entry.name;
468
- const subResults = await scanForPackageJsons(rootDir, subPath, depth + 1);
469
- results.push(...subResults);
470
- }
471
- } catch {}
472
- return results;
473
- }
474
- async function parsePackageJson(rootDir, relativePath) {
475
- try {
476
- const packageJsonPath = path3.join(rootDir, relativePath, "package.json");
477
- const content = await fs2.readFile(packageJsonPath, "utf-8");
478
- const pkg = JSON.parse(content);
479
- const name = pkg.name || path3.basename(relativePath);
480
- const deps = { ...pkg.dependencies, ...pkg.devDependencies };
481
- let type = "unknown";
482
- if (deps["next"] || deps["react"] || deps["vue"] || deps["svelte"]) {
483
- type = "app";
484
- } else if (deps["express"] || deps["fastify"] || deps["koa"] || deps["hono"]) {
485
- type = "service";
486
- } else if (pkg.main || pkg.exports) {
487
- type = "library";
488
- }
489
- const hasWorkspaces = Boolean(pkg.workspaces);
490
- return { name, relativePath, type, hasWorkspaces };
491
- } catch {
492
- return null;
493
- }
494
- }
495
- async function detectProjectStructure(rootDir) {
496
- const projectMap = new Map;
497
- let isMonorepo = false;
498
- try {
499
- const entries = await fs2.readdir(rootDir, { withFileTypes: true });
500
- const dirNames = entries.filter((e) => e.isDirectory()).map((e) => e.name);
501
- const monorepoPatterns = ["apps", "packages", "libs", "services"];
502
- const hasMonorepoStructure = monorepoPatterns.some((p) => dirNames.includes(p));
503
- if (hasMonorepoStructure) {
504
- isMonorepo = true;
505
- for (const pattern of monorepoPatterns) {
506
- if (!dirNames.includes(pattern))
507
- continue;
508
- const patternDir = path3.join(rootDir, pattern);
509
- try {
510
- const subDirs = await fs2.readdir(patternDir, { withFileTypes: true });
511
- for (const subDir of subDirs) {
512
- if (!subDir.isDirectory())
513
- continue;
514
- const projectRoot = `${pattern}/${subDir.name}`;
515
- const type = getProjectType(pattern);
516
- projectMap.set(projectRoot, {
517
- name: subDir.name,
518
- root: projectRoot,
519
- type
520
- });
521
- }
522
- } catch {}
523
- }
524
- }
525
- const packageJsons = await scanForPackageJsons(rootDir);
526
- for (const pkg of packageJsons) {
527
- if (pkg.hasWorkspaces) {
528
- isMonorepo = true;
529
- }
530
- if (packageJsons.length > 1) {
531
- isMonorepo = true;
532
- }
533
- projectMap.set(pkg.relativePath, {
534
- name: pkg.name,
535
- root: pkg.relativePath,
536
- type: pkg.type
537
- });
538
- }
539
- let rootType = "unknown";
540
- try {
541
- const rootPkgPath = path3.join(rootDir, "package.json");
542
- const rootPkg = JSON.parse(await fs2.readFile(rootPkgPath, "utf-8"));
543
- if (rootPkg.workspaces) {
544
- isMonorepo = true;
545
- }
546
- const deps = { ...rootPkg.dependencies, ...rootPkg.devDependencies };
547
- if (deps["next"] || deps["react"] || deps["vue"]) {
548
- rootType = "app";
549
- } else if (deps["express"] || deps["fastify"] || deps["koa"]) {
550
- rootType = "service";
551
- }
552
- } catch {}
553
- const projects = Array.from(projectMap.values()).sort((a, b) => a.root.length - b.root.length);
554
- return {
555
- projects,
556
- isMonorepo,
557
- rootType: isMonorepo ? undefined : rootType
558
- };
559
- } catch {
560
- return {
561
- projects: [],
562
- isMonorepo: false,
563
- rootType: "unknown"
564
- };
565
- }
566
- }
567
- function getProjectType(patternDir) {
568
- switch (patternDir) {
569
- case "apps":
570
- return "app";
571
- case "packages":
572
- case "libs":
573
- return "library";
574
- case "services":
575
- return "service";
576
- case "scripts":
577
- case "tools":
578
- return "script";
579
- default:
580
- return "unknown";
581
- }
582
- }
583
- function findProjectForFile(filepath, structure) {
584
- const normalizedPath = filepath.replace(/\\/g, "/");
585
- const matches = [];
586
- for (const project of structure.projects) {
587
- if (normalizedPath === project.root || normalizedPath.startsWith(project.root + "/")) {
588
- matches.push(project);
589
- }
590
- }
591
- if (matches.length > 0) {
592
- return matches.reduce((best, current) => current.root.length > best.root.length ? current : best);
593
- }
594
- for (const { pattern, type } of PROJECT_PATTERNS) {
595
- const match = normalizedPath.match(pattern);
596
- if (match) {
597
- return {
598
- name: match[1],
599
- root: match[0],
600
- type
601
- };
602
- }
603
- }
604
- return {
605
- name: "root",
606
- root: "",
607
- type: structure.rootType ?? "unknown"
608
- };
609
- }
610
- var MAX_SCAN_DEPTH = 4, SKIP_DIRS, PROJECT_PATTERNS, SCOPE_KEYWORDS;
611
- var init_projectDetector = __esm(() => {
612
- SKIP_DIRS = new Set([
613
- "node_modules",
614
- ".git",
615
- "dist",
616
- "build",
617
- ".next",
618
- ".nuxt",
619
- "coverage",
620
- ".raggrep"
621
- ]);
622
- PROJECT_PATTERNS = [
623
- { pattern: /^apps\/([^/]+)/, type: "app", defaultScope: "unknown" },
624
- { pattern: /^packages\/([^/]+)/, type: "library", defaultScope: "shared" },
625
- { pattern: /^libs\/([^/]+)/, type: "library", defaultScope: "shared" },
626
- { pattern: /^services\/([^/]+)/, type: "service", defaultScope: "backend" },
627
- { pattern: /^scripts\/([^/]+)/, type: "script", defaultScope: "tooling" },
628
- { pattern: /^tools\/([^/]+)/, type: "script", defaultScope: "tooling" }
629
- ];
630
- SCOPE_KEYWORDS = {
631
- frontend: [
632
- "web",
633
- "webapp",
634
- "frontend",
635
- "client",
636
- "ui",
637
- "app",
638
- "mobile",
639
- "react",
640
- "vue",
641
- "angular",
642
- "next",
643
- "nuxt"
644
- ],
645
- backend: [
646
- "api",
647
- "server",
648
- "backend",
649
- "service",
650
- "worker",
651
- "lambda",
652
- "functions"
653
- ],
654
- shared: ["shared", "common", "utils", "lib", "core", "types", "models"],
655
- tooling: [
656
- "scripts",
657
- "tools",
658
- "cli",
659
- "devtools",
660
- "build",
661
- "config",
662
- "infra"
663
- ],
664
- unknown: []
665
- };
666
- });
667
-
668
- // src/introspection/conventions/entryPoints.ts
669
- import * as path4 from "path";
670
434
  function getParentFolder(filepath) {
671
- const dir = path4.dirname(filepath);
672
- return path4.basename(dir);
435
+ const dir = path3.dirname(filepath);
436
+ return path3.basename(dir);
673
437
  }
674
438
  var entryPointConventions;
675
439
  var init_entryPoints = __esm(() => {
@@ -754,53 +518,268 @@ var init_entryPoints = __esm(() => {
754
518
  return filename === "lib.rs" || filename === "main.rs";
755
519
  },
756
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()];
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"]
757
585
  }
758
586
  ];
759
587
  });
760
588
 
761
- // src/introspection/conventions/configFiles.ts
589
+ // src/domain/services/conventions/configFiles.ts
762
590
  var configFileConventions;
763
591
  var init_configFiles = __esm(() => {
764
592
  configFileConventions = [
765
593
  {
766
- id: "package-json",
767
- name: "Package.json",
768
- description: "Node.js package manifest",
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"]
600
+ },
601
+ {
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"]
608
+ },
609
+ {
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"]
616
+ },
617
+ {
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"]
624
+ },
625
+ {
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"]
632
+ },
633
+ {
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
+ ]
647
+ },
648
+ {
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"]
655
+ },
656
+ {
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"]
663
+ },
664
+ {
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"]
671
+ },
672
+ {
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"]
679
+ },
680
+ {
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
+ ]
695
+ },
696
+ {
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"]
703
+ },
704
+ {
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"]
711
+ },
712
+ {
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"]
719
+ },
720
+ {
721
+ id: "poetry-lock",
722
+ name: "Poetry Lock",
723
+ description: "Poetry dependency lock file",
769
724
  category: "configuration",
770
- match: (filepath, filename) => filename === "package.json",
771
- keywords: ["package", "dependencies", "npm", "scripts", "manifest", "node"]
725
+ match: (filepath, filename) => filename === "poetry.lock",
726
+ keywords: ["python", "poetry", "dependencies", "lock", "versions"]
772
727
  },
773
728
  {
774
- id: "pnpm-workspace",
775
- name: "PNPM Workspace",
776
- description: "PNPM monorepo workspace configuration",
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"]
735
+ },
736
+ {
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"]
743
+ },
744
+ {
745
+ id: "mypy-ini",
746
+ name: "Mypy Config",
747
+ description: "Mypy type checker configuration",
777
748
  category: "configuration",
778
- match: (filepath, filename) => filename === "pnpm-workspace.yaml" || filename === "pnpm-workspace.yml",
779
- keywords: ["workspace", "monorepo", "pnpm", "packages"]
749
+ match: (filepath, filename) => filename === "mypy.ini" || filename === ".mypy.ini",
750
+ keywords: ["python", "mypy", "types", "type checking", "static analysis"]
780
751
  },
781
752
  {
782
- id: "yarn-lock",
783
- name: "Yarn Lock",
784
- description: "Yarn dependency lock file",
753
+ id: "flake8",
754
+ name: "Flake8 Config",
755
+ description: "Flake8 linter configuration",
785
756
  category: "configuration",
786
- match: (filepath, filename) => filename === "yarn.lock",
787
- keywords: ["dependencies", "lock", "yarn", "versions"]
757
+ match: (filepath, filename) => filename === ".flake8",
758
+ keywords: ["python", "flake8", "linting", "lint", "style"]
788
759
  },
789
760
  {
790
- id: "package-lock",
791
- name: "Package Lock",
792
- description: "NPM dependency lock file",
761
+ id: "pylintrc",
762
+ name: "Pylint Config",
763
+ description: "Pylint linter configuration",
793
764
  category: "configuration",
794
- match: (filepath, filename) => filename === "package-lock.json",
795
- keywords: ["dependencies", "lock", "npm", "versions"]
765
+ match: (filepath, filename) => filename === ".pylintrc" || filename === "pylintrc" || filename === "pylint.toml",
766
+ keywords: ["python", "pylint", "linting", "lint", "code quality"]
796
767
  },
797
768
  {
798
- id: "bun-lockb",
799
- name: "Bun Lock",
800
- description: "Bun dependency lock file",
769
+ id: "ruff-toml",
770
+ name: "Ruff Config",
771
+ description: "Ruff linter/formatter configuration",
801
772
  category: "configuration",
802
- match: (filepath, filename) => filename === "bun.lockb" || filename === "bun.lock",
803
- keywords: ["dependencies", "lock", "bun", "versions"]
773
+ match: (filepath, filename) => filename === "ruff.toml" || filename === ".ruff.toml",
774
+ keywords: ["python", "ruff", "linting", "formatting", "fast"]
775
+ },
776
+ {
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"]
804
783
  },
805
784
  {
806
785
  id: "tsconfig",
@@ -1043,7 +1022,7 @@ var init_configFiles = __esm(() => {
1043
1022
  ];
1044
1023
  });
1045
1024
 
1046
- // src/introspection/conventions/frameworks/nextjs.ts
1025
+ // src/domain/services/conventions/frameworks/nextjs.ts
1047
1026
  var nextjsConventions, nextjsFramework;
1048
1027
  var init_nextjs = __esm(() => {
1049
1028
  nextjsConventions = [
@@ -1208,7 +1187,7 @@ var init_nextjs = __esm(() => {
1208
1187
  };
1209
1188
  });
1210
1189
 
1211
- // src/introspection/conventions/frameworks/convex.ts
1190
+ // src/domain/services/conventions/frameworks/convex.ts
1212
1191
  var convexConventions, convexFramework;
1213
1192
  var init_convex = __esm(() => {
1214
1193
  convexConventions = [
@@ -1304,7 +1283,7 @@ var init_convex = __esm(() => {
1304
1283
  };
1305
1284
  });
1306
1285
 
1307
- // src/introspection/conventions/frameworks/index.ts
1286
+ // src/domain/services/conventions/frameworks/index.ts
1308
1287
  function getAllFrameworkConventions() {
1309
1288
  return frameworkProviders.flatMap((f) => f.conventions);
1310
1289
  }
@@ -1320,26 +1299,21 @@ var init_frameworks = __esm(() => {
1320
1299
  ];
1321
1300
  });
1322
1301
 
1323
- // src/introspection/conventions/index.ts
1324
- import * as path5 from "path";
1325
- function getAllConventions() {
1302
+ // src/domain/services/conventions/index.ts
1303
+ import * as path4 from "path";
1304
+ function getConventions() {
1326
1305
  return [
1327
1306
  ...entryPointConventions,
1328
1307
  ...configFileConventions,
1329
- ...getAllFrameworkConventions()
1330
- ];
1331
- }
1332
- function getConventions() {
1333
- return [
1334
- ...getAllConventions(),
1308
+ ...getAllFrameworkConventions(),
1335
1309
  ...typeDefinitionConventions,
1336
1310
  ...testFileConventions
1337
1311
  ];
1338
1312
  }
1339
1313
  function getConventionKeywords(filepath) {
1340
1314
  const conventions = getConventions();
1341
- const filename = path5.basename(filepath);
1342
- const extension = path5.extname(filepath);
1315
+ const filename = path4.basename(filepath);
1316
+ const extension = path4.extname(filepath);
1343
1317
  const keywords = new Set;
1344
1318
  for (const convention of conventions) {
1345
1319
  try {
@@ -1386,9 +1360,8 @@ var init_conventions = __esm(() => {
1386
1360
  keywords: ["types", "definitions", "typescript", "interfaces"],
1387
1361
  dynamicKeywords: (filepath) => {
1388
1362
  const match = filepath.match(/([^/]+)\.types\.ts$/);
1389
- if (match) {
1363
+ if (match)
1390
1364
  return [match[1].toLowerCase()];
1391
- }
1392
1365
  return [];
1393
1366
  }
1394
1367
  },
@@ -1411,9 +1384,8 @@ var init_conventions = __esm(() => {
1411
1384
  keywords: ["test", "spec", "unit test"],
1412
1385
  dynamicKeywords: (filepath) => {
1413
1386
  const match = filepath.match(/([^/]+)\.(test|spec)\./);
1414
- if (match) {
1387
+ if (match)
1415
1388
  return [match[1].toLowerCase()];
1416
- }
1417
1389
  return [];
1418
1390
  }
1419
1391
  },
@@ -1428,22 +1400,19 @@ var init_conventions = __esm(() => {
1428
1400
  ];
1429
1401
  });
1430
1402
 
1431
- // src/introspection/fileIntrospector.ts
1432
- import * as path6 from "path";
1403
+ // src/domain/services/introspection.ts
1404
+ import * as path5 from "path";
1433
1405
  function introspectFile(filepath, structure, fileContent) {
1434
1406
  const normalizedPath = filepath.replace(/\\/g, "/");
1435
1407
  const segments = normalizedPath.split("/").filter((s) => s.length > 0);
1436
1408
  const filename = segments[segments.length - 1] || "";
1437
- const ext = path6.extname(filename);
1409
+ const ext = path5.extname(filename);
1438
1410
  const project = findProjectForFile(normalizedPath, structure);
1439
1411
  const language = EXTENSION_TO_LANGUAGE[ext] || "unknown";
1440
1412
  const layer = detectLayer(segments, filename);
1441
1413
  const domain = detectDomain(segments);
1442
1414
  const scope = detectScope(segments, project, layer);
1443
- let framework;
1444
- if (fileContent) {
1445
- framework = detectFramework(fileContent);
1446
- }
1415
+ const framework = fileContent ? detectFramework(fileContent) : undefined;
1447
1416
  return {
1448
1417
  filepath: normalizedPath,
1449
1418
  project,
@@ -1456,21 +1425,81 @@ function introspectFile(filepath, structure, fileContent) {
1456
1425
  pathSegments: segments.slice(0, -1)
1457
1426
  };
1458
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
+ }
1459
1490
  function detectLayer(segments, filename) {
1460
1491
  const filenameLower = filename.toLowerCase();
1461
1492
  for (const [layer, patterns] of Object.entries(LAYER_PATTERNS)) {
1462
1493
  for (const pattern of patterns) {
1463
- if (filenameLower.includes(pattern)) {
1494
+ if (filenameLower.includes(pattern))
1464
1495
  return layer;
1465
- }
1466
1496
  }
1467
1497
  }
1468
1498
  for (let i = segments.length - 2;i >= 0; i--) {
1469
1499
  const segment = segments[i].toLowerCase();
1470
1500
  for (const [layer, patterns] of Object.entries(LAYER_PATTERNS)) {
1471
- if (patterns.includes(segment)) {
1501
+ if (patterns.includes(segment))
1472
1502
  return layer;
1473
- }
1474
1503
  }
1475
1504
  }
1476
1505
  return;
@@ -1491,9 +1520,8 @@ function detectDomain(segments) {
1491
1520
  const segmentLower = segment.toLowerCase();
1492
1521
  if (skipSegments.has(segmentLower))
1493
1522
  continue;
1494
- if (DOMAIN_PATTERNS.includes(segmentLower)) {
1523
+ if (DOMAIN_PATTERNS.includes(segmentLower))
1495
1524
  return segmentLower;
1496
- }
1497
1525
  for (const domain of DOMAIN_PATTERNS) {
1498
1526
  if (segmentLower.startsWith(domain) || segmentLower.endsWith(domain)) {
1499
1527
  return domain;
@@ -1504,9 +1532,8 @@ function detectDomain(segments) {
1504
1532
  }
1505
1533
  function detectScope(segments, project, layer) {
1506
1534
  const projectScope = detectScopeFromName(project.name);
1507
- if (projectScope !== "unknown") {
1535
+ if (projectScope !== "unknown")
1508
1536
  return projectScope;
1509
- }
1510
1537
  if (layer) {
1511
1538
  switch (layer) {
1512
1539
  case "controller":
@@ -1524,15 +1551,12 @@ function detectScope(segments, project, layer) {
1524
1551
  }
1525
1552
  for (const segment of segments) {
1526
1553
  const segmentLower = segment.toLowerCase();
1527
- if (["server", "api", "backend"].includes(segmentLower)) {
1554
+ if (["server", "api", "backend"].includes(segmentLower))
1528
1555
  return "backend";
1529
- }
1530
- if (["client", "web", "frontend", "ui"].includes(segmentLower)) {
1556
+ if (["client", "web", "frontend", "ui"].includes(segmentLower))
1531
1557
  return "frontend";
1532
- }
1533
- if (["shared", "common", "lib", "libs"].includes(segmentLower)) {
1558
+ if (["shared", "common", "lib", "libs"].includes(segmentLower))
1534
1559
  return "shared";
1535
- }
1536
1560
  }
1537
1561
  return "unknown";
1538
1562
  }
@@ -1546,44 +1570,8 @@ function detectFramework(content) {
1546
1570
  }
1547
1571
  return;
1548
1572
  }
1549
- function introspectionToKeywords(intro) {
1550
- const keywords = [];
1551
- const filename = path6.basename(intro.filepath);
1552
- const filenameWithoutExt = filename.replace(/\.[^.]+$/, "");
1553
- const filenameParts = filenameWithoutExt.split(/[-_.]/).flatMap((part) => part.split(/(?=[A-Z])/)).map((part) => part.toLowerCase()).filter((part) => part.length > 1);
1554
- keywords.push(...filenameParts);
1555
- keywords.push(filenameWithoutExt.toLowerCase());
1556
- if (intro.project.name && intro.project.name !== "root") {
1557
- keywords.push(intro.project.name.toLowerCase());
1558
- }
1559
- if (intro.scope !== "unknown") {
1560
- keywords.push(intro.scope);
1561
- }
1562
- if (intro.layer) {
1563
- keywords.push(intro.layer);
1564
- }
1565
- if (intro.domain) {
1566
- keywords.push(intro.domain);
1567
- }
1568
- if (intro.language !== "unknown") {
1569
- keywords.push(intro.language);
1570
- }
1571
- if (intro.framework) {
1572
- keywords.push(intro.framework);
1573
- }
1574
- const skipSegments = new Set(["src", "lib", "index"]);
1575
- for (const segment of intro.pathSegments) {
1576
- if (!skipSegments.has(segment.toLowerCase()) && segment.length > 2) {
1577
- keywords.push(segment.toLowerCase());
1578
- }
1579
- }
1580
- const conventionKeywords = getConventionKeywords(intro.filepath);
1581
- keywords.push(...conventionKeywords);
1582
- return [...new Set(keywords)];
1583
- }
1584
- var LAYER_PATTERNS, DOMAIN_PATTERNS, FRAMEWORK_INDICATORS, EXTENSION_TO_LANGUAGE;
1585
- var init_fileIntrospector = __esm(() => {
1586
- init_projectDetector();
1573
+ var LAYER_PATTERNS, DOMAIN_PATTERNS, FRAMEWORK_INDICATORS, EXTENSION_TO_LANGUAGE, SCOPE_KEYWORDS, PROJECT_PATTERNS;
1574
+ var init_introspection = __esm(() => {
1587
1575
  init_conventions();
1588
1576
  LAYER_PATTERNS = {
1589
1577
  controller: ["controller", "api", "routes", "route", "handler"],
@@ -1702,120 +1690,45 @@ var init_fileIntrospector = __esm(() => {
1702
1690
  ".md": "markdown",
1703
1691
  ".json": "json",
1704
1692
  ".yaml": "yaml",
1705
- ".yml": "yaml"
1693
+ ".yml": "yaml",
1694
+ ".txt": "text"
1706
1695
  };
1707
- });
1708
-
1709
- // src/introspection/index.ts
1710
- import * as path7 from "path";
1711
- import * as fs3 from "fs/promises";
1712
-
1713
- class IntrospectionIndex {
1714
- rootDir;
1715
- structure = null;
1716
- files = new Map;
1717
- config = {};
1718
- constructor(rootDir) {
1719
- this.rootDir = rootDir;
1720
- }
1721
- async initialize() {
1722
- this.structure = await detectProjectStructure(this.rootDir);
1723
- try {
1724
- const configPath = path7.join(this.rootDir, ".raggrep", "config.json");
1725
- const configContent = await fs3.readFile(configPath, "utf-8");
1726
- const config = JSON.parse(configContent);
1727
- this.config = config.introspection || {};
1728
- } catch {}
1729
- }
1730
- getStructure() {
1731
- return this.structure;
1732
- }
1733
- addFile(filepath, content) {
1734
- if (!this.structure) {
1735
- throw new Error("IntrospectionIndex not initialized");
1736
- }
1737
- const intro = introspectFile(filepath, this.structure, content);
1738
- this.applyOverrides(intro);
1739
- this.files.set(filepath, intro);
1740
- return intro;
1741
- }
1742
- getFile(filepath) {
1743
- return this.files.get(filepath);
1744
- }
1745
- getAllFiles() {
1746
- return Array.from(this.files.values());
1747
- }
1748
- applyOverrides(intro) {
1749
- if (!this.config.projects)
1750
- return;
1751
- for (const [projectPath, overrides] of Object.entries(this.config.projects)) {
1752
- if (intro.filepath.startsWith(projectPath + "/") || intro.project.root === projectPath) {
1753
- if (overrides.scope) {
1754
- intro.scope = overrides.scope;
1755
- }
1756
- if (overrides.framework) {
1757
- intro.framework = overrides.framework;
1758
- }
1759
- break;
1760
- }
1761
- }
1762
- }
1763
- async save(config) {
1764
- const introDir = path7.join(getRaggrepDir(this.rootDir, config), "introspection");
1765
- await fs3.mkdir(introDir, { recursive: true });
1766
- const projectPath = path7.join(introDir, "_project.json");
1767
- await fs3.writeFile(projectPath, JSON.stringify({
1768
- version: "1.0.0",
1769
- lastUpdated: new Date().toISOString(),
1770
- structure: this.structure
1771
- }, null, 2));
1772
- for (const [filepath, intro] of this.files) {
1773
- const introFilePath = path7.join(introDir, "files", filepath.replace(/\.[^.]+$/, ".json"));
1774
- await fs3.mkdir(path7.dirname(introFilePath), { recursive: true });
1775
- await fs3.writeFile(introFilePath, JSON.stringify(intro, null, 2));
1776
- }
1777
- console.log(` [Introspection] Saved metadata for ${this.files.size} files`);
1778
- }
1779
- async load(config) {
1780
- const introDir = path7.join(getRaggrepDir(this.rootDir, config), "introspection");
1781
- try {
1782
- const projectPath = path7.join(introDir, "_project.json");
1783
- const projectContent = await fs3.readFile(projectPath, "utf-8");
1784
- const projectData = JSON.parse(projectContent);
1785
- this.structure = projectData.structure;
1786
- await this.loadFilesRecursive(path7.join(introDir, "files"), "");
1787
- } catch {
1788
- this.structure = null;
1789
- this.files.clear();
1790
- }
1791
- }
1792
- async loadFilesRecursive(basePath, prefix) {
1793
- try {
1794
- const entries = await fs3.readdir(basePath, { withFileTypes: true });
1795
- for (const entry of entries) {
1796
- const entryPath = path7.join(basePath, entry.name);
1797
- const relativePath = prefix ? `${prefix}/${entry.name}` : entry.name;
1798
- if (entry.isDirectory()) {
1799
- await this.loadFilesRecursive(entryPath, relativePath);
1800
- } else if (entry.name.endsWith(".json")) {
1801
- const content = await fs3.readFile(entryPath, "utf-8");
1802
- const intro = JSON.parse(content);
1803
- this.files.set(intro.filepath, intro);
1804
- }
1805
- }
1806
- } catch {}
1807
- }
1808
- clear() {
1809
- this.files.clear();
1810
- this.structure = null;
1811
- }
1812
- }
1813
- var init_introspection = __esm(() => {
1814
- init_projectDetector();
1815
- init_fileIntrospector();
1816
- init_config2();
1817
- init_fileIntrospector();
1818
- init_projectDetector();
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
+ ];
1819
1732
  });
1820
1733
 
1821
1734
  // src/modules/core/symbols.ts
@@ -1985,8 +1898,8 @@ var exports_core = {};
1985
1898
  __export(exports_core, {
1986
1899
  CoreModule: () => CoreModule
1987
1900
  });
1988
- import * as path8 from "path";
1989
- import * as fs4 from "fs/promises";
1901
+ import * as path6 from "path";
1902
+ import * as fs2 from "fs/promises";
1990
1903
 
1991
1904
  class CoreModule {
1992
1905
  id = "core";
@@ -2004,7 +1917,9 @@ class CoreModule {
2004
1917
  const contentTokens = tokenize(content);
2005
1918
  const intro = ctx.getIntrospection?.(filepath);
2006
1919
  const introKeywords = intro ? introspectionToKeywords(intro) : [];
2007
- const allTokens = [...new Set([...contentTokens, ...symbolKeywords, ...introKeywords])];
1920
+ const allTokens = [
1921
+ ...new Set([...contentTokens, ...symbolKeywords, ...introKeywords])
1922
+ ];
2008
1923
  const chunks = this.createChunks(filepath, content, symbols);
2009
1924
  const stats = await ctx.getFileStats(filepath);
2010
1925
  this.symbolIndex.set(filepath, {
@@ -2078,8 +1993,8 @@ class CoreModule {
2078
1993
  }
2079
1994
  async finalize(ctx) {
2080
1995
  const config = ctx.config;
2081
- const coreDir = path8.join(getRaggrepDir(ctx.rootDir, config), "index", "core");
2082
- await fs4.mkdir(coreDir, { recursive: true });
1996
+ const coreDir = path6.join(getRaggrepDir(ctx.rootDir, config), "index", "core");
1997
+ await fs2.mkdir(coreDir, { recursive: true });
2083
1998
  this.bm25Index = new BM25Index;
2084
1999
  for (const [filepath, entry] of this.symbolIndex) {
2085
2000
  this.bm25Index.addDocument(filepath, entry.tokens);
@@ -2090,7 +2005,7 @@ class CoreModule {
2090
2005
  files: Object.fromEntries(this.symbolIndex),
2091
2006
  bm25Data: this.bm25Index.serialize()
2092
2007
  };
2093
- await fs4.writeFile(path8.join(coreDir, "symbols.json"), JSON.stringify(symbolIndexData, null, 2));
2008
+ await fs2.writeFile(path6.join(coreDir, "symbols.json"), JSON.stringify(symbolIndexData, null, 2));
2094
2009
  console.log(` [Core] Symbol index built with ${this.symbolIndex.size} files`);
2095
2010
  }
2096
2011
  async search(query, ctx, options) {
@@ -2187,10 +2102,10 @@ class CoreModule {
2187
2102
  return bestChunk;
2188
2103
  }
2189
2104
  async loadSymbolIndex(rootDir, config) {
2190
- const coreDir = path8.join(getRaggrepDir(rootDir, config), "index", "core");
2191
- const symbolsPath = path8.join(coreDir, "symbols.json");
2105
+ const coreDir = path6.join(getRaggrepDir(rootDir, config), "index", "core");
2106
+ const symbolsPath = path6.join(coreDir, "symbols.json");
2192
2107
  try {
2193
- const content = await fs4.readFile(symbolsPath, "utf-8");
2108
+ const content = await fs2.readFile(symbolsPath, "utf-8");
2194
2109
  const data = JSON.parse(content);
2195
2110
  this.symbolIndex = new Map(Object.entries(data.files));
2196
2111
  if (data.bm25Data) {
@@ -2617,8 +2532,8 @@ var init_keywords = __esm(() => {
2617
2532
  });
2618
2533
 
2619
2534
  // src/infrastructure/storage/symbolicIndex.ts
2620
- import * as fs5 from "fs/promises";
2621
- import * as path9 from "path";
2535
+ import * as fs3 from "fs/promises";
2536
+ import * as path7 from "path";
2622
2537
 
2623
2538
  class SymbolicIndex {
2624
2539
  meta = null;
@@ -2627,7 +2542,7 @@ class SymbolicIndex {
2627
2542
  symbolicPath;
2628
2543
  moduleId;
2629
2544
  constructor(indexDir, moduleId) {
2630
- this.symbolicPath = path9.join(indexDir, "index", moduleId, "symbolic");
2545
+ this.symbolicPath = path7.join(indexDir, "index", moduleId, "symbolic");
2631
2546
  this.moduleId = moduleId;
2632
2547
  }
2633
2548
  async initialize() {
@@ -2687,18 +2602,18 @@ class SymbolicIndex {
2687
2602
  throw new Error("Index not initialized");
2688
2603
  this.meta.lastUpdated = new Date().toISOString();
2689
2604
  this.meta.fileCount = this.fileSummaries.size;
2690
- await fs5.mkdir(this.symbolicPath, { recursive: true });
2691
- const metaPath = path9.join(this.symbolicPath, "_meta.json");
2692
- await fs5.writeFile(metaPath, JSON.stringify(this.meta, null, 2));
2605
+ await fs3.mkdir(this.symbolicPath, { recursive: true });
2606
+ const metaPath = path7.join(this.symbolicPath, "_meta.json");
2607
+ await fs3.writeFile(metaPath, JSON.stringify(this.meta, null, 2));
2693
2608
  for (const [filepath, summary] of this.fileSummaries) {
2694
2609
  const summaryPath = this.getFileSummaryPath(filepath);
2695
- await fs5.mkdir(path9.dirname(summaryPath), { recursive: true });
2696
- await fs5.writeFile(summaryPath, JSON.stringify(summary, null, 2));
2610
+ await fs3.mkdir(path7.dirname(summaryPath), { recursive: true });
2611
+ await fs3.writeFile(summaryPath, JSON.stringify(summary, null, 2));
2697
2612
  }
2698
2613
  }
2699
2614
  async load() {
2700
- const metaPath = path9.join(this.symbolicPath, "_meta.json");
2701
- const metaContent = await fs5.readFile(metaPath, "utf-8");
2615
+ const metaPath = path7.join(this.symbolicPath, "_meta.json");
2616
+ const metaContent = await fs3.readFile(metaPath, "utf-8");
2702
2617
  this.meta = JSON.parse(metaContent);
2703
2618
  this.fileSummaries.clear();
2704
2619
  await this.loadFileSummariesRecursive(this.symbolicPath);
@@ -2706,14 +2621,14 @@ class SymbolicIndex {
2706
2621
  }
2707
2622
  async loadFileSummariesRecursive(dir) {
2708
2623
  try {
2709
- const entries = await fs5.readdir(dir, { withFileTypes: true });
2624
+ const entries = await fs3.readdir(dir, { withFileTypes: true });
2710
2625
  for (const entry of entries) {
2711
- const fullPath = path9.join(dir, entry.name);
2626
+ const fullPath = path7.join(dir, entry.name);
2712
2627
  if (entry.isDirectory()) {
2713
2628
  await this.loadFileSummariesRecursive(fullPath);
2714
2629
  } else if (entry.name.endsWith(".json") && entry.name !== "_meta.json") {
2715
2630
  try {
2716
- const content = await fs5.readFile(fullPath, "utf-8");
2631
+ const content = await fs3.readFile(fullPath, "utf-8");
2717
2632
  const summary = JSON.parse(content);
2718
2633
  if (summary.filepath) {
2719
2634
  this.fileSummaries.set(summary.filepath, summary);
@@ -2725,18 +2640,18 @@ class SymbolicIndex {
2725
2640
  }
2726
2641
  getFileSummaryPath(filepath) {
2727
2642
  const jsonPath = filepath.replace(/\.[^.]+$/, ".json");
2728
- return path9.join(this.symbolicPath, jsonPath);
2643
+ return path7.join(this.symbolicPath, jsonPath);
2729
2644
  }
2730
2645
  async deleteFileSummary(filepath) {
2731
2646
  try {
2732
- await fs5.unlink(this.getFileSummaryPath(filepath));
2647
+ await fs3.unlink(this.getFileSummaryPath(filepath));
2733
2648
  } catch {}
2734
2649
  this.fileSummaries.delete(filepath);
2735
2650
  }
2736
2651
  async exists() {
2737
2652
  try {
2738
- const metaPath = path9.join(this.symbolicPath, "_meta.json");
2739
- await fs5.access(metaPath);
2653
+ const metaPath = path7.join(this.symbolicPath, "_meta.json");
2654
+ await fs3.access(metaPath);
2740
2655
  return true;
2741
2656
  } catch {
2742
2657
  return false;
@@ -2775,7 +2690,7 @@ __export(exports_typescript, {
2775
2690
  DEFAULT_TOP_K: () => DEFAULT_TOP_K2,
2776
2691
  DEFAULT_MIN_SCORE: () => DEFAULT_MIN_SCORE2
2777
2692
  });
2778
- import * as path10 from "path";
2693
+ import * as path8 from "path";
2779
2694
 
2780
2695
  class TypeScriptModule {
2781
2696
  id = "language/typescript";
@@ -2969,16 +2884,16 @@ class TypeScriptModule {
2969
2884
  while ((match = importRegex.exec(content)) !== null) {
2970
2885
  const importPath = match[1];
2971
2886
  if (importPath.startsWith(".")) {
2972
- const dir = path10.dirname(filepath);
2973
- const resolved = path10.normalize(path10.join(dir, importPath));
2887
+ const dir = path8.dirname(filepath);
2888
+ const resolved = path8.normalize(path8.join(dir, importPath));
2974
2889
  references.push(resolved);
2975
2890
  }
2976
2891
  }
2977
2892
  while ((match = requireRegex.exec(content)) !== null) {
2978
2893
  const importPath = match[1];
2979
2894
  if (importPath.startsWith(".")) {
2980
- const dir = path10.dirname(filepath);
2981
- const resolved = path10.normalize(path10.join(dir, importPath));
2895
+ const dir = path8.dirname(filepath);
2896
+ const resolved = path8.normalize(path8.join(dir, importPath));
2982
2897
  references.push(resolved);
2983
2898
  }
2984
2899
  }
@@ -3026,6 +2941,270 @@ var init_registry = __esm(() => {
3026
2941
  registry = new ModuleRegistryImpl;
3027
2942
  });
3028
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);
2959
+ }
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);
2968
+ }
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";
2986
+ }
2987
+ const hasWorkspaces = Boolean(pkg.workspaces);
2988
+ return { name, relativePath, type, hasWorkspaces };
2989
+ } catch {
2990
+ return null;
2991
+ }
2992
+ }
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 {}
3037
+ }
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
+ };
3076
+ }
3077
+ }
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
+ ]);
3090
+ });
3091
+
3092
+ // src/infrastructure/introspection/IntrospectionIndex.ts
3093
+ import * as path10 from "path";
3094
+ import * as fs5 from "fs/promises";
3095
+
3096
+ class IntrospectionIndex {
3097
+ rootDir;
3098
+ structure = null;
3099
+ files = new Map;
3100
+ config = {};
3101
+ constructor(rootDir) {
3102
+ this.rootDir = rootDir;
3103
+ }
3104
+ async initialize() {
3105
+ this.structure = await detectProjectStructure(this.rootDir);
3106
+ try {
3107
+ const configPath = path10.join(this.rootDir, ".raggrep", "config.json");
3108
+ const configContent = await fs5.readFile(configPath, "utf-8");
3109
+ const config = JSON.parse(configContent);
3110
+ this.config = config.introspection || {};
3111
+ } catch {}
3112
+ }
3113
+ getStructure() {
3114
+ return this.structure;
3115
+ }
3116
+ addFile(filepath, content) {
3117
+ if (!this.structure) {
3118
+ throw new Error("IntrospectionIndex not initialized");
3119
+ }
3120
+ const intro = introspectFile(filepath, this.structure, content);
3121
+ this.applyOverrides(intro);
3122
+ this.files.set(filepath, intro);
3123
+ return intro;
3124
+ }
3125
+ getFile(filepath) {
3126
+ return this.files.get(filepath);
3127
+ }
3128
+ getAllFiles() {
3129
+ return Array.from(this.files.values());
3130
+ }
3131
+ applyOverrides(intro) {
3132
+ if (!this.config.projects)
3133
+ return;
3134
+ for (const [projectPath, overrides] of Object.entries(this.config.projects)) {
3135
+ if (intro.filepath.startsWith(projectPath + "/") || intro.project.root === projectPath) {
3136
+ if (overrides.scope) {
3137
+ intro.scope = overrides.scope;
3138
+ }
3139
+ if (overrides.framework) {
3140
+ intro.framework = overrides.framework;
3141
+ }
3142
+ break;
3143
+ }
3144
+ }
3145
+ }
3146
+ async save(config) {
3147
+ const introDir = path10.join(getRaggrepDir(this.rootDir, config), "introspection");
3148
+ await fs5.mkdir(introDir, { recursive: true });
3149
+ const projectPath = path10.join(introDir, "_project.json");
3150
+ await fs5.writeFile(projectPath, JSON.stringify({
3151
+ version: "1.0.0",
3152
+ lastUpdated: new Date().toISOString(),
3153
+ structure: this.structure
3154
+ }, null, 2));
3155
+ for (const [filepath, intro] of this.files) {
3156
+ const introFilePath = path10.join(introDir, "files", filepath.replace(/\.[^.]+$/, ".json"));
3157
+ await fs5.mkdir(path10.dirname(introFilePath), { recursive: true });
3158
+ await fs5.writeFile(introFilePath, JSON.stringify(intro, null, 2));
3159
+ }
3160
+ console.log(` [Introspection] Saved metadata for ${this.files.size} files`);
3161
+ }
3162
+ async load(config) {
3163
+ const introDir = path10.join(getRaggrepDir(this.rootDir, config), "introspection");
3164
+ try {
3165
+ const projectPath = path10.join(introDir, "_project.json");
3166
+ const projectContent = await fs5.readFile(projectPath, "utf-8");
3167
+ const projectData = JSON.parse(projectContent);
3168
+ this.structure = projectData.structure;
3169
+ await this.loadFilesRecursive(path10.join(introDir, "files"), "");
3170
+ } catch {
3171
+ this.structure = null;
3172
+ this.files.clear();
3173
+ }
3174
+ }
3175
+ async loadFilesRecursive(basePath, prefix) {
3176
+ try {
3177
+ const entries = await fs5.readdir(basePath, { withFileTypes: true });
3178
+ for (const entry of entries) {
3179
+ const entryPath = path10.join(basePath, entry.name);
3180
+ const relativePath = prefix ? `${prefix}/${entry.name}` : entry.name;
3181
+ if (entry.isDirectory()) {
3182
+ await this.loadFilesRecursive(entryPath, relativePath);
3183
+ } else if (entry.name.endsWith(".json")) {
3184
+ const content = await fs5.readFile(entryPath, "utf-8");
3185
+ const intro = JSON.parse(content);
3186
+ this.files.set(intro.filepath, intro);
3187
+ }
3188
+ }
3189
+ } catch {}
3190
+ }
3191
+ clear() {
3192
+ this.files.clear();
3193
+ this.structure = null;
3194
+ }
3195
+ }
3196
+ var init_IntrospectionIndex = __esm(() => {
3197
+ init_projectDetector();
3198
+ init_introspection();
3199
+ init_config2();
3200
+ });
3201
+
3202
+ // src/infrastructure/introspection/index.ts
3203
+ var init_introspection2 = __esm(() => {
3204
+ init_IntrospectionIndex();
3205
+ init_projectDetector();
3206
+ });
3207
+
3029
3208
  // src/app/indexer/watcher.ts
3030
3209
  import { watch } from "chokidar";
3031
3210
  import * as path11 from "path";
@@ -3521,7 +3700,7 @@ async function getIndexStatus(rootDir) {
3521
3700
  var init_indexer = __esm(() => {
3522
3701
  init_config2();
3523
3702
  init_registry();
3524
- init_introspection();
3703
+ init_introspection2();
3525
3704
  init_watcher();
3526
3705
  });
3527
3706
 
@@ -3615,6 +3794,20 @@ async function loadGlobalManifest(rootDir, config) {
3615
3794
  return null;
3616
3795
  }
3617
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
+ }
3618
3811
  function formatSearchResults(results) {
3619
3812
  if (results.length === 0) {
3620
3813
  return "No results found.";
@@ -3630,6 +3823,7 @@ function formatSearchResults(results) {
3630
3823
  output += `${i + 1}. ${location}${nameInfo}
3631
3824
  `;
3632
3825
  output += ` Score: ${(result.score * 100).toFixed(1)}% | Type: ${chunk.type}`;
3826
+ output += ` | via ${formatModuleName(result.moduleId)}`;
3633
3827
  if (chunk.isExported) {
3634
3828
  output += " | exported";
3635
3829
  }
@@ -3657,7 +3851,7 @@ init_embeddings();
3657
3851
  // package.json
3658
3852
  var package_default = {
3659
3853
  name: "raggrep",
3660
- version: "0.1.6",
3854
+ version: "0.1.7",
3661
3855
  description: "Local filesystem-based RAG system for codebases - semantic search using local embeddings",
3662
3856
  type: "module",
3663
3857
  main: "./dist/index.js",
@@ -4092,4 +4286,4 @@ Run 'raggrep <command> --help' for more information.
4092
4286
  }
4093
4287
  main();
4094
4288
 
4095
- //# debugId=03A02811A6080C5964756E2164756E21
4289
+ //# debugId=C248CB1C621D0FC764756E2164756E21