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.
Files changed (27) hide show
  1. package/README.md +23 -9
  2. package/dist/app/indexer/index.d.ts +2 -2
  3. package/dist/cli/main.js +1964 -918
  4. package/dist/cli/main.js.map +21 -14
  5. package/dist/domain/entities/conventions.d.ts +63 -0
  6. package/dist/domain/entities/index.d.ts +2 -0
  7. package/dist/domain/services/conventions/configFiles.d.ts +10 -0
  8. package/dist/domain/services/conventions/conventions.test.d.ts +4 -0
  9. package/dist/domain/services/conventions/entryPoints.d.ts +10 -0
  10. package/dist/domain/services/conventions/frameworks/convex.d.ts +11 -0
  11. package/dist/domain/services/conventions/frameworks/index.d.ts +22 -0
  12. package/dist/domain/services/conventions/frameworks/nextjs.d.ts +10 -0
  13. package/dist/domain/services/conventions/index.d.ts +39 -0
  14. package/dist/domain/services/introspection.d.ts +31 -0
  15. package/dist/index.js +1452 -416
  16. package/dist/index.js.map +20 -14
  17. package/dist/infrastructure/config/configLoader.d.ts +22 -3
  18. package/dist/infrastructure/config/index.d.ts +1 -1
  19. package/dist/{introspection/index.d.ts → infrastructure/introspection/IntrospectionIndex.d.ts} +3 -14
  20. package/dist/infrastructure/introspection/index.d.ts +9 -0
  21. package/dist/{introspection → infrastructure/introspection}/projectDetector.d.ts +3 -12
  22. package/dist/tests/integration.test.d.ts +9 -0
  23. package/dist/types.d.ts +4 -4
  24. package/package.json +1 -1
  25. package/dist/introspection/fileIntrospector.d.ts +0 -14
  26. /package/dist/{introspection/types.d.ts → domain/entities/introspection.d.ts} +0 -0
  27. /package/dist/{introspection → domain/services}/introspection.test.d.ts +0 -0
package/dist/index.js CHANGED
@@ -76,7 +76,8 @@ var init_config = __esm(() => {
76
76
  ".go",
77
77
  ".rs",
78
78
  ".java",
79
- ".md"
79
+ ".md",
80
+ ".txt"
80
81
  ];
81
82
  });
82
83
 
@@ -89,20 +90,40 @@ var init_entities = __esm(() => {
89
90
  // src/infrastructure/config/configLoader.ts
90
91
  import * as path from "path";
91
92
  import * as fs from "fs/promises";
92
- function getRaggrepDir(rootDir, config = DEFAULT_CONFIG) {
93
- return path.join(rootDir, config.indexDir);
93
+ import * as os from "os";
94
+ import * as crypto from "crypto";
95
+ function hashPath(inputPath) {
96
+ return crypto.createHash("sha256").update(inputPath).digest("hex").slice(0, 12);
97
+ }
98
+ function getRaggrepDir(rootDir, _config = DEFAULT_CONFIG) {
99
+ const absoluteRoot = path.resolve(rootDir);
100
+ const projectHash = hashPath(absoluteRoot);
101
+ return path.join(RAGGREP_TEMP_BASE, projectHash);
102
+ }
103
+ function getIndexLocation(rootDir) {
104
+ const absoluteRoot = path.resolve(rootDir);
105
+ const projectHash = hashPath(absoluteRoot);
106
+ return {
107
+ indexDir: path.join(RAGGREP_TEMP_BASE, projectHash),
108
+ projectRoot: absoluteRoot,
109
+ projectHash
110
+ };
94
111
  }
95
112
  function getModuleIndexPath(rootDir, moduleId, config = DEFAULT_CONFIG) {
96
- return path.join(rootDir, config.indexDir, "index", moduleId);
113
+ const indexDir = getRaggrepDir(rootDir, config);
114
+ return path.join(indexDir, "index", moduleId);
97
115
  }
98
116
  function getModuleManifestPath(rootDir, moduleId, config = DEFAULT_CONFIG) {
99
- return path.join(rootDir, config.indexDir, "index", moduleId, "manifest.json");
117
+ const indexDir = getRaggrepDir(rootDir, config);
118
+ return path.join(indexDir, "index", moduleId, "manifest.json");
100
119
  }
101
120
  function getGlobalManifestPath(rootDir, config = DEFAULT_CONFIG) {
102
- return path.join(rootDir, config.indexDir, "manifest.json");
121
+ const indexDir = getRaggrepDir(rootDir, config);
122
+ return path.join(indexDir, "manifest.json");
103
123
  }
104
124
  function getConfigPath(rootDir, config = DEFAULT_CONFIG) {
105
- return path.join(rootDir, config.indexDir, "config.json");
125
+ const indexDir = getRaggrepDir(rootDir, config);
126
+ return path.join(indexDir, "config.json");
106
127
  }
107
128
  async function loadConfig(rootDir) {
108
129
  const configPath = getConfigPath(rootDir, DEFAULT_CONFIG);
@@ -129,10 +150,11 @@ function getEmbeddingConfigFromModule(moduleConfig) {
129
150
  showProgress: options.showProgress !== false
130
151
  };
131
152
  }
132
- var DEFAULT_CONFIG, EMBEDDING_MODELS;
153
+ var DEFAULT_CONFIG, RAGGREP_TEMP_BASE, EMBEDDING_MODELS;
133
154
  var init_configLoader = __esm(() => {
134
155
  init_entities();
135
156
  DEFAULT_CONFIG = createDefaultConfig();
157
+ RAGGREP_TEMP_BASE = path.join(os.tmpdir(), "raggrep-indexes");
136
158
  EMBEDDING_MODELS = {
137
159
  "all-MiniLM-L6-v2": "Xenova/all-MiniLM-L6-v2",
138
160
  "all-MiniLM-L12-v2": "Xenova/all-MiniLM-L12-v2",
@@ -232,21 +254,1323 @@ class BM25Index {
232
254
  totalDocs: this.totalDocs
233
255
  };
234
256
  }
235
- static deserialize(data) {
236
- const index = new BM25Index;
237
- index.avgDocLength = data.avgDocLength;
238
- index.totalDocs = data.totalDocs;
239
- index.documentFrequencies = new Map(Object.entries(data.documentFrequencies));
240
- for (const [id, tokens] of Object.entries(data.documents)) {
241
- index.documents.set(id, { content: "", tokens });
257
+ static deserialize(data) {
258
+ const index = new BM25Index;
259
+ index.avgDocLength = data.avgDocLength;
260
+ index.totalDocs = data.totalDocs;
261
+ index.documentFrequencies = new Map(Object.entries(data.documentFrequencies));
262
+ for (const [id, tokens] of Object.entries(data.documents)) {
263
+ index.documents.set(id, { content: "", tokens });
264
+ }
265
+ return index;
266
+ }
267
+ }
268
+ function normalizeScore(score, midpoint = 5) {
269
+ return 1 / (1 + Math.exp(-score / midpoint + 1));
270
+ }
271
+ var BM25_K1 = 1.5, BM25_B = 0.75;
272
+
273
+ // src/domain/services/conventions/entryPoints.ts
274
+ import * as path2 from "path";
275
+ function getParentFolder(filepath) {
276
+ const dir = path2.dirname(filepath);
277
+ return path2.basename(dir);
278
+ }
279
+ var entryPointConventions;
280
+ var init_entryPoints = __esm(() => {
281
+ entryPointConventions = [
282
+ {
283
+ id: "index-file",
284
+ name: "Index/Barrel File",
285
+ description: "Module entry point that typically re-exports from other files",
286
+ category: "entry-point",
287
+ match: (filepath, filename) => {
288
+ return /^index\.(ts|tsx|js|jsx|mjs|cjs)$/.test(filename);
289
+ },
290
+ keywords: ["entry", "barrel", "exports", "module"],
291
+ dynamicKeywords: (filepath) => {
292
+ const parent = getParentFolder(filepath);
293
+ if (["src", "lib", "dist", "build", ".", ""].includes(parent)) {
294
+ return [];
295
+ }
296
+ return [parent.toLowerCase()];
297
+ }
298
+ },
299
+ {
300
+ id: "main-file",
301
+ name: "Main Entry Point",
302
+ description: "Application main entry point",
303
+ category: "entry-point",
304
+ match: (filepath, filename) => {
305
+ return /^main\.(ts|tsx|js|jsx|mjs|cjs)$/.test(filename);
306
+ },
307
+ keywords: ["entry", "main", "entrypoint", "bootstrap", "startup"]
308
+ },
309
+ {
310
+ id: "app-component",
311
+ name: "Root App Component",
312
+ description: "Root application component (React, Vue, etc.)",
313
+ category: "entry-point",
314
+ match: (filepath, filename) => {
315
+ return /^App\.(tsx|jsx|vue|svelte)$/.test(filename);
316
+ },
317
+ keywords: ["root", "app", "application", "component", "main"]
318
+ },
319
+ {
320
+ id: "deno-mod",
321
+ name: "Deno Module Entry",
322
+ description: "Deno module entry point",
323
+ category: "entry-point",
324
+ match: (filepath, filename) => {
325
+ return filename === "mod.ts";
326
+ },
327
+ keywords: ["entry", "module", "deno", "exports"],
328
+ dynamicKeywords: (filepath) => {
329
+ const parent = getParentFolder(filepath);
330
+ if (["src", "lib", ".", ""].includes(parent)) {
331
+ return [];
332
+ }
333
+ return [parent.toLowerCase()];
334
+ }
335
+ },
336
+ {
337
+ id: "python-init",
338
+ name: "Python Package Init",
339
+ description: "Python package initialization file",
340
+ category: "entry-point",
341
+ match: (filepath, filename) => {
342
+ return filename === "__init__.py";
343
+ },
344
+ keywords: ["entry", "package", "init", "python", "module"],
345
+ dynamicKeywords: (filepath) => {
346
+ const parent = getParentFolder(filepath);
347
+ if (["src", "lib", ".", ""].includes(parent)) {
348
+ return [];
349
+ }
350
+ return [parent.toLowerCase()];
351
+ }
352
+ },
353
+ {
354
+ id: "rust-lib",
355
+ name: "Rust Library Entry",
356
+ description: "Rust library crate entry point",
357
+ category: "entry-point",
358
+ match: (filepath, filename) => {
359
+ return filename === "lib.rs" || filename === "main.rs";
360
+ },
361
+ keywords: ["entry", "crate", "rust", "module"]
362
+ },
363
+ {
364
+ id: "go-main",
365
+ name: "Go Main Entry",
366
+ description: "Go application main entry point",
367
+ category: "entry-point",
368
+ match: (filepath, filename) => {
369
+ return filename === "main.go";
370
+ },
371
+ keywords: ["entry", "main", "go", "golang", "entrypoint"],
372
+ dynamicKeywords: (filepath) => {
373
+ const parent = getParentFolder(filepath);
374
+ if (parent && !["cmd", "src", ".", ""].includes(parent)) {
375
+ return [parent.toLowerCase()];
376
+ }
377
+ return [];
378
+ }
379
+ },
380
+ {
381
+ id: "python-main",
382
+ name: "Python Main Module",
383
+ description: "Python package main entry point",
384
+ category: "entry-point",
385
+ match: (filepath, filename) => {
386
+ return filename === "__main__.py";
387
+ },
388
+ keywords: ["entry", "main", "python", "entrypoint", "cli"],
389
+ dynamicKeywords: (filepath) => {
390
+ const parent = getParentFolder(filepath);
391
+ if (["src", "lib", ".", ""].includes(parent)) {
392
+ return [];
393
+ }
394
+ return [parent.toLowerCase()];
395
+ }
396
+ },
397
+ {
398
+ id: "python-app",
399
+ name: "Python App Entry",
400
+ description: "Common Python application entry points",
401
+ category: "entry-point",
402
+ match: (filepath, filename) => {
403
+ return filename === "app.py" || filename === "main.py" || filename === "run.py";
404
+ },
405
+ keywords: ["entry", "main", "python", "app", "entrypoint"]
406
+ },
407
+ {
408
+ id: "python-manage",
409
+ name: "Django Manage",
410
+ description: "Django management script",
411
+ category: "entry-point",
412
+ match: (filepath, filename) => {
413
+ return filename === "manage.py";
414
+ },
415
+ keywords: ["entry", "django", "python", "manage", "cli", "admin"]
416
+ },
417
+ {
418
+ id: "python-wsgi",
419
+ name: "Python WSGI Entry",
420
+ description: "Python WSGI application entry point",
421
+ category: "entry-point",
422
+ match: (filepath, filename) => {
423
+ return filename === "wsgi.py" || filename === "asgi.py";
424
+ },
425
+ keywords: ["entry", "wsgi", "asgi", "python", "server", "web"]
426
+ }
427
+ ];
428
+ });
429
+
430
+ // src/domain/services/conventions/configFiles.ts
431
+ var configFileConventions;
432
+ var init_configFiles = __esm(() => {
433
+ configFileConventions = [
434
+ {
435
+ id: "package-json",
436
+ name: "Package.json",
437
+ description: "Node.js package manifest",
438
+ category: "configuration",
439
+ match: (filepath, filename) => filename === "package.json",
440
+ keywords: ["package", "dependencies", "npm", "scripts", "manifest", "node"]
441
+ },
442
+ {
443
+ id: "pnpm-workspace",
444
+ name: "PNPM Workspace",
445
+ description: "PNPM monorepo workspace configuration",
446
+ category: "configuration",
447
+ match: (filepath, filename) => filename === "pnpm-workspace.yaml" || filename === "pnpm-workspace.yml",
448
+ keywords: ["workspace", "monorepo", "pnpm", "packages"]
449
+ },
450
+ {
451
+ id: "yarn-lock",
452
+ name: "Yarn Lock",
453
+ description: "Yarn dependency lock file",
454
+ category: "configuration",
455
+ match: (filepath, filename) => filename === "yarn.lock",
456
+ keywords: ["dependencies", "lock", "yarn", "versions"]
457
+ },
458
+ {
459
+ id: "package-lock",
460
+ name: "Package Lock",
461
+ description: "NPM dependency lock file",
462
+ category: "configuration",
463
+ match: (filepath, filename) => filename === "package-lock.json",
464
+ keywords: ["dependencies", "lock", "npm", "versions"]
465
+ },
466
+ {
467
+ id: "bun-lockb",
468
+ name: "Bun Lock",
469
+ description: "Bun dependency lock file",
470
+ category: "configuration",
471
+ match: (filepath, filename) => filename === "bun.lockb" || filename === "bun.lock",
472
+ keywords: ["dependencies", "lock", "bun", "versions"]
473
+ },
474
+ {
475
+ id: "go-mod",
476
+ name: "Go Module",
477
+ description: "Go module definition file",
478
+ category: "configuration",
479
+ match: (filepath, filename) => filename === "go.mod",
480
+ keywords: [
481
+ "go",
482
+ "golang",
483
+ "module",
484
+ "dependencies",
485
+ "package",
486
+ "workspace"
487
+ ]
488
+ },
489
+ {
490
+ id: "go-sum",
491
+ name: "Go Sum",
492
+ description: "Go module checksum file",
493
+ category: "configuration",
494
+ match: (filepath, filename) => filename === "go.sum",
495
+ keywords: ["go", "golang", "dependencies", "checksum", "lock", "versions"]
496
+ },
497
+ {
498
+ id: "go-work",
499
+ name: "Go Workspace",
500
+ description: "Go workspace configuration for multi-module development",
501
+ category: "configuration",
502
+ match: (filepath, filename) => filename === "go.work" || filename === "go.work.sum",
503
+ keywords: ["go", "golang", "workspace", "monorepo", "modules"]
504
+ },
505
+ {
506
+ id: "makefile",
507
+ name: "Makefile",
508
+ description: "Make build automation file",
509
+ category: "build",
510
+ match: (filepath, filename) => filename === "Makefile" || filename === "makefile" || filename === "GNUmakefile",
511
+ keywords: ["make", "build", "automation", "tasks", "compile"]
512
+ },
513
+ {
514
+ id: "requirements-txt",
515
+ name: "Python Requirements",
516
+ description: "Python pip requirements file",
517
+ category: "configuration",
518
+ match: (filepath, filename) => filename === "requirements.txt" || filename.startsWith("requirements-") || filename.startsWith("requirements_"),
519
+ keywords: ["python", "pip", "dependencies", "packages", "requirements"]
520
+ },
521
+ {
522
+ id: "pyproject-toml",
523
+ name: "Python Project",
524
+ description: "Python project configuration (PEP 518/621)",
525
+ category: "configuration",
526
+ match: (filepath, filename) => filename === "pyproject.toml",
527
+ keywords: [
528
+ "python",
529
+ "project",
530
+ "config",
531
+ "poetry",
532
+ "build",
533
+ "dependencies",
534
+ "package"
535
+ ]
536
+ },
537
+ {
538
+ id: "setup-py",
539
+ name: "Python Setup",
540
+ description: "Python package setup script",
541
+ category: "configuration",
542
+ match: (filepath, filename) => filename === "setup.py",
543
+ keywords: ["python", "setup", "package", "install", "distribution"]
544
+ },
545
+ {
546
+ id: "setup-cfg",
547
+ name: "Python Setup Config",
548
+ description: "Python setup configuration file",
549
+ category: "configuration",
550
+ match: (filepath, filename) => filename === "setup.cfg",
551
+ keywords: ["python", "setup", "config", "package", "metadata"]
552
+ },
553
+ {
554
+ id: "pipfile",
555
+ name: "Pipfile",
556
+ description: "Pipenv dependency file",
557
+ category: "configuration",
558
+ match: (filepath, filename) => filename === "Pipfile" || filename === "Pipfile.lock",
559
+ keywords: ["python", "pipenv", "dependencies", "packages", "virtualenv"]
560
+ },
561
+ {
562
+ id: "poetry-lock",
563
+ name: "Poetry Lock",
564
+ description: "Poetry dependency lock file",
565
+ category: "configuration",
566
+ match: (filepath, filename) => filename === "poetry.lock",
567
+ keywords: ["python", "poetry", "dependencies", "lock", "versions"]
568
+ },
569
+ {
570
+ id: "tox-ini",
571
+ name: "Tox Config",
572
+ description: "Tox testing automation configuration",
573
+ category: "test",
574
+ match: (filepath, filename) => filename === "tox.ini",
575
+ keywords: ["python", "tox", "testing", "automation", "environments"]
576
+ },
577
+ {
578
+ id: "pytest-ini",
579
+ name: "Pytest Config",
580
+ description: "Pytest configuration file",
581
+ category: "test",
582
+ match: (filepath, filename) => filename === "pytest.ini" || filename === "conftest.py",
583
+ keywords: ["python", "pytest", "testing", "test", "fixtures"]
584
+ },
585
+ {
586
+ id: "mypy-ini",
587
+ name: "Mypy Config",
588
+ description: "Mypy type checker configuration",
589
+ category: "configuration",
590
+ match: (filepath, filename) => filename === "mypy.ini" || filename === ".mypy.ini",
591
+ keywords: ["python", "mypy", "types", "type checking", "static analysis"]
592
+ },
593
+ {
594
+ id: "flake8",
595
+ name: "Flake8 Config",
596
+ description: "Flake8 linter configuration",
597
+ category: "configuration",
598
+ match: (filepath, filename) => filename === ".flake8",
599
+ keywords: ["python", "flake8", "linting", "lint", "style"]
600
+ },
601
+ {
602
+ id: "pylintrc",
603
+ name: "Pylint Config",
604
+ description: "Pylint linter configuration",
605
+ category: "configuration",
606
+ match: (filepath, filename) => filename === ".pylintrc" || filename === "pylintrc" || filename === "pylint.toml",
607
+ keywords: ["python", "pylint", "linting", "lint", "code quality"]
608
+ },
609
+ {
610
+ id: "ruff-toml",
611
+ name: "Ruff Config",
612
+ description: "Ruff linter/formatter configuration",
613
+ category: "configuration",
614
+ match: (filepath, filename) => filename === "ruff.toml" || filename === ".ruff.toml",
615
+ keywords: ["python", "ruff", "linting", "formatting", "fast"]
616
+ },
617
+ {
618
+ id: "black-toml",
619
+ name: "Black Config",
620
+ description: "Black formatter configuration",
621
+ category: "configuration",
622
+ match: (filepath, filename) => filename === ".black.toml",
623
+ keywords: ["python", "black", "formatting", "format", "style"]
624
+ },
625
+ {
626
+ id: "tsconfig",
627
+ name: "TypeScript Config",
628
+ description: "TypeScript compiler configuration",
629
+ category: "configuration",
630
+ match: (filepath, filename) => filename === "tsconfig.json" || filename.startsWith("tsconfig.") && filename.endsWith(".json"),
631
+ keywords: [
632
+ "typescript",
633
+ "config",
634
+ "compiler",
635
+ "ts",
636
+ "settings",
637
+ "paths",
638
+ "types"
639
+ ]
640
+ },
641
+ {
642
+ id: "jsconfig",
643
+ name: "JavaScript Config",
644
+ description: "JavaScript project configuration",
645
+ category: "configuration",
646
+ match: (filepath, filename) => filename === "jsconfig.json",
647
+ keywords: ["javascript", "config", "compiler", "js", "settings", "paths"]
648
+ },
649
+ {
650
+ id: "eslint-config",
651
+ name: "ESLint Config",
652
+ description: "ESLint linting configuration",
653
+ category: "configuration",
654
+ 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",
655
+ keywords: ["eslint", "linting", "lint", "rules", "code quality"]
656
+ },
657
+ {
658
+ id: "prettier-config",
659
+ name: "Prettier Config",
660
+ description: "Prettier code formatting configuration",
661
+ category: "configuration",
662
+ 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",
663
+ keywords: ["prettier", "formatting", "format", "code style", "style"]
664
+ },
665
+ {
666
+ id: "biome-config",
667
+ name: "Biome Config",
668
+ description: "Biome linting and formatting configuration",
669
+ category: "configuration",
670
+ match: (filepath, filename) => filename === "biome.json" || filename === "biome.jsonc",
671
+ keywords: ["biome", "linting", "formatting", "lint", "format"]
672
+ },
673
+ {
674
+ id: "vite-config",
675
+ name: "Vite Config",
676
+ description: "Vite build tool configuration",
677
+ category: "build",
678
+ match: (filepath, filename) => filename === "vite.config.ts" || filename === "vite.config.js" || filename === "vite.config.mjs",
679
+ keywords: ["vite", "bundler", "build", "dev server", "hmr"]
680
+ },
681
+ {
682
+ id: "webpack-config",
683
+ name: "Webpack Config",
684
+ description: "Webpack bundler configuration",
685
+ category: "build",
686
+ match: (filepath, filename) => filename === "webpack.config.js" || filename === "webpack.config.ts" || filename.startsWith("webpack.") && (filename.endsWith(".js") || filename.endsWith(".ts")),
687
+ keywords: ["webpack", "bundler", "build", "loaders", "plugins"]
688
+ },
689
+ {
690
+ id: "rollup-config",
691
+ name: "Rollup Config",
692
+ description: "Rollup bundler configuration",
693
+ category: "build",
694
+ match: (filepath, filename) => filename === "rollup.config.js" || filename === "rollup.config.ts" || filename === "rollup.config.mjs",
695
+ keywords: ["rollup", "bundler", "build", "esm", "bundle"]
696
+ },
697
+ {
698
+ id: "esbuild-config",
699
+ name: "esbuild Config",
700
+ description: "esbuild bundler configuration",
701
+ category: "build",
702
+ match: (filepath, filename) => filename === "esbuild.config.js" || filename === "esbuild.config.ts" || filename === "esbuild.config.mjs",
703
+ keywords: ["esbuild", "bundler", "build", "fast"]
704
+ },
705
+ {
706
+ id: "jest-config",
707
+ name: "Jest Config",
708
+ description: "Jest testing framework configuration",
709
+ category: "test",
710
+ match: (filepath, filename) => filename === "jest.config.js" || filename === "jest.config.ts" || filename === "jest.config.mjs" || filename === "jest.config.cjs" || filename === "jest.config.json",
711
+ keywords: ["jest", "testing", "test", "unit test", "config"]
712
+ },
713
+ {
714
+ id: "vitest-config",
715
+ name: "Vitest Config",
716
+ description: "Vitest testing framework configuration",
717
+ category: "test",
718
+ match: (filepath, filename) => filename === "vitest.config.ts" || filename === "vitest.config.js" || filename === "vitest.config.mts",
719
+ keywords: ["vitest", "testing", "test", "unit test", "config"]
720
+ },
721
+ {
722
+ id: "playwright-config",
723
+ name: "Playwright Config",
724
+ description: "Playwright E2E testing configuration",
725
+ category: "test",
726
+ match: (filepath, filename) => filename === "playwright.config.ts" || filename === "playwright.config.js",
727
+ keywords: ["playwright", "testing", "e2e", "end-to-end", "browser test"]
728
+ },
729
+ {
730
+ id: "cypress-config",
731
+ name: "Cypress Config",
732
+ description: "Cypress E2E testing configuration",
733
+ category: "test",
734
+ match: (filepath, filename) => filename === "cypress.config.ts" || filename === "cypress.config.js" || filename === "cypress.json",
735
+ keywords: ["cypress", "testing", "e2e", "end-to-end", "browser test"]
736
+ },
737
+ {
738
+ id: "tailwind-config",
739
+ name: "Tailwind Config",
740
+ description: "Tailwind CSS configuration",
741
+ category: "configuration",
742
+ match: (filepath, filename) => filename === "tailwind.config.js" || filename === "tailwind.config.ts" || filename === "tailwind.config.cjs" || filename === "tailwind.config.mjs",
743
+ keywords: ["tailwind", "css", "styling", "utility", "design"]
744
+ },
745
+ {
746
+ id: "postcss-config",
747
+ name: "PostCSS Config",
748
+ description: "PostCSS configuration",
749
+ category: "configuration",
750
+ match: (filepath, filename) => filename === "postcss.config.js" || filename === "postcss.config.cjs" || filename === "postcss.config.mjs" || filename === ".postcssrc" || filename === ".postcssrc.json",
751
+ keywords: ["postcss", "css", "styling", "transforms"]
752
+ },
753
+ {
754
+ id: "env-file",
755
+ name: "Environment File",
756
+ description: "Environment variables file",
757
+ category: "configuration",
758
+ match: (filepath, filename) => filename === ".env" || filename === ".env.local" || filename === ".env.development" || filename === ".env.production" || filename === ".env.test" || filename.startsWith(".env."),
759
+ keywords: ["environment", "env", "variables", "secrets", "config"]
760
+ },
761
+ {
762
+ id: "env-example",
763
+ name: "Environment Example",
764
+ description: "Example environment variables file",
765
+ category: "documentation",
766
+ match: (filepath, filename) => filename === ".env.example" || filename === ".env.sample" || filename === ".env.template",
767
+ keywords: ["environment", "env", "example", "template", "setup"]
768
+ },
769
+ {
770
+ id: "dockerfile",
771
+ name: "Dockerfile",
772
+ description: "Docker container image definition",
773
+ category: "deployment",
774
+ match: (filepath, filename) => filename === "Dockerfile" || filename.startsWith("Dockerfile."),
775
+ keywords: ["docker", "container", "image", "deployment", "build"]
776
+ },
777
+ {
778
+ id: "docker-compose",
779
+ name: "Docker Compose",
780
+ description: "Docker Compose multi-container configuration",
781
+ category: "deployment",
782
+ match: (filepath, filename) => filename === "docker-compose.yml" || filename === "docker-compose.yaml" || filename === "compose.yml" || filename === "compose.yaml" || filename.startsWith("docker-compose."),
783
+ keywords: ["docker", "compose", "containers", "services", "deployment"]
784
+ },
785
+ {
786
+ id: "github-actions",
787
+ name: "GitHub Actions Workflow",
788
+ description: "GitHub Actions CI/CD workflow",
789
+ category: "deployment",
790
+ match: (filepath) => filepath.includes(".github/workflows/") && filepath.endsWith(".yml"),
791
+ keywords: ["github", "actions", "ci", "cd", "workflow", "automation"]
792
+ },
793
+ {
794
+ id: "vercel-config",
795
+ name: "Vercel Config",
796
+ description: "Vercel deployment configuration",
797
+ category: "deployment",
798
+ match: (filepath, filename) => filename === "vercel.json",
799
+ keywords: ["vercel", "deployment", "hosting", "serverless"]
800
+ },
801
+ {
802
+ id: "netlify-config",
803
+ name: "Netlify Config",
804
+ description: "Netlify deployment configuration",
805
+ category: "deployment",
806
+ match: (filepath, filename) => filename === "netlify.toml",
807
+ keywords: ["netlify", "deployment", "hosting", "functions"]
808
+ },
809
+ {
810
+ id: "gitignore",
811
+ name: "Git Ignore",
812
+ description: "Git ignored files configuration",
813
+ category: "configuration",
814
+ match: (filepath, filename) => filename === ".gitignore",
815
+ keywords: ["git", "ignore", "version control", "excluded"]
816
+ },
817
+ {
818
+ id: "gitattributes",
819
+ name: "Git Attributes",
820
+ description: "Git file attributes configuration",
821
+ category: "configuration",
822
+ match: (filepath, filename) => filename === ".gitattributes",
823
+ keywords: ["git", "attributes", "version control", "line endings"]
824
+ },
825
+ {
826
+ id: "readme",
827
+ name: "README",
828
+ description: "Project documentation",
829
+ category: "documentation",
830
+ match: (filepath, filename) => filename.toLowerCase() === "readme.md" || filename.toLowerCase() === "readme",
831
+ keywords: [
832
+ "readme",
833
+ "documentation",
834
+ "docs",
835
+ "overview",
836
+ "getting started"
837
+ ]
838
+ },
839
+ {
840
+ id: "changelog",
841
+ name: "Changelog",
842
+ description: "Project changelog",
843
+ category: "documentation",
844
+ match: (filepath, filename) => filename.toLowerCase() === "changelog.md" || filename.toLowerCase() === "changelog",
845
+ keywords: ["changelog", "changes", "releases", "history", "versions"]
846
+ },
847
+ {
848
+ id: "contributing",
849
+ name: "Contributing Guide",
850
+ description: "Contribution guidelines",
851
+ category: "documentation",
852
+ match: (filepath, filename) => filename.toLowerCase() === "contributing.md" || filename.toLowerCase() === "contributing",
853
+ keywords: ["contributing", "contribution", "guidelines", "development"]
854
+ },
855
+ {
856
+ id: "license",
857
+ name: "License",
858
+ description: "Project license",
859
+ category: "documentation",
860
+ match: (filepath, filename) => filename.toLowerCase() === "license" || filename.toLowerCase() === "license.md" || filename.toLowerCase() === "license.txt",
861
+ keywords: ["license", "legal", "copyright", "terms"]
862
+ }
863
+ ];
864
+ });
865
+
866
+ // src/domain/services/conventions/frameworks/nextjs.ts
867
+ var nextjsConventions, nextjsFramework;
868
+ var init_nextjs = __esm(() => {
869
+ nextjsConventions = [
870
+ {
871
+ id: "next-config",
872
+ name: "Next.js Config",
873
+ description: "Next.js framework configuration",
874
+ category: "configuration",
875
+ match: (filepath, filename) => filename === "next.config.js" || filename === "next.config.mjs" || filename === "next.config.ts",
876
+ keywords: ["nextjs", "next", "config", "framework", "settings"]
877
+ },
878
+ {
879
+ id: "next-env",
880
+ name: "Next.js Environment Types",
881
+ description: "Next.js TypeScript environment declarations",
882
+ category: "types",
883
+ match: (filepath, filename) => filename === "next-env.d.ts",
884
+ keywords: ["nextjs", "types", "typescript", "declarations"]
885
+ },
886
+ {
887
+ id: "next-layout",
888
+ name: "Next.js Layout",
889
+ description: "Next.js layout component (App Router)",
890
+ category: "framework",
891
+ match: (filepath, filename) => (filename === "layout.tsx" || filename === "layout.js") && (filepath.includes("/app/") || filepath.startsWith("app/")),
892
+ keywords: ["nextjs", "layout", "wrapper", "template", "app router"],
893
+ dynamicKeywords: (filepath) => {
894
+ const match = filepath.match(/app\/(.+?)\/layout\./);
895
+ if (match) {
896
+ const segments = match[1].split("/").filter((s) => !s.startsWith("(") && !s.startsWith("["));
897
+ return segments.map((s) => s.toLowerCase());
898
+ }
899
+ if (filepath === "app/layout.tsx" || filepath === "app/layout.js") {
900
+ return ["root", "main"];
901
+ }
902
+ return [];
903
+ }
904
+ },
905
+ {
906
+ id: "next-page",
907
+ name: "Next.js Page",
908
+ description: "Next.js page component (App Router)",
909
+ category: "framework",
910
+ match: (filepath, filename) => (filename === "page.tsx" || filename === "page.js") && (filepath.includes("/app/") || filepath.startsWith("app/")),
911
+ keywords: ["nextjs", "page", "route", "view", "app router"],
912
+ dynamicKeywords: (filepath) => {
913
+ const match = filepath.match(/app\/(.+?)\/page\./);
914
+ if (match) {
915
+ const segments = match[1].split("/").filter((s) => !s.startsWith("(")).map((s) => s.replace(/^\[(.+?)\]$/, "$1"));
916
+ return segments.map((s) => s.toLowerCase());
917
+ }
918
+ if (filepath === "app/page.tsx" || filepath === "app/page.js") {
919
+ return ["home", "index", "root"];
920
+ }
921
+ return [];
922
+ }
923
+ },
924
+ {
925
+ id: "next-loading",
926
+ name: "Next.js Loading",
927
+ description: "Next.js loading UI component",
928
+ category: "framework",
929
+ match: (filepath, filename) => (filename === "loading.tsx" || filename === "loading.js") && (filepath.includes("/app/") || filepath.startsWith("app/")),
930
+ keywords: ["nextjs", "loading", "suspense", "skeleton", "spinner"]
931
+ },
932
+ {
933
+ id: "next-error",
934
+ name: "Next.js Error",
935
+ description: "Next.js error boundary component",
936
+ category: "framework",
937
+ match: (filepath, filename) => (filename === "error.tsx" || filename === "error.js") && (filepath.includes("/app/") || filepath.startsWith("app/")),
938
+ keywords: ["nextjs", "error", "boundary", "fallback", "catch"]
939
+ },
940
+ {
941
+ id: "next-not-found",
942
+ name: "Next.js Not Found",
943
+ description: "Next.js 404 page component",
944
+ category: "framework",
945
+ match: (filepath, filename) => (filename === "not-found.tsx" || filename === "not-found.js") && (filepath.includes("/app/") || filepath.startsWith("app/")),
946
+ keywords: ["nextjs", "404", "not found", "missing", "error"]
947
+ },
948
+ {
949
+ id: "next-template",
950
+ name: "Next.js Template",
951
+ description: "Next.js template component",
952
+ category: "framework",
953
+ match: (filepath, filename) => (filename === "template.tsx" || filename === "template.js") && (filepath.includes("/app/") || filepath.startsWith("app/")),
954
+ keywords: ["nextjs", "template", "wrapper", "app router"]
955
+ },
956
+ {
957
+ id: "next-route-handler",
958
+ name: "Next.js Route Handler",
959
+ description: "Next.js API route handler (App Router)",
960
+ category: "framework",
961
+ match: (filepath, filename) => (filename === "route.ts" || filename === "route.js") && (filepath.includes("/app/") || filepath.startsWith("app/")),
962
+ keywords: ["nextjs", "api", "route", "handler", "endpoint", "rest"],
963
+ dynamicKeywords: (filepath) => {
964
+ const match = filepath.match(/app\/api\/(.+?)\/route\./);
965
+ if (match) {
966
+ const segments = match[1].split("/").filter((s) => !s.startsWith("(")).map((s) => s.replace(/^\[(.+?)\]$/, "$1"));
967
+ return ["api", ...segments.map((s) => s.toLowerCase())];
968
+ }
969
+ return ["api"];
970
+ }
971
+ },
972
+ {
973
+ id: "next-middleware",
974
+ name: "Next.js Middleware",
975
+ description: "Next.js edge middleware",
976
+ category: "framework",
977
+ match: (filepath, filename) => filename === "middleware.ts" || filename === "middleware.js",
978
+ keywords: ["nextjs", "middleware", "edge", "request", "interceptor"]
979
+ },
980
+ {
981
+ id: "next-global-error",
982
+ name: "Next.js Global Error",
983
+ description: "Next.js global error handler",
984
+ category: "framework",
985
+ match: (filepath, filename) => filename === "global-error.tsx" || filename === "global-error.js",
986
+ keywords: ["nextjs", "error", "global", "boundary", "catch"]
987
+ },
988
+ {
989
+ id: "next-pages-api",
990
+ name: "Next.js API Route (Pages)",
991
+ description: "Next.js API route (Pages Router)",
992
+ category: "framework",
993
+ match: (filepath) => filepath.includes("/pages/api/") || filepath.startsWith("pages/api/"),
994
+ keywords: ["nextjs", "api", "route", "handler", "endpoint", "pages router"],
995
+ dynamicKeywords: (filepath) => {
996
+ const match = filepath.match(/pages\/api\/(.+?)\.(ts|js)/);
997
+ if (match) {
998
+ const segments = match[1].split("/").map((s) => s.replace(/^\[(.+?)\]$/, "$1"));
999
+ return ["api", ...segments.map((s) => s.toLowerCase())];
1000
+ }
1001
+ return ["api"];
1002
+ }
1003
+ },
1004
+ {
1005
+ id: "next-pages-document",
1006
+ name: "Next.js Document",
1007
+ description: "Next.js custom document (Pages Router)",
1008
+ category: "framework",
1009
+ match: (filepath, filename) => (filename === "_document.tsx" || filename === "_document.js") && (filepath.includes("/pages/") || filepath.startsWith("pages/")),
1010
+ keywords: ["nextjs", "document", "html", "head", "body", "pages router"]
1011
+ },
1012
+ {
1013
+ id: "next-pages-app",
1014
+ name: "Next.js App (Pages)",
1015
+ description: "Next.js custom app (Pages Router)",
1016
+ category: "framework",
1017
+ match: (filepath, filename) => (filename === "_app.tsx" || filename === "_app.js") && (filepath.includes("/pages/") || filepath.startsWith("pages/")),
1018
+ keywords: ["nextjs", "app", "wrapper", "provider", "pages router"]
1019
+ }
1020
+ ];
1021
+ nextjsFramework = {
1022
+ id: "nextjs",
1023
+ name: "Next.js",
1024
+ detect: (filepath) => {
1025
+ return filepath === "next.config.js" || filepath === "next.config.mjs" || filepath === "next.config.ts" || filepath.includes("/app/page.") || filepath.includes("/pages/_app.");
1026
+ },
1027
+ conventions: nextjsConventions
1028
+ };
1029
+ });
1030
+
1031
+ // src/domain/services/conventions/frameworks/convex.ts
1032
+ var convexConventions, convexFramework;
1033
+ var init_convex = __esm(() => {
1034
+ convexConventions = [
1035
+ {
1036
+ id: "convex-config",
1037
+ name: "Convex Config",
1038
+ description: "Convex project configuration",
1039
+ category: "configuration",
1040
+ match: (filepath, filename) => filename === "convex.json",
1041
+ keywords: ["convex", "config", "backend", "settings"]
1042
+ },
1043
+ {
1044
+ id: "convex-schema",
1045
+ name: "Convex Schema",
1046
+ description: "Convex database schema definition",
1047
+ category: "framework",
1048
+ match: (filepath, filename) => filename === "schema.ts" && (filepath.includes("/convex/") || filepath.startsWith("convex/")),
1049
+ keywords: ["convex", "schema", "database", "tables", "types", "model"]
1050
+ },
1051
+ {
1052
+ id: "convex-function",
1053
+ name: "Convex Function File",
1054
+ description: "Convex backend function file",
1055
+ category: "framework",
1056
+ match: (filepath, filename, extension) => (extension === ".ts" || extension === ".js") && (filepath.includes("/convex/") || filepath.startsWith("convex/")) && !filepath.includes("/_generated/") && filename !== "schema.ts" && !filename.startsWith("_"),
1057
+ keywords: ["convex", "function", "backend", "query", "mutation", "action"],
1058
+ dynamicKeywords: (filepath) => {
1059
+ const match = filepath.match(/convex\/(.+?)\.(ts|js)/);
1060
+ if (match) {
1061
+ const name = match[1].replace(/\//g, " ").split(" ").pop() || "";
1062
+ if (name && !["schema", "http", "crons"].includes(name)) {
1063
+ return [name.toLowerCase()];
1064
+ }
1065
+ }
1066
+ return [];
1067
+ }
1068
+ },
1069
+ {
1070
+ id: "convex-http",
1071
+ name: "Convex HTTP Routes",
1072
+ description: "Convex HTTP endpoint definitions",
1073
+ category: "framework",
1074
+ match: (filepath, filename) => filename === "http.ts" && (filepath.includes("/convex/") || filepath.startsWith("convex/")),
1075
+ keywords: ["convex", "http", "routes", "api", "endpoints", "rest"]
1076
+ },
1077
+ {
1078
+ id: "convex-crons",
1079
+ name: "Convex Cron Jobs",
1080
+ description: "Convex scheduled function definitions",
1081
+ category: "framework",
1082
+ match: (filepath, filename) => filename === "crons.ts" && (filepath.includes("/convex/") || filepath.startsWith("convex/")),
1083
+ keywords: [
1084
+ "convex",
1085
+ "crons",
1086
+ "scheduled",
1087
+ "jobs",
1088
+ "background",
1089
+ "recurring"
1090
+ ]
1091
+ },
1092
+ {
1093
+ id: "convex-generated",
1094
+ name: "Convex Generated",
1095
+ description: "Convex auto-generated files",
1096
+ category: "framework",
1097
+ match: (filepath) => filepath.includes("/convex/_generated/") || filepath.startsWith("convex/_generated/"),
1098
+ keywords: ["convex", "generated", "types", "api"]
1099
+ },
1100
+ {
1101
+ id: "convex-auth",
1102
+ name: "Convex Auth",
1103
+ description: "Convex authentication configuration",
1104
+ category: "framework",
1105
+ match: (filepath, filename) => filename === "auth.ts" && (filepath.includes("/convex/") || filepath.startsWith("convex/")),
1106
+ keywords: ["convex", "auth", "authentication", "login", "users"]
1107
+ },
1108
+ {
1109
+ id: "convex-auth-config",
1110
+ name: "Convex Auth Config",
1111
+ description: "Convex auth configuration file",
1112
+ category: "configuration",
1113
+ match: (filepath, filename) => filename === "auth.config.ts",
1114
+ keywords: ["convex", "auth", "config", "providers", "oauth"]
1115
+ }
1116
+ ];
1117
+ convexFramework = {
1118
+ id: "convex",
1119
+ name: "Convex",
1120
+ detect: (filepath) => {
1121
+ return filepath === "convex.json" || filepath.startsWith("convex/") || filepath.includes("/convex/");
1122
+ },
1123
+ conventions: convexConventions
1124
+ };
1125
+ });
1126
+
1127
+ // src/domain/services/conventions/frameworks/index.ts
1128
+ function getAllFrameworkConventions() {
1129
+ return frameworkProviders.flatMap((f) => f.conventions);
1130
+ }
1131
+ var frameworkProviders;
1132
+ var init_frameworks = __esm(() => {
1133
+ init_nextjs();
1134
+ init_convex();
1135
+ init_nextjs();
1136
+ init_convex();
1137
+ frameworkProviders = [
1138
+ nextjsFramework,
1139
+ convexFramework
1140
+ ];
1141
+ });
1142
+
1143
+ // src/domain/services/conventions/index.ts
1144
+ import * as path3 from "path";
1145
+ function getConventions() {
1146
+ return [
1147
+ ...entryPointConventions,
1148
+ ...configFileConventions,
1149
+ ...getAllFrameworkConventions(),
1150
+ ...typeDefinitionConventions,
1151
+ ...testFileConventions
1152
+ ];
1153
+ }
1154
+ function getConventionKeywords(filepath) {
1155
+ const conventions = getConventions();
1156
+ const filename = path3.basename(filepath);
1157
+ const extension = path3.extname(filepath);
1158
+ const keywords = new Set;
1159
+ for (const convention of conventions) {
1160
+ try {
1161
+ if (convention.match(filepath, filename, extension)) {
1162
+ for (const keyword of convention.keywords) {
1163
+ keywords.add(keyword.toLowerCase());
1164
+ }
1165
+ if (convention.dynamicKeywords) {
1166
+ const dynamicKws = convention.dynamicKeywords(filepath);
1167
+ for (const kw of dynamicKws) {
1168
+ if (kw && kw.length > 1) {
1169
+ keywords.add(kw.toLowerCase());
1170
+ }
1171
+ }
1172
+ }
1173
+ }
1174
+ } catch {}
1175
+ }
1176
+ return Array.from(keywords);
1177
+ }
1178
+ var typeDefinitionConventions, testFileConventions;
1179
+ var init_conventions = __esm(() => {
1180
+ init_entryPoints();
1181
+ init_configFiles();
1182
+ init_frameworks();
1183
+ init_entryPoints();
1184
+ init_configFiles();
1185
+ init_frameworks();
1186
+ typeDefinitionConventions = [
1187
+ {
1188
+ id: "dts-file",
1189
+ name: "TypeScript Declaration",
1190
+ description: "TypeScript type declaration file",
1191
+ category: "types",
1192
+ match: (filepath, filename) => filename.endsWith(".d.ts"),
1193
+ keywords: ["types", "declarations", "typescript", "definitions"]
1194
+ },
1195
+ {
1196
+ id: "types-file",
1197
+ name: "Types File",
1198
+ description: "TypeScript types file",
1199
+ category: "types",
1200
+ match: (filepath, filename) => filename.endsWith(".types.ts") || filename === "types.ts",
1201
+ keywords: ["types", "definitions", "typescript", "interfaces"],
1202
+ dynamicKeywords: (filepath) => {
1203
+ const match = filepath.match(/([^/]+)\.types\.ts$/);
1204
+ if (match)
1205
+ return [match[1].toLowerCase()];
1206
+ return [];
1207
+ }
1208
+ },
1209
+ {
1210
+ id: "types-folder",
1211
+ name: "Types Folder File",
1212
+ description: "File in a types folder",
1213
+ category: "types",
1214
+ match: (filepath) => filepath.includes("/types/") || filepath.startsWith("types/"),
1215
+ keywords: ["types", "definitions"]
1216
+ }
1217
+ ];
1218
+ testFileConventions = [
1219
+ {
1220
+ id: "test-file",
1221
+ name: "Test File",
1222
+ description: "Unit/integration test file",
1223
+ category: "test",
1224
+ match: (filepath, filename) => filename.includes(".test.") || filename.includes(".spec.") || filename.includes("_test."),
1225
+ keywords: ["test", "spec", "unit test"],
1226
+ dynamicKeywords: (filepath) => {
1227
+ const match = filepath.match(/([^/]+)\.(test|spec)\./);
1228
+ if (match)
1229
+ return [match[1].toLowerCase()];
1230
+ return [];
1231
+ }
1232
+ },
1233
+ {
1234
+ id: "test-folder",
1235
+ name: "Test Folder File",
1236
+ description: "File in a test folder",
1237
+ category: "test",
1238
+ match: (filepath) => filepath.includes("/__tests__/") || filepath.includes("/test/") || filepath.includes("/tests/") || filepath.startsWith("__tests__/") || filepath.startsWith("test/") || filepath.startsWith("tests/"),
1239
+ keywords: ["test", "testing"]
1240
+ }
1241
+ ];
1242
+ });
1243
+
1244
+ // src/domain/services/introspection.ts
1245
+ import * as path4 from "path";
1246
+ function introspectFile(filepath, structure, fileContent) {
1247
+ const normalizedPath = filepath.replace(/\\/g, "/");
1248
+ const segments = normalizedPath.split("/").filter((s) => s.length > 0);
1249
+ const filename = segments[segments.length - 1] || "";
1250
+ const ext = path4.extname(filename);
1251
+ const project = findProjectForFile(normalizedPath, structure);
1252
+ const language = EXTENSION_TO_LANGUAGE[ext] || "unknown";
1253
+ const layer = detectLayer(segments, filename);
1254
+ const domain = detectDomain(segments);
1255
+ const scope = detectScope(segments, project, layer);
1256
+ const framework = fileContent ? detectFramework(fileContent) : undefined;
1257
+ return {
1258
+ filepath: normalizedPath,
1259
+ project,
1260
+ scope,
1261
+ layer,
1262
+ domain,
1263
+ language,
1264
+ framework,
1265
+ depth: segments.length - 1,
1266
+ pathSegments: segments.slice(0, -1)
1267
+ };
1268
+ }
1269
+ function introspectionToKeywords(intro) {
1270
+ const keywords = [];
1271
+ const filename = path4.basename(intro.filepath);
1272
+ const filenameWithoutExt = filename.replace(/\.[^.]+$/, "");
1273
+ const filenameParts = filenameWithoutExt.split(/[-_.]/).flatMap((part) => part.split(/(?=[A-Z])/)).map((part) => part.toLowerCase()).filter((part) => part.length > 1);
1274
+ keywords.push(...filenameParts);
1275
+ keywords.push(filenameWithoutExt.toLowerCase());
1276
+ if (intro.project.name && intro.project.name !== "root") {
1277
+ keywords.push(intro.project.name.toLowerCase());
1278
+ }
1279
+ if (intro.scope !== "unknown")
1280
+ keywords.push(intro.scope);
1281
+ if (intro.layer)
1282
+ keywords.push(intro.layer);
1283
+ if (intro.domain)
1284
+ keywords.push(intro.domain);
1285
+ if (intro.language !== "unknown")
1286
+ keywords.push(intro.language);
1287
+ if (intro.framework)
1288
+ keywords.push(intro.framework);
1289
+ const skipSegments = new Set(["src", "lib", "index"]);
1290
+ for (const segment of intro.pathSegments) {
1291
+ if (!skipSegments.has(segment.toLowerCase()) && segment.length > 2) {
1292
+ keywords.push(segment.toLowerCase());
1293
+ }
1294
+ }
1295
+ const conventionKeywords = getConventionKeywords(intro.filepath);
1296
+ keywords.push(...conventionKeywords);
1297
+ return [...new Set(keywords)];
1298
+ }
1299
+ function detectScopeFromName(name) {
1300
+ const nameLower = name.toLowerCase();
1301
+ for (const [scope, keywords] of Object.entries(SCOPE_KEYWORDS)) {
1302
+ if (scope === "unknown")
1303
+ continue;
1304
+ for (const keyword of keywords) {
1305
+ if (nameLower.includes(keyword)) {
1306
+ return scope;
1307
+ }
1308
+ }
1309
+ }
1310
+ return "unknown";
1311
+ }
1312
+ function findProjectForFile(filepath, structure) {
1313
+ const normalizedPath = filepath.replace(/\\/g, "/");
1314
+ const matches = [];
1315
+ for (const project of structure.projects) {
1316
+ if (normalizedPath === project.root || normalizedPath.startsWith(project.root + "/")) {
1317
+ matches.push(project);
1318
+ }
1319
+ }
1320
+ if (matches.length > 0) {
1321
+ return matches.reduce((best, current) => current.root.length > best.root.length ? current : best);
1322
+ }
1323
+ for (const { pattern, type } of PROJECT_PATTERNS) {
1324
+ const match = normalizedPath.match(pattern);
1325
+ if (match) {
1326
+ return { name: match[1], root: match[0], type };
1327
+ }
1328
+ }
1329
+ return { name: "root", root: "", type: structure.rootType ?? "unknown" };
1330
+ }
1331
+ function detectLayer(segments, filename) {
1332
+ const filenameLower = filename.toLowerCase();
1333
+ for (const [layer, patterns] of Object.entries(LAYER_PATTERNS)) {
1334
+ for (const pattern of patterns) {
1335
+ if (filenameLower.includes(pattern))
1336
+ return layer;
1337
+ }
1338
+ }
1339
+ for (let i = segments.length - 2;i >= 0; i--) {
1340
+ const segment = segments[i].toLowerCase();
1341
+ for (const [layer, patterns] of Object.entries(LAYER_PATTERNS)) {
1342
+ if (patterns.includes(segment))
1343
+ return layer;
1344
+ }
1345
+ }
1346
+ return;
1347
+ }
1348
+ function detectDomain(segments) {
1349
+ const skipSegments = new Set([
1350
+ "src",
1351
+ "lib",
1352
+ "app",
1353
+ "apps",
1354
+ "packages",
1355
+ "services",
1356
+ "modules",
1357
+ "features",
1358
+ ...Object.values(LAYER_PATTERNS).flat()
1359
+ ]);
1360
+ for (const segment of segments) {
1361
+ const segmentLower = segment.toLowerCase();
1362
+ if (skipSegments.has(segmentLower))
1363
+ continue;
1364
+ if (DOMAIN_PATTERNS.includes(segmentLower))
1365
+ return segmentLower;
1366
+ for (const domain of DOMAIN_PATTERNS) {
1367
+ if (segmentLower.startsWith(domain) || segmentLower.endsWith(domain)) {
1368
+ return domain;
1369
+ }
1370
+ }
1371
+ }
1372
+ return;
1373
+ }
1374
+ function detectScope(segments, project, layer) {
1375
+ const projectScope = detectScopeFromName(project.name);
1376
+ if (projectScope !== "unknown")
1377
+ return projectScope;
1378
+ if (layer) {
1379
+ switch (layer) {
1380
+ case "controller":
1381
+ case "repository":
1382
+ case "middleware":
1383
+ return "backend";
1384
+ case "presentation":
1385
+ return "frontend";
1386
+ case "util":
1387
+ case "model":
1388
+ return "shared";
1389
+ case "test":
1390
+ return "tooling";
242
1391
  }
243
- return index;
244
1392
  }
1393
+ for (const segment of segments) {
1394
+ const segmentLower = segment.toLowerCase();
1395
+ if (["server", "api", "backend"].includes(segmentLower))
1396
+ return "backend";
1397
+ if (["client", "web", "frontend", "ui"].includes(segmentLower))
1398
+ return "frontend";
1399
+ if (["shared", "common", "lib", "libs"].includes(segmentLower))
1400
+ return "shared";
1401
+ }
1402
+ return "unknown";
245
1403
  }
246
- function normalizeScore(score, midpoint = 5) {
247
- return 1 / (1 + Math.exp(-score / midpoint + 1));
1404
+ function detectFramework(content) {
1405
+ for (const [framework, indicators] of Object.entries(FRAMEWORK_INDICATORS)) {
1406
+ for (const indicator of indicators) {
1407
+ if (content.includes(`from '${indicator}`) || content.includes(`from "${indicator}`) || content.includes(`require('${indicator}`) || content.includes(`require("${indicator}`)) {
1408
+ return framework;
1409
+ }
1410
+ }
1411
+ }
1412
+ return;
248
1413
  }
249
- var BM25_K1 = 1.5, BM25_B = 0.75;
1414
+ var LAYER_PATTERNS, DOMAIN_PATTERNS, FRAMEWORK_INDICATORS, EXTENSION_TO_LANGUAGE, SCOPE_KEYWORDS, PROJECT_PATTERNS;
1415
+ var init_introspection = __esm(() => {
1416
+ init_conventions();
1417
+ LAYER_PATTERNS = {
1418
+ controller: ["controller", "api", "routes", "route", "handler"],
1419
+ service: ["service", "logic", "usecase", "usecases", "handler"],
1420
+ repository: ["repository", "repo", "dao", "store", "persistence"],
1421
+ model: [
1422
+ "model",
1423
+ "models",
1424
+ "entity",
1425
+ "entities",
1426
+ "schema",
1427
+ "schemas",
1428
+ "types",
1429
+ "type"
1430
+ ],
1431
+ util: ["util", "utils", "helper", "helpers", "common", "lib"],
1432
+ config: ["config", "configuration", "settings"],
1433
+ middleware: ["middleware", "middlewares"],
1434
+ domain: ["domain"],
1435
+ infrastructure: ["infrastructure", "infra"],
1436
+ application: ["application", "app"],
1437
+ presentation: [
1438
+ "presentation",
1439
+ "ui",
1440
+ "views",
1441
+ "view",
1442
+ "component",
1443
+ "components"
1444
+ ],
1445
+ test: ["test", "tests", "spec", "specs", "__tests__", "e2e"]
1446
+ };
1447
+ DOMAIN_PATTERNS = [
1448
+ "auth",
1449
+ "authentication",
1450
+ "user",
1451
+ "users",
1452
+ "account",
1453
+ "accounts",
1454
+ "profile",
1455
+ "profiles",
1456
+ "product",
1457
+ "products",
1458
+ "item",
1459
+ "items",
1460
+ "catalog",
1461
+ "order",
1462
+ "orders",
1463
+ "cart",
1464
+ "checkout",
1465
+ "payment",
1466
+ "payments",
1467
+ "billing",
1468
+ "subscription",
1469
+ "subscriptions",
1470
+ "notification",
1471
+ "notifications",
1472
+ "email",
1473
+ "sms",
1474
+ "report",
1475
+ "reports",
1476
+ "analytics",
1477
+ "metrics",
1478
+ "dashboard",
1479
+ "admin",
1480
+ "settings",
1481
+ "search",
1482
+ "chat",
1483
+ "message",
1484
+ "messages",
1485
+ "feed",
1486
+ "post",
1487
+ "posts",
1488
+ "comment",
1489
+ "comments",
1490
+ "media",
1491
+ "upload",
1492
+ "file",
1493
+ "files",
1494
+ "storage",
1495
+ "cache",
1496
+ "session",
1497
+ "log",
1498
+ "logs",
1499
+ "audit"
1500
+ ];
1501
+ FRAMEWORK_INDICATORS = {
1502
+ nextjs: ["next", "next/"],
1503
+ express: ["express"],
1504
+ fastify: ["fastify"],
1505
+ react: ["react"],
1506
+ vue: ["vue"],
1507
+ angular: ["@angular/"],
1508
+ nestjs: ["@nestjs/"],
1509
+ koa: ["koa"]
1510
+ };
1511
+ EXTENSION_TO_LANGUAGE = {
1512
+ ".ts": "typescript",
1513
+ ".tsx": "typescript",
1514
+ ".js": "javascript",
1515
+ ".jsx": "javascript",
1516
+ ".mjs": "javascript",
1517
+ ".cjs": "javascript",
1518
+ ".py": "python",
1519
+ ".go": "go",
1520
+ ".rs": "rust",
1521
+ ".java": "java",
1522
+ ".kt": "kotlin",
1523
+ ".swift": "swift",
1524
+ ".rb": "ruby",
1525
+ ".php": "php",
1526
+ ".cs": "csharp",
1527
+ ".cpp": "cpp",
1528
+ ".c": "c",
1529
+ ".h": "c",
1530
+ ".hpp": "cpp",
1531
+ ".md": "markdown",
1532
+ ".json": "json",
1533
+ ".yaml": "yaml",
1534
+ ".yml": "yaml",
1535
+ ".txt": "text"
1536
+ };
1537
+ SCOPE_KEYWORDS = {
1538
+ frontend: [
1539
+ "web",
1540
+ "webapp",
1541
+ "frontend",
1542
+ "client",
1543
+ "ui",
1544
+ "app",
1545
+ "mobile",
1546
+ "react",
1547
+ "vue",
1548
+ "angular",
1549
+ "next",
1550
+ "nuxt"
1551
+ ],
1552
+ backend: [
1553
+ "api",
1554
+ "server",
1555
+ "backend",
1556
+ "service",
1557
+ "worker",
1558
+ "lambda",
1559
+ "functions"
1560
+ ],
1561
+ shared: ["shared", "common", "utils", "lib", "core", "types", "models"],
1562
+ tooling: ["scripts", "tools", "cli", "devtools", "build", "config", "infra"],
1563
+ unknown: []
1564
+ };
1565
+ PROJECT_PATTERNS = [
1566
+ { pattern: /^apps\/([^/]+)/, type: "app", defaultScope: "unknown" },
1567
+ { pattern: /^packages\/([^/]+)/, type: "library", defaultScope: "shared" },
1568
+ { pattern: /^libs\/([^/]+)/, type: "library", defaultScope: "shared" },
1569
+ { pattern: /^services\/([^/]+)/, type: "service", defaultScope: "backend" },
1570
+ { pattern: /^scripts\/([^/]+)/, type: "script", defaultScope: "tooling" },
1571
+ { pattern: /^tools\/([^/]+)/, type: "script", defaultScope: "tooling" }
1572
+ ];
1573
+ });
250
1574
 
251
1575
  // src/modules/core/symbols.ts
252
1576
  function extractSymbols(content) {
@@ -415,7 +1739,7 @@ var exports_core = {};
415
1739
  __export(exports_core, {
416
1740
  CoreModule: () => CoreModule
417
1741
  });
418
- import * as path2 from "path";
1742
+ import * as path5 from "path";
419
1743
  import * as fs2 from "fs/promises";
420
1744
 
421
1745
  class CoreModule {
@@ -432,7 +1756,11 @@ class CoreModule {
432
1756
  const symbols = extractSymbols(content);
433
1757
  const symbolKeywords = symbolsToKeywords(symbols);
434
1758
  const contentTokens = tokenize(content);
435
- const allTokens = [...new Set([...contentTokens, ...symbolKeywords])];
1759
+ const intro = ctx.getIntrospection?.(filepath);
1760
+ const introKeywords = intro ? introspectionToKeywords(intro) : [];
1761
+ const allTokens = [
1762
+ ...new Set([...contentTokens, ...symbolKeywords, ...introKeywords])
1763
+ ];
436
1764
  const chunks = this.createChunks(filepath, content, symbols);
437
1765
  const stats = await ctx.getFileStats(filepath);
438
1766
  this.symbolIndex.set(filepath, {
@@ -506,7 +1834,7 @@ class CoreModule {
506
1834
  }
507
1835
  async finalize(ctx) {
508
1836
  const config = ctx.config;
509
- const coreDir = path2.join(getRaggrepDir(ctx.rootDir, config), "index", "core");
1837
+ const coreDir = path5.join(getRaggrepDir(ctx.rootDir, config), "index", "core");
510
1838
  await fs2.mkdir(coreDir, { recursive: true });
511
1839
  this.bm25Index = new BM25Index;
512
1840
  for (const [filepath, entry] of this.symbolIndex) {
@@ -518,7 +1846,7 @@ class CoreModule {
518
1846
  files: Object.fromEntries(this.symbolIndex),
519
1847
  bm25Data: this.bm25Index.serialize()
520
1848
  };
521
- await fs2.writeFile(path2.join(coreDir, "symbols.json"), JSON.stringify(symbolIndexData, null, 2));
1849
+ await fs2.writeFile(path5.join(coreDir, "symbols.json"), JSON.stringify(symbolIndexData, null, 2));
522
1850
  console.log(` [Core] Symbol index built with ${this.symbolIndex.size} files`);
523
1851
  }
524
1852
  async search(query, ctx, options) {
@@ -615,8 +1943,8 @@ class CoreModule {
615
1943
  return bestChunk;
616
1944
  }
617
1945
  async loadSymbolIndex(rootDir, config) {
618
- const coreDir = path2.join(getRaggrepDir(rootDir, config), "index", "core");
619
- const symbolsPath = path2.join(coreDir, "symbols.json");
1946
+ const coreDir = path5.join(getRaggrepDir(rootDir, config), "index", "core");
1947
+ const symbolsPath = path5.join(coreDir, "symbols.json");
620
1948
  try {
621
1949
  const content = await fs2.readFile(symbolsPath, "utf-8");
622
1950
  const data = JSON.parse(content);
@@ -637,13 +1965,14 @@ class CoreModule {
637
1965
  var DEFAULT_MIN_SCORE = 0.1, DEFAULT_TOP_K = 20, LINES_PER_CHUNK = 50, CHUNK_OVERLAP = 10;
638
1966
  var init_core = __esm(() => {
639
1967
  init_config2();
1968
+ init_introspection();
640
1969
  init_symbols();
641
1970
  });
642
1971
 
643
1972
  // src/infrastructure/embeddings/transformersEmbedding.ts
644
1973
  import { pipeline, env } from "@xenova/transformers";
645
- import * as path3 from "path";
646
- import * as os from "os";
1974
+ import * as path6 from "path";
1975
+ import * as os2 from "os";
647
1976
 
648
1977
  class TransformersEmbeddingProvider {
649
1978
  pipeline = null;
@@ -775,7 +2104,7 @@ async function getEmbeddings(texts) {
775
2104
  }
776
2105
  var CACHE_DIR, EMBEDDING_MODELS2, EMBEDDING_DIMENSION = 384, BATCH_SIZE = 32, globalProvider = null, globalConfig;
777
2106
  var init_transformersEmbedding = __esm(() => {
778
- CACHE_DIR = path3.join(os.homedir(), ".cache", "raggrep", "models");
2107
+ CACHE_DIR = path6.join(os2.homedir(), ".cache", "raggrep", "models");
779
2108
  env.cacheDir = CACHE_DIR;
780
2109
  env.allowLocalModels = true;
781
2110
  EMBEDDING_MODELS2 = {
@@ -1060,7 +2389,7 @@ function parsePathContext(filepath) {
1060
2389
  let layer;
1061
2390
  const allLower = [...dirSegments, filename].map((s) => s.toLowerCase()).join(" ");
1062
2391
  const filenameLower = filename.toLowerCase();
1063
- for (const [layerName, patterns] of Object.entries(LAYER_PATTERNS)) {
2392
+ for (const [layerName, patterns] of Object.entries(LAYER_PATTERNS2)) {
1064
2393
  for (const pattern of patterns) {
1065
2394
  if (filenameLower.includes(pattern)) {
1066
2395
  layer = layerName;
@@ -1075,7 +2404,7 @@ function parsePathContext(filepath) {
1075
2404
  break;
1076
2405
  }
1077
2406
  let domain;
1078
- const layerPatternSet = new Set(Object.values(LAYER_PATTERNS).flat());
2407
+ const layerPatternSet = new Set(Object.values(LAYER_PATTERNS2).flat());
1079
2408
  const reversedSegments = [...dirSegments].reverse();
1080
2409
  for (const segment of reversedSegments) {
1081
2410
  const lower = segment.toLowerCase();
@@ -1113,7 +2442,7 @@ function formatPathContextForEmbedding(pathContext) {
1113
2442
  const unique = [...new Set(parts)];
1114
2443
  return `[${unique.join(" ")}]`;
1115
2444
  }
1116
- var COMMON_KEYWORDS, LAYER_PATTERNS;
2445
+ var COMMON_KEYWORDS, LAYER_PATTERNS2;
1117
2446
  var init_keywords = __esm(() => {
1118
2447
  COMMON_KEYWORDS = new Set([
1119
2448
  "const",
@@ -1183,7 +2512,7 @@ var init_keywords = __esm(() => {
1183
2512
  "has",
1184
2513
  "have"
1185
2514
  ]);
1186
- LAYER_PATTERNS = {
2515
+ LAYER_PATTERNS2 = {
1187
2516
  controller: ["controller", "controllers", "handler", "handlers", "route", "routes", "api"],
1188
2517
  service: ["service", "services", "usecase", "usecases", "application"],
1189
2518
  repository: ["repository", "repositories", "repo", "repos", "dao", "store", "storage"],
@@ -1200,7 +2529,7 @@ var init_keywords = __esm(() => {
1200
2529
 
1201
2530
  // src/infrastructure/storage/symbolicIndex.ts
1202
2531
  import * as fs3 from "fs/promises";
1203
- import * as path4 from "path";
2532
+ import * as path7 from "path";
1204
2533
 
1205
2534
  class SymbolicIndex {
1206
2535
  meta = null;
@@ -1209,7 +2538,7 @@ class SymbolicIndex {
1209
2538
  symbolicPath;
1210
2539
  moduleId;
1211
2540
  constructor(indexDir, moduleId) {
1212
- this.symbolicPath = path4.join(indexDir, "index", moduleId, "symbolic");
2541
+ this.symbolicPath = path7.join(indexDir, "index", moduleId, "symbolic");
1213
2542
  this.moduleId = moduleId;
1214
2543
  }
1215
2544
  async initialize() {
@@ -1270,16 +2599,16 @@ class SymbolicIndex {
1270
2599
  this.meta.lastUpdated = new Date().toISOString();
1271
2600
  this.meta.fileCount = this.fileSummaries.size;
1272
2601
  await fs3.mkdir(this.symbolicPath, { recursive: true });
1273
- const metaPath = path4.join(this.symbolicPath, "_meta.json");
2602
+ const metaPath = path7.join(this.symbolicPath, "_meta.json");
1274
2603
  await fs3.writeFile(metaPath, JSON.stringify(this.meta, null, 2));
1275
2604
  for (const [filepath, summary] of this.fileSummaries) {
1276
2605
  const summaryPath = this.getFileSummaryPath(filepath);
1277
- await fs3.mkdir(path4.dirname(summaryPath), { recursive: true });
2606
+ await fs3.mkdir(path7.dirname(summaryPath), { recursive: true });
1278
2607
  await fs3.writeFile(summaryPath, JSON.stringify(summary, null, 2));
1279
2608
  }
1280
2609
  }
1281
2610
  async load() {
1282
- const metaPath = path4.join(this.symbolicPath, "_meta.json");
2611
+ const metaPath = path7.join(this.symbolicPath, "_meta.json");
1283
2612
  const metaContent = await fs3.readFile(metaPath, "utf-8");
1284
2613
  this.meta = JSON.parse(metaContent);
1285
2614
  this.fileSummaries.clear();
@@ -1290,7 +2619,7 @@ class SymbolicIndex {
1290
2619
  try {
1291
2620
  const entries = await fs3.readdir(dir, { withFileTypes: true });
1292
2621
  for (const entry of entries) {
1293
- const fullPath = path4.join(dir, entry.name);
2622
+ const fullPath = path7.join(dir, entry.name);
1294
2623
  if (entry.isDirectory()) {
1295
2624
  await this.loadFileSummariesRecursive(fullPath);
1296
2625
  } else if (entry.name.endsWith(".json") && entry.name !== "_meta.json") {
@@ -1307,7 +2636,7 @@ class SymbolicIndex {
1307
2636
  }
1308
2637
  getFileSummaryPath(filepath) {
1309
2638
  const jsonPath = filepath.replace(/\.[^.]+$/, ".json");
1310
- return path4.join(this.symbolicPath, jsonPath);
2639
+ return path7.join(this.symbolicPath, jsonPath);
1311
2640
  }
1312
2641
  async deleteFileSummary(filepath) {
1313
2642
  try {
@@ -1317,7 +2646,7 @@ class SymbolicIndex {
1317
2646
  }
1318
2647
  async exists() {
1319
2648
  try {
1320
- const metaPath = path4.join(this.symbolicPath, "_meta.json");
2649
+ const metaPath = path7.join(this.symbolicPath, "_meta.json");
1321
2650
  await fs3.access(metaPath);
1322
2651
  return true;
1323
2652
  } catch {
@@ -1357,7 +2686,7 @@ __export(exports_typescript, {
1357
2686
  DEFAULT_TOP_K: () => DEFAULT_TOP_K2,
1358
2687
  DEFAULT_MIN_SCORE: () => DEFAULT_MIN_SCORE2
1359
2688
  });
1360
- import * as path5 from "path";
2689
+ import * as path8 from "path";
1361
2690
 
1362
2691
  class TypeScriptModule {
1363
2692
  id = "language/typescript";
@@ -1551,16 +2880,16 @@ class TypeScriptModule {
1551
2880
  while ((match = importRegex.exec(content)) !== null) {
1552
2881
  const importPath = match[1];
1553
2882
  if (importPath.startsWith(".")) {
1554
- const dir = path5.dirname(filepath);
1555
- const resolved = path5.normalize(path5.join(dir, importPath));
2883
+ const dir = path8.dirname(filepath);
2884
+ const resolved = path8.normalize(path8.join(dir, importPath));
1556
2885
  references.push(resolved);
1557
2886
  }
1558
2887
  }
1559
2888
  while ((match = requireRegex.exec(content)) !== null) {
1560
2889
  const importPath = match[1];
1561
2890
  if (importPath.startsWith(".")) {
1562
- const dir = path5.dirname(filepath);
1563
- const resolved = path5.normalize(path5.join(dir, importPath));
2891
+ const dir = path8.dirname(filepath);
2892
+ const resolved = path8.normalize(path8.join(dir, importPath));
1564
2893
  references.push(resolved);
1565
2894
  }
1566
2895
  }
@@ -1581,7 +2910,7 @@ var init_typescript = __esm(() => {
1581
2910
  init_config2();
1582
2911
  import { glob } from "glob";
1583
2912
  import * as fs6 from "fs/promises";
1584
- import * as path9 from "path";
2913
+ import * as path11 from "path";
1585
2914
 
1586
2915
  // src/modules/registry.ts
1587
2916
  class ModuleRegistryImpl {
@@ -1611,12 +2940,12 @@ async function registerBuiltInModules() {
1611
2940
  registry.register(new TypeScriptModule2);
1612
2941
  }
1613
2942
 
1614
- // src/introspection/index.ts
1615
- import * as path8 from "path";
2943
+ // src/infrastructure/introspection/IntrospectionIndex.ts
2944
+ import * as path10 from "path";
1616
2945
  import * as fs5 from "fs/promises";
1617
2946
 
1618
- // src/introspection/projectDetector.ts
1619
- import * as path6 from "path";
2947
+ // src/infrastructure/introspection/projectDetector.ts
2948
+ import * as path9 from "path";
1620
2949
  import * as fs4 from "fs/promises";
1621
2950
  var MAX_SCAN_DEPTH = 4;
1622
2951
  var SKIP_DIRS = new Set([
@@ -1629,76 +2958,18 @@ var SKIP_DIRS = new Set([
1629
2958
  "coverage",
1630
2959
  ".raggrep"
1631
2960
  ]);
1632
- var PROJECT_PATTERNS = [
1633
- { pattern: /^apps\/([^/]+)/, type: "app", defaultScope: "unknown" },
1634
- { pattern: /^packages\/([^/]+)/, type: "library", defaultScope: "shared" },
1635
- { pattern: /^libs\/([^/]+)/, type: "library", defaultScope: "shared" },
1636
- { pattern: /^services\/([^/]+)/, type: "service", defaultScope: "backend" },
1637
- { pattern: /^scripts\/([^/]+)/, type: "script", defaultScope: "tooling" },
1638
- { pattern: /^tools\/([^/]+)/, type: "script", defaultScope: "tooling" }
1639
- ];
1640
- var SCOPE_KEYWORDS = {
1641
- frontend: [
1642
- "web",
1643
- "webapp",
1644
- "frontend",
1645
- "client",
1646
- "ui",
1647
- "app",
1648
- "mobile",
1649
- "react",
1650
- "vue",
1651
- "angular",
1652
- "next",
1653
- "nuxt"
1654
- ],
1655
- backend: [
1656
- "api",
1657
- "server",
1658
- "backend",
1659
- "service",
1660
- "worker",
1661
- "lambda",
1662
- "functions"
1663
- ],
1664
- shared: ["shared", "common", "utils", "lib", "core", "types", "models"],
1665
- tooling: [
1666
- "scripts",
1667
- "tools",
1668
- "cli",
1669
- "devtools",
1670
- "build",
1671
- "config",
1672
- "infra"
1673
- ],
1674
- unknown: []
1675
- };
1676
- function detectScopeFromName(name) {
1677
- const nameLower = name.toLowerCase();
1678
- for (const [scope, keywords] of Object.entries(SCOPE_KEYWORDS)) {
1679
- if (scope === "unknown")
1680
- continue;
1681
- for (const keyword of keywords) {
1682
- if (nameLower.includes(keyword)) {
1683
- return scope;
1684
- }
1685
- }
1686
- }
1687
- return "unknown";
1688
- }
1689
2961
  async function scanForPackageJsons(rootDir, currentDir = "", depth = 0) {
1690
2962
  if (depth > MAX_SCAN_DEPTH)
1691
2963
  return [];
1692
2964
  const results = [];
1693
- const fullDir = currentDir ? path6.join(rootDir, currentDir) : rootDir;
2965
+ const fullDir = currentDir ? path9.join(rootDir, currentDir) : rootDir;
1694
2966
  try {
1695
2967
  const entries = await fs4.readdir(fullDir, { withFileTypes: true });
1696
2968
  const hasPackageJson = entries.some((e) => e.isFile() && e.name === "package.json");
1697
2969
  if (hasPackageJson && currentDir) {
1698
2970
  const info = await parsePackageJson(rootDir, currentDir);
1699
- if (info) {
2971
+ if (info)
1700
2972
  results.push(info);
1701
- }
1702
2973
  }
1703
2974
  for (const entry of entries) {
1704
2975
  if (!entry.isDirectory())
@@ -1714,10 +2985,10 @@ async function scanForPackageJsons(rootDir, currentDir = "", depth = 0) {
1714
2985
  }
1715
2986
  async function parsePackageJson(rootDir, relativePath) {
1716
2987
  try {
1717
- const packageJsonPath = path6.join(rootDir, relativePath, "package.json");
2988
+ const packageJsonPath = path9.join(rootDir, relativePath, "package.json");
1718
2989
  const content = await fs4.readFile(packageJsonPath, "utf-8");
1719
2990
  const pkg = JSON.parse(content);
1720
- const name = pkg.name || path6.basename(relativePath);
2991
+ const name = pkg.name || path9.basename(relativePath);
1721
2992
  const deps = { ...pkg.dependencies, ...pkg.devDependencies };
1722
2993
  let type = "unknown";
1723
2994
  if (deps["next"] || deps["react"] || deps["vue"] || deps["svelte"]) {
@@ -1733,6 +3004,22 @@ async function parsePackageJson(rootDir, relativePath) {
1733
3004
  return null;
1734
3005
  }
1735
3006
  }
3007
+ function getProjectType(patternDir) {
3008
+ switch (patternDir) {
3009
+ case "apps":
3010
+ return "app";
3011
+ case "packages":
3012
+ case "libs":
3013
+ return "library";
3014
+ case "services":
3015
+ return "service";
3016
+ case "scripts":
3017
+ case "tools":
3018
+ return "script";
3019
+ default:
3020
+ return "unknown";
3021
+ }
3022
+ }
1736
3023
  async function detectProjectStructure(rootDir) {
1737
3024
  const projectMap = new Map;
1738
3025
  let isMonorepo = false;
@@ -1746,7 +3033,7 @@ async function detectProjectStructure(rootDir) {
1746
3033
  for (const pattern of monorepoPatterns) {
1747
3034
  if (!dirNames.includes(pattern))
1748
3035
  continue;
1749
- const patternDir = path6.join(rootDir, pattern);
3036
+ const patternDir = path9.join(rootDir, pattern);
1750
3037
  try {
1751
3038
  const subDirs = await fs4.readdir(patternDir, { withFileTypes: true });
1752
3039
  for (const subDir of subDirs) {
@@ -1765,12 +3052,10 @@ async function detectProjectStructure(rootDir) {
1765
3052
  }
1766
3053
  const packageJsons = await scanForPackageJsons(rootDir);
1767
3054
  for (const pkg of packageJsons) {
1768
- if (pkg.hasWorkspaces) {
3055
+ if (pkg.hasWorkspaces)
1769
3056
  isMonorepo = true;
1770
- }
1771
- if (packageJsons.length > 1) {
3057
+ if (packageJsons.length > 1)
1772
3058
  isMonorepo = true;
1773
- }
1774
3059
  projectMap.set(pkg.relativePath, {
1775
3060
  name: pkg.name,
1776
3061
  root: pkg.relativePath,
@@ -1779,11 +3064,10 @@ async function detectProjectStructure(rootDir) {
1779
3064
  }
1780
3065
  let rootType = "unknown";
1781
3066
  try {
1782
- const rootPkgPath = path6.join(rootDir, "package.json");
3067
+ const rootPkgPath = path9.join(rootDir, "package.json");
1783
3068
  const rootPkg = JSON.parse(await fs4.readFile(rootPkgPath, "utf-8"));
1784
- if (rootPkg.workspaces) {
3069
+ if (rootPkg.workspaces)
1785
3070
  isMonorepo = true;
1786
- }
1787
3071
  const deps = { ...rootPkg.dependencies, ...rootPkg.devDependencies };
1788
3072
  if (deps["next"] || deps["react"] || deps["vue"]) {
1789
3073
  rootType = "app";
@@ -1805,273 +3089,9 @@ async function detectProjectStructure(rootDir) {
1805
3089
  };
1806
3090
  }
1807
3091
  }
1808
- function getProjectType(patternDir) {
1809
- switch (patternDir) {
1810
- case "apps":
1811
- return "app";
1812
- case "packages":
1813
- case "libs":
1814
- return "library";
1815
- case "services":
1816
- return "service";
1817
- case "scripts":
1818
- case "tools":
1819
- return "script";
1820
- default:
1821
- return "unknown";
1822
- }
1823
- }
1824
- function findProjectForFile(filepath, structure) {
1825
- const normalizedPath = filepath.replace(/\\/g, "/");
1826
- const matches = [];
1827
- for (const project of structure.projects) {
1828
- if (normalizedPath === project.root || normalizedPath.startsWith(project.root + "/")) {
1829
- matches.push(project);
1830
- }
1831
- }
1832
- if (matches.length > 0) {
1833
- return matches.reduce((best, current) => current.root.length > best.root.length ? current : best);
1834
- }
1835
- for (const { pattern, type } of PROJECT_PATTERNS) {
1836
- const match = normalizedPath.match(pattern);
1837
- if (match) {
1838
- return {
1839
- name: match[1],
1840
- root: match[0],
1841
- type
1842
- };
1843
- }
1844
- }
1845
- return {
1846
- name: "root",
1847
- root: "",
1848
- type: structure.rootType ?? "unknown"
1849
- };
1850
- }
1851
-
1852
- // src/introspection/fileIntrospector.ts
1853
- import * as path7 from "path";
1854
- var LAYER_PATTERNS2 = {
1855
- controller: ["controller", "api", "routes", "route", "handler"],
1856
- service: ["service", "logic", "usecase", "usecases", "handler"],
1857
- repository: ["repository", "repo", "dao", "store", "persistence"],
1858
- model: ["model", "models", "entity", "entities", "schema", "schemas", "types", "type"],
1859
- util: ["util", "utils", "helper", "helpers", "common", "lib"],
1860
- config: ["config", "configuration", "settings"],
1861
- middleware: ["middleware", "middlewares"],
1862
- domain: ["domain"],
1863
- infrastructure: ["infrastructure", "infra"],
1864
- application: ["application", "app"],
1865
- presentation: ["presentation", "ui", "views", "view", "component", "components"],
1866
- test: ["test", "tests", "spec", "specs", "__tests__", "e2e"]
1867
- };
1868
- var DOMAIN_PATTERNS = [
1869
- "auth",
1870
- "authentication",
1871
- "user",
1872
- "users",
1873
- "account",
1874
- "accounts",
1875
- "profile",
1876
- "profiles",
1877
- "product",
1878
- "products",
1879
- "item",
1880
- "items",
1881
- "catalog",
1882
- "order",
1883
- "orders",
1884
- "cart",
1885
- "checkout",
1886
- "payment",
1887
- "payments",
1888
- "billing",
1889
- "subscription",
1890
- "subscriptions",
1891
- "notification",
1892
- "notifications",
1893
- "email",
1894
- "sms",
1895
- "report",
1896
- "reports",
1897
- "analytics",
1898
- "metrics",
1899
- "dashboard",
1900
- "admin",
1901
- "settings",
1902
- "search",
1903
- "chat",
1904
- "message",
1905
- "messages",
1906
- "feed",
1907
- "post",
1908
- "posts",
1909
- "comment",
1910
- "comments",
1911
- "media",
1912
- "upload",
1913
- "file",
1914
- "files",
1915
- "storage",
1916
- "cache",
1917
- "session",
1918
- "log",
1919
- "logs",
1920
- "audit"
1921
- ];
1922
- var FRAMEWORK_INDICATORS = {
1923
- nextjs: ["next", "next/"],
1924
- express: ["express"],
1925
- fastify: ["fastify"],
1926
- react: ["react"],
1927
- vue: ["vue"],
1928
- angular: ["@angular/"],
1929
- nestjs: ["@nestjs/"],
1930
- koa: ["koa"]
1931
- };
1932
- var EXTENSION_TO_LANGUAGE = {
1933
- ".ts": "typescript",
1934
- ".tsx": "typescript",
1935
- ".js": "javascript",
1936
- ".jsx": "javascript",
1937
- ".mjs": "javascript",
1938
- ".cjs": "javascript",
1939
- ".py": "python",
1940
- ".go": "go",
1941
- ".rs": "rust",
1942
- ".java": "java",
1943
- ".kt": "kotlin",
1944
- ".swift": "swift",
1945
- ".rb": "ruby",
1946
- ".php": "php",
1947
- ".cs": "csharp",
1948
- ".cpp": "cpp",
1949
- ".c": "c",
1950
- ".h": "c",
1951
- ".hpp": "cpp",
1952
- ".md": "markdown",
1953
- ".json": "json",
1954
- ".yaml": "yaml",
1955
- ".yml": "yaml"
1956
- };
1957
- function introspectFile(filepath, structure, fileContent) {
1958
- const normalizedPath = filepath.replace(/\\/g, "/");
1959
- const segments = normalizedPath.split("/").filter((s) => s.length > 0);
1960
- const filename = segments[segments.length - 1] || "";
1961
- const ext = path7.extname(filename);
1962
- const project = findProjectForFile(normalizedPath, structure);
1963
- const language = EXTENSION_TO_LANGUAGE[ext] || "unknown";
1964
- const layer = detectLayer(segments, filename);
1965
- const domain = detectDomain(segments);
1966
- const scope = detectScope(segments, project, layer);
1967
- let framework;
1968
- if (fileContent) {
1969
- framework = detectFramework(fileContent);
1970
- }
1971
- return {
1972
- filepath: normalizedPath,
1973
- project,
1974
- scope,
1975
- layer,
1976
- domain,
1977
- language,
1978
- framework,
1979
- depth: segments.length - 1,
1980
- pathSegments: segments.slice(0, -1)
1981
- };
1982
- }
1983
- function detectLayer(segments, filename) {
1984
- const filenameLower = filename.toLowerCase();
1985
- for (const [layer, patterns] of Object.entries(LAYER_PATTERNS2)) {
1986
- for (const pattern of patterns) {
1987
- if (filenameLower.includes(pattern)) {
1988
- return layer;
1989
- }
1990
- }
1991
- }
1992
- for (let i = segments.length - 2;i >= 0; i--) {
1993
- const segment = segments[i].toLowerCase();
1994
- for (const [layer, patterns] of Object.entries(LAYER_PATTERNS2)) {
1995
- if (patterns.includes(segment)) {
1996
- return layer;
1997
- }
1998
- }
1999
- }
2000
- return;
2001
- }
2002
- function detectDomain(segments) {
2003
- const skipSegments = new Set([
2004
- "src",
2005
- "lib",
2006
- "app",
2007
- "apps",
2008
- "packages",
2009
- "services",
2010
- "modules",
2011
- "features",
2012
- ...Object.values(LAYER_PATTERNS2).flat()
2013
- ]);
2014
- for (const segment of segments) {
2015
- const segmentLower = segment.toLowerCase();
2016
- if (skipSegments.has(segmentLower))
2017
- continue;
2018
- if (DOMAIN_PATTERNS.includes(segmentLower)) {
2019
- return segmentLower;
2020
- }
2021
- for (const domain of DOMAIN_PATTERNS) {
2022
- if (segmentLower.startsWith(domain) || segmentLower.endsWith(domain)) {
2023
- return domain;
2024
- }
2025
- }
2026
- }
2027
- return;
2028
- }
2029
- function detectScope(segments, project, layer) {
2030
- const projectScope = detectScopeFromName(project.name);
2031
- if (projectScope !== "unknown") {
2032
- return projectScope;
2033
- }
2034
- if (layer) {
2035
- switch (layer) {
2036
- case "controller":
2037
- case "repository":
2038
- case "middleware":
2039
- return "backend";
2040
- case "presentation":
2041
- return "frontend";
2042
- case "util":
2043
- case "model":
2044
- return "shared";
2045
- case "test":
2046
- return "tooling";
2047
- }
2048
- }
2049
- for (const segment of segments) {
2050
- const segmentLower = segment.toLowerCase();
2051
- if (["server", "api", "backend"].includes(segmentLower)) {
2052
- return "backend";
2053
- }
2054
- if (["client", "web", "frontend", "ui"].includes(segmentLower)) {
2055
- return "frontend";
2056
- }
2057
- if (["shared", "common", "lib", "libs"].includes(segmentLower)) {
2058
- return "shared";
2059
- }
2060
- }
2061
- return "unknown";
2062
- }
2063
- function detectFramework(content) {
2064
- for (const [framework, indicators] of Object.entries(FRAMEWORK_INDICATORS)) {
2065
- for (const indicator of indicators) {
2066
- if (content.includes(`from '${indicator}`) || content.includes(`from "${indicator}`) || content.includes(`require('${indicator}`) || content.includes(`require("${indicator}`)) {
2067
- return framework;
2068
- }
2069
- }
2070
- }
2071
- return;
2072
- }
2073
3092
 
2074
- // src/introspection/index.ts
3093
+ // src/infrastructure/introspection/IntrospectionIndex.ts
3094
+ init_introspection();
2075
3095
  init_config2();
2076
3096
 
2077
3097
  class IntrospectionIndex {
@@ -2085,7 +3105,7 @@ class IntrospectionIndex {
2085
3105
  async initialize() {
2086
3106
  this.structure = await detectProjectStructure(this.rootDir);
2087
3107
  try {
2088
- const configPath = path8.join(this.rootDir, ".raggrep", "config.json");
3108
+ const configPath = path10.join(this.rootDir, ".raggrep", "config.json");
2089
3109
  const configContent = await fs5.readFile(configPath, "utf-8");
2090
3110
  const config = JSON.parse(configContent);
2091
3111
  this.config = config.introspection || {};
@@ -2125,29 +3145,29 @@ class IntrospectionIndex {
2125
3145
  }
2126
3146
  }
2127
3147
  async save(config) {
2128
- const introDir = path8.join(getRaggrepDir(this.rootDir, config), "introspection");
3148
+ const introDir = path10.join(getRaggrepDir(this.rootDir, config), "introspection");
2129
3149
  await fs5.mkdir(introDir, { recursive: true });
2130
- const projectPath = path8.join(introDir, "_project.json");
3150
+ const projectPath = path10.join(introDir, "_project.json");
2131
3151
  await fs5.writeFile(projectPath, JSON.stringify({
2132
3152
  version: "1.0.0",
2133
3153
  lastUpdated: new Date().toISOString(),
2134
3154
  structure: this.structure
2135
3155
  }, null, 2));
2136
3156
  for (const [filepath, intro] of this.files) {
2137
- const introFilePath = path8.join(introDir, "files", filepath.replace(/\.[^.]+$/, ".json"));
2138
- await fs5.mkdir(path8.dirname(introFilePath), { recursive: true });
3157
+ const introFilePath = path10.join(introDir, "files", filepath.replace(/\.[^.]+$/, ".json"));
3158
+ await fs5.mkdir(path10.dirname(introFilePath), { recursive: true });
2139
3159
  await fs5.writeFile(introFilePath, JSON.stringify(intro, null, 2));
2140
3160
  }
2141
3161
  console.log(` [Introspection] Saved metadata for ${this.files.size} files`);
2142
3162
  }
2143
3163
  async load(config) {
2144
- const introDir = path8.join(getRaggrepDir(this.rootDir, config), "introspection");
3164
+ const introDir = path10.join(getRaggrepDir(this.rootDir, config), "introspection");
2145
3165
  try {
2146
- const projectPath = path8.join(introDir, "_project.json");
3166
+ const projectPath = path10.join(introDir, "_project.json");
2147
3167
  const projectContent = await fs5.readFile(projectPath, "utf-8");
2148
3168
  const projectData = JSON.parse(projectContent);
2149
3169
  this.structure = projectData.structure;
2150
- await this.loadFilesRecursive(path8.join(introDir, "files"), "");
3170
+ await this.loadFilesRecursive(path10.join(introDir, "files"), "");
2151
3171
  } catch {
2152
3172
  this.structure = null;
2153
3173
  this.files.clear();
@@ -2157,7 +3177,7 @@ class IntrospectionIndex {
2157
3177
  try {
2158
3178
  const entries = await fs5.readdir(basePath, { withFileTypes: true });
2159
3179
  for (const entry of entries) {
2160
- const entryPath = path8.join(basePath, entry.name);
3180
+ const entryPath = path10.join(basePath, entry.name);
2161
3181
  const relativePath = prefix ? `${prefix}/${entry.name}` : entry.name;
2162
3182
  if (entry.isDirectory()) {
2163
3183
  await this.loadFilesRecursive(entryPath, relativePath);
@@ -2174,7 +3194,6 @@ class IntrospectionIndex {
2174
3194
  this.structure = null;
2175
3195
  }
2176
3196
  }
2177
-
2178
3197
  // src/app/indexer/watcher.ts
2179
3198
  import { watch } from "chokidar";
2180
3199
  init_config2();
@@ -2182,8 +3201,10 @@ init_config2();
2182
3201
  // src/app/indexer/index.ts
2183
3202
  async function indexDirectory(rootDir, options = {}) {
2184
3203
  const verbose = options.verbose ?? false;
2185
- rootDir = path9.resolve(rootDir);
3204
+ rootDir = path11.resolve(rootDir);
3205
+ const location = getIndexLocation(rootDir);
2186
3206
  console.log(`Indexing directory: ${rootDir}`);
3207
+ console.log(`Index location: ${location.indexDir}`);
2187
3208
  const config = await loadConfig(rootDir);
2188
3209
  const introspection = new IntrospectionIndex(rootDir);
2189
3210
  await introspection.initialize();
@@ -2225,11 +3246,11 @@ async function indexDirectory(rootDir, options = {}) {
2225
3246
  rootDir,
2226
3247
  config,
2227
3248
  readFile: async (filepath) => {
2228
- const fullPath = path9.isAbsolute(filepath) ? filepath : path9.join(rootDir, filepath);
3249
+ const fullPath = path11.isAbsolute(filepath) ? filepath : path11.join(rootDir, filepath);
2229
3250
  return fs6.readFile(fullPath, "utf-8");
2230
3251
  },
2231
3252
  getFileStats: async (filepath) => {
2232
- const fullPath = path9.isAbsolute(filepath) ? filepath : path9.join(rootDir, filepath);
3253
+ const fullPath = path11.isAbsolute(filepath) ? filepath : path11.join(rootDir, filepath);
2233
3254
  const stats = await fs6.stat(fullPath);
2234
3255
  return { lastModified: stats.mtime.toISOString() };
2235
3256
  }
@@ -2254,18 +3275,18 @@ async function indexWithModule(rootDir, files, module, config, verbose, introspe
2254
3275
  rootDir,
2255
3276
  config,
2256
3277
  readFile: async (filepath) => {
2257
- const fullPath = path9.isAbsolute(filepath) ? filepath : path9.join(rootDir, filepath);
3278
+ const fullPath = path11.isAbsolute(filepath) ? filepath : path11.join(rootDir, filepath);
2258
3279
  return fs6.readFile(fullPath, "utf-8");
2259
3280
  },
2260
3281
  getFileStats: async (filepath) => {
2261
- const fullPath = path9.isAbsolute(filepath) ? filepath : path9.join(rootDir, filepath);
3282
+ const fullPath = path11.isAbsolute(filepath) ? filepath : path11.join(rootDir, filepath);
2262
3283
  const stats = await fs6.stat(fullPath);
2263
3284
  return { lastModified: stats.mtime.toISOString() };
2264
3285
  },
2265
3286
  getIntrospection: (filepath) => introspection.getFile(filepath)
2266
3287
  };
2267
3288
  for (const filepath of files) {
2268
- const relativePath = path9.relative(rootDir, filepath);
3289
+ const relativePath = path11.relative(rootDir, filepath);
2269
3290
  try {
2270
3291
  const stats = await fs6.stat(filepath);
2271
3292
  const lastModified = stats.mtime.toISOString();
@@ -2335,13 +3356,13 @@ async function loadModuleManifest(rootDir, moduleId, config) {
2335
3356
  }
2336
3357
  async function writeModuleManifest(rootDir, moduleId, manifest, config) {
2337
3358
  const manifestPath = getModuleManifestPath(rootDir, moduleId, config);
2338
- await fs6.mkdir(path9.dirname(manifestPath), { recursive: true });
3359
+ await fs6.mkdir(path11.dirname(manifestPath), { recursive: true });
2339
3360
  await fs6.writeFile(manifestPath, JSON.stringify(manifest, null, 2));
2340
3361
  }
2341
3362
  async function writeFileIndex(rootDir, moduleId, filepath, fileIndex, config) {
2342
3363
  const indexPath = getModuleIndexPath(rootDir, moduleId, config);
2343
- const indexFilePath = path9.join(indexPath, filepath.replace(/\.[^.]+$/, ".json"));
2344
- await fs6.mkdir(path9.dirname(indexFilePath), { recursive: true });
3364
+ const indexFilePath = path11.join(indexPath, filepath.replace(/\.[^.]+$/, ".json"));
3365
+ await fs6.mkdir(path11.dirname(indexFilePath), { recursive: true });
2345
3366
  await fs6.writeFile(indexFilePath, JSON.stringify(fileIndex, null, 2));
2346
3367
  }
2347
3368
  async function updateGlobalManifest(rootDir, modules, config) {
@@ -2351,12 +3372,12 @@ async function updateGlobalManifest(rootDir, modules, config) {
2351
3372
  lastUpdated: new Date().toISOString(),
2352
3373
  modules: modules.map((m) => m.id)
2353
3374
  };
2354
- await fs6.mkdir(path9.dirname(manifestPath), { recursive: true });
3375
+ await fs6.mkdir(path11.dirname(manifestPath), { recursive: true });
2355
3376
  await fs6.writeFile(manifestPath, JSON.stringify(manifest, null, 2));
2356
3377
  }
2357
3378
  async function cleanupIndex(rootDir, options = {}) {
2358
3379
  const verbose = options.verbose ?? false;
2359
- rootDir = path9.resolve(rootDir);
3380
+ rootDir = path11.resolve(rootDir);
2360
3381
  console.log(`Cleaning up index in: ${rootDir}`);
2361
3382
  const config = await loadConfig(rootDir);
2362
3383
  await registerBuiltInModules();
@@ -2386,7 +3407,7 @@ async function cleanupModuleIndex(rootDir, moduleId, config, verbose) {
2386
3407
  const filesToRemove = [];
2387
3408
  const updatedFiles = {};
2388
3409
  for (const [filepath, entry] of Object.entries(manifest.files)) {
2389
- const fullPath = path9.join(rootDir, filepath);
3410
+ const fullPath = path11.join(rootDir, filepath);
2390
3411
  try {
2391
3412
  await fs6.access(fullPath);
2392
3413
  updatedFiles[filepath] = entry;
@@ -2400,7 +3421,7 @@ async function cleanupModuleIndex(rootDir, moduleId, config, verbose) {
2400
3421
  }
2401
3422
  }
2402
3423
  for (const filepath of filesToRemove) {
2403
- const indexFilePath = path9.join(indexPath, filepath.replace(/\.[^.]+$/, ".json"));
3424
+ const indexFilePath = path11.join(indexPath, filepath.replace(/\.[^.]+$/, ".json"));
2404
3425
  try {
2405
3426
  await fs6.unlink(indexFilePath);
2406
3427
  } catch {}
@@ -2416,7 +3437,7 @@ async function cleanupEmptyDirectories(dir) {
2416
3437
  const entries = await fs6.readdir(dir, { withFileTypes: true });
2417
3438
  for (const entry of entries) {
2418
3439
  if (entry.isDirectory()) {
2419
- const subDir = path9.join(dir, entry.name);
3440
+ const subDir = path11.join(dir, entry.name);
2420
3441
  await cleanupEmptyDirectories(subDir);
2421
3442
  }
2422
3443
  }
@@ -2434,9 +3455,9 @@ async function cleanupEmptyDirectories(dir) {
2434
3455
  // src/app/search/index.ts
2435
3456
  init_config2();
2436
3457
  import * as fs7 from "fs/promises";
2437
- import * as path10 from "path";
3458
+ import * as path12 from "path";
2438
3459
  async function search(rootDir, query, options = {}) {
2439
- rootDir = path10.resolve(rootDir);
3460
+ rootDir = path12.resolve(rootDir);
2440
3461
  console.log(`Searching for: "${query}"`);
2441
3462
  const config = await loadConfig(rootDir);
2442
3463
  await registerBuiltInModules();
@@ -2477,7 +3498,7 @@ function createSearchContext(rootDir, moduleId, config) {
2477
3498
  config,
2478
3499
  loadFileIndex: async (filepath) => {
2479
3500
  const hasExtension = /\.[^./]+$/.test(filepath);
2480
- const indexFilePath = hasExtension ? path10.join(indexPath, filepath.replace(/\.[^.]+$/, ".json")) : path10.join(indexPath, filepath + ".json");
3501
+ const indexFilePath = hasExtension ? path12.join(indexPath, filepath.replace(/\.[^.]+$/, ".json")) : path12.join(indexPath, filepath + ".json");
2481
3502
  try {
2482
3503
  const content = await fs7.readFile(indexFilePath, "utf-8");
2483
3504
  return JSON.parse(content);
@@ -2489,7 +3510,7 @@ function createSearchContext(rootDir, moduleId, config) {
2489
3510
  const files = [];
2490
3511
  await traverseDirectory(indexPath, files, indexPath);
2491
3512
  return files.filter((f) => f.endsWith(".json") && !f.endsWith("manifest.json")).map((f) => {
2492
- const relative3 = path10.relative(indexPath, f);
3513
+ const relative3 = path12.relative(indexPath, f);
2493
3514
  return relative3.replace(/\.json$/, "");
2494
3515
  });
2495
3516
  }
@@ -2499,7 +3520,7 @@ async function traverseDirectory(dir, files, basePath) {
2499
3520
  try {
2500
3521
  const entries = await fs7.readdir(dir, { withFileTypes: true });
2501
3522
  for (const entry of entries) {
2502
- const fullPath = path10.join(dir, entry.name);
3523
+ const fullPath = path12.join(dir, entry.name);
2503
3524
  if (entry.isDirectory()) {
2504
3525
  await traverseDirectory(fullPath, files, basePath);
2505
3526
  } else if (entry.isFile()) {
@@ -2517,6 +3538,20 @@ async function loadGlobalManifest(rootDir, config) {
2517
3538
  return null;
2518
3539
  }
2519
3540
  }
3541
+ function formatModuleName(moduleId) {
3542
+ switch (moduleId) {
3543
+ case "core":
3544
+ return "Core";
3545
+ case "language/typescript":
3546
+ return "TypeScript";
3547
+ default:
3548
+ if (moduleId.startsWith("language/")) {
3549
+ const lang = moduleId.replace("language/", "");
3550
+ return lang.charAt(0).toUpperCase() + lang.slice(1);
3551
+ }
3552
+ return moduleId;
3553
+ }
3554
+ }
2520
3555
  function formatSearchResults(results) {
2521
3556
  if (results.length === 0) {
2522
3557
  return "No results found.";
@@ -2532,6 +3567,7 @@ function formatSearchResults(results) {
2532
3567
  output += `${i + 1}. ${location}${nameInfo}
2533
3568
  `;
2534
3569
  output += ` Score: ${(result.score * 100).toFixed(1)}% | Type: ${chunk.type}`;
3570
+ output += ` | via ${formatModuleName(result.moduleId)}`;
2535
3571
  if (chunk.isExported) {
2536
3572
  output += " | exported";
2537
3573
  }
@@ -2575,4 +3611,4 @@ export {
2575
3611
  cleanup
2576
3612
  };
2577
3613
 
2578
- //# debugId=0E3E5BCA1147AB0A64756E2164756E21
3614
+ //# debugId=B36BFBBC8240BDFB64756E2164756E21