raggrep 0.1.6 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +62 -95
- package/dist/app/indexer/index.d.ts +27 -2
- package/dist/cli/main.js +967 -604
- package/dist/cli/main.js.map +18 -17
- package/dist/{introspection/conventions/types.d.ts → domain/entities/conventions.d.ts} +6 -5
- package/dist/domain/entities/index.d.ts +2 -0
- package/dist/{introspection → domain/services}/conventions/configFiles.d.ts +1 -1
- package/dist/{introspection → domain/services}/conventions/entryPoints.d.ts +1 -1
- package/dist/{introspection → domain/services}/conventions/frameworks/convex.d.ts +1 -1
- package/dist/{introspection → domain/services}/conventions/frameworks/index.d.ts +1 -1
- package/dist/{introspection → domain/services}/conventions/frameworks/nextjs.d.ts +1 -1
- package/dist/{introspection → domain/services}/conventions/index.d.ts +5 -5
- package/dist/domain/services/introspection.d.ts +31 -0
- package/dist/index.js +671 -474
- package/dist/index.js.map +16 -16
- package/dist/{introspection/index.d.ts → infrastructure/introspection/IntrospectionIndex.d.ts} +3 -14
- package/dist/infrastructure/introspection/index.d.ts +9 -0
- package/dist/{introspection → infrastructure/introspection}/projectDetector.d.ts +3 -12
- package/dist/types.d.ts +4 -4
- package/package.json +1 -1
- package/dist/introspection/fileIntrospector.d.ts +0 -14
- /package/dist/{introspection/types.d.ts → domain/entities/introspection.d.ts} +0 -0
- /package/dist/{introspection → domain/services}/conventions/conventions.test.d.ts +0 -0
- /package/dist/{introspection → domain/services}/introspection.test.d.ts +0 -0
package/dist/index.js
CHANGED
|
@@ -270,247 +270,11 @@ function normalizeScore(score, midpoint = 5) {
|
|
|
270
270
|
}
|
|
271
271
|
var BM25_K1 = 1.5, BM25_B = 0.75;
|
|
272
272
|
|
|
273
|
-
// src/
|
|
273
|
+
// src/domain/services/conventions/entryPoints.ts
|
|
274
274
|
import * as path2 from "path";
|
|
275
|
-
import * as fs2 from "fs/promises";
|
|
276
|
-
function detectScopeFromName(name) {
|
|
277
|
-
const nameLower = name.toLowerCase();
|
|
278
|
-
for (const [scope, keywords] of Object.entries(SCOPE_KEYWORDS)) {
|
|
279
|
-
if (scope === "unknown")
|
|
280
|
-
continue;
|
|
281
|
-
for (const keyword of keywords) {
|
|
282
|
-
if (nameLower.includes(keyword)) {
|
|
283
|
-
return scope;
|
|
284
|
-
}
|
|
285
|
-
}
|
|
286
|
-
}
|
|
287
|
-
return "unknown";
|
|
288
|
-
}
|
|
289
|
-
async function scanForPackageJsons(rootDir, currentDir = "", depth = 0) {
|
|
290
|
-
if (depth > MAX_SCAN_DEPTH)
|
|
291
|
-
return [];
|
|
292
|
-
const results = [];
|
|
293
|
-
const fullDir = currentDir ? path2.join(rootDir, currentDir) : rootDir;
|
|
294
|
-
try {
|
|
295
|
-
const entries = await fs2.readdir(fullDir, { withFileTypes: true });
|
|
296
|
-
const hasPackageJson = entries.some((e) => e.isFile() && e.name === "package.json");
|
|
297
|
-
if (hasPackageJson && currentDir) {
|
|
298
|
-
const info = await parsePackageJson(rootDir, currentDir);
|
|
299
|
-
if (info) {
|
|
300
|
-
results.push(info);
|
|
301
|
-
}
|
|
302
|
-
}
|
|
303
|
-
for (const entry of entries) {
|
|
304
|
-
if (!entry.isDirectory())
|
|
305
|
-
continue;
|
|
306
|
-
if (SKIP_DIRS.has(entry.name))
|
|
307
|
-
continue;
|
|
308
|
-
const subPath = currentDir ? `${currentDir}/${entry.name}` : entry.name;
|
|
309
|
-
const subResults = await scanForPackageJsons(rootDir, subPath, depth + 1);
|
|
310
|
-
results.push(...subResults);
|
|
311
|
-
}
|
|
312
|
-
} catch {}
|
|
313
|
-
return results;
|
|
314
|
-
}
|
|
315
|
-
async function parsePackageJson(rootDir, relativePath) {
|
|
316
|
-
try {
|
|
317
|
-
const packageJsonPath = path2.join(rootDir, relativePath, "package.json");
|
|
318
|
-
const content = await fs2.readFile(packageJsonPath, "utf-8");
|
|
319
|
-
const pkg = JSON.parse(content);
|
|
320
|
-
const name = pkg.name || path2.basename(relativePath);
|
|
321
|
-
const deps = { ...pkg.dependencies, ...pkg.devDependencies };
|
|
322
|
-
let type = "unknown";
|
|
323
|
-
if (deps["next"] || deps["react"] || deps["vue"] || deps["svelte"]) {
|
|
324
|
-
type = "app";
|
|
325
|
-
} else if (deps["express"] || deps["fastify"] || deps["koa"] || deps["hono"]) {
|
|
326
|
-
type = "service";
|
|
327
|
-
} else if (pkg.main || pkg.exports) {
|
|
328
|
-
type = "library";
|
|
329
|
-
}
|
|
330
|
-
const hasWorkspaces = Boolean(pkg.workspaces);
|
|
331
|
-
return { name, relativePath, type, hasWorkspaces };
|
|
332
|
-
} catch {
|
|
333
|
-
return null;
|
|
334
|
-
}
|
|
335
|
-
}
|
|
336
|
-
async function detectProjectStructure(rootDir) {
|
|
337
|
-
const projectMap = new Map;
|
|
338
|
-
let isMonorepo = false;
|
|
339
|
-
try {
|
|
340
|
-
const entries = await fs2.readdir(rootDir, { withFileTypes: true });
|
|
341
|
-
const dirNames = entries.filter((e) => e.isDirectory()).map((e) => e.name);
|
|
342
|
-
const monorepoPatterns = ["apps", "packages", "libs", "services"];
|
|
343
|
-
const hasMonorepoStructure = monorepoPatterns.some((p) => dirNames.includes(p));
|
|
344
|
-
if (hasMonorepoStructure) {
|
|
345
|
-
isMonorepo = true;
|
|
346
|
-
for (const pattern of monorepoPatterns) {
|
|
347
|
-
if (!dirNames.includes(pattern))
|
|
348
|
-
continue;
|
|
349
|
-
const patternDir = path2.join(rootDir, pattern);
|
|
350
|
-
try {
|
|
351
|
-
const subDirs = await fs2.readdir(patternDir, { withFileTypes: true });
|
|
352
|
-
for (const subDir of subDirs) {
|
|
353
|
-
if (!subDir.isDirectory())
|
|
354
|
-
continue;
|
|
355
|
-
const projectRoot = `${pattern}/${subDir.name}`;
|
|
356
|
-
const type = getProjectType(pattern);
|
|
357
|
-
projectMap.set(projectRoot, {
|
|
358
|
-
name: subDir.name,
|
|
359
|
-
root: projectRoot,
|
|
360
|
-
type
|
|
361
|
-
});
|
|
362
|
-
}
|
|
363
|
-
} catch {}
|
|
364
|
-
}
|
|
365
|
-
}
|
|
366
|
-
const packageJsons = await scanForPackageJsons(rootDir);
|
|
367
|
-
for (const pkg of packageJsons) {
|
|
368
|
-
if (pkg.hasWorkspaces) {
|
|
369
|
-
isMonorepo = true;
|
|
370
|
-
}
|
|
371
|
-
if (packageJsons.length > 1) {
|
|
372
|
-
isMonorepo = true;
|
|
373
|
-
}
|
|
374
|
-
projectMap.set(pkg.relativePath, {
|
|
375
|
-
name: pkg.name,
|
|
376
|
-
root: pkg.relativePath,
|
|
377
|
-
type: pkg.type
|
|
378
|
-
});
|
|
379
|
-
}
|
|
380
|
-
let rootType = "unknown";
|
|
381
|
-
try {
|
|
382
|
-
const rootPkgPath = path2.join(rootDir, "package.json");
|
|
383
|
-
const rootPkg = JSON.parse(await fs2.readFile(rootPkgPath, "utf-8"));
|
|
384
|
-
if (rootPkg.workspaces) {
|
|
385
|
-
isMonorepo = true;
|
|
386
|
-
}
|
|
387
|
-
const deps = { ...rootPkg.dependencies, ...rootPkg.devDependencies };
|
|
388
|
-
if (deps["next"] || deps["react"] || deps["vue"]) {
|
|
389
|
-
rootType = "app";
|
|
390
|
-
} else if (deps["express"] || deps["fastify"] || deps["koa"]) {
|
|
391
|
-
rootType = "service";
|
|
392
|
-
}
|
|
393
|
-
} catch {}
|
|
394
|
-
const projects = Array.from(projectMap.values()).sort((a, b) => a.root.length - b.root.length);
|
|
395
|
-
return {
|
|
396
|
-
projects,
|
|
397
|
-
isMonorepo,
|
|
398
|
-
rootType: isMonorepo ? undefined : rootType
|
|
399
|
-
};
|
|
400
|
-
} catch {
|
|
401
|
-
return {
|
|
402
|
-
projects: [],
|
|
403
|
-
isMonorepo: false,
|
|
404
|
-
rootType: "unknown"
|
|
405
|
-
};
|
|
406
|
-
}
|
|
407
|
-
}
|
|
408
|
-
function getProjectType(patternDir) {
|
|
409
|
-
switch (patternDir) {
|
|
410
|
-
case "apps":
|
|
411
|
-
return "app";
|
|
412
|
-
case "packages":
|
|
413
|
-
case "libs":
|
|
414
|
-
return "library";
|
|
415
|
-
case "services":
|
|
416
|
-
return "service";
|
|
417
|
-
case "scripts":
|
|
418
|
-
case "tools":
|
|
419
|
-
return "script";
|
|
420
|
-
default:
|
|
421
|
-
return "unknown";
|
|
422
|
-
}
|
|
423
|
-
}
|
|
424
|
-
function findProjectForFile(filepath, structure) {
|
|
425
|
-
const normalizedPath = filepath.replace(/\\/g, "/");
|
|
426
|
-
const matches = [];
|
|
427
|
-
for (const project of structure.projects) {
|
|
428
|
-
if (normalizedPath === project.root || normalizedPath.startsWith(project.root + "/")) {
|
|
429
|
-
matches.push(project);
|
|
430
|
-
}
|
|
431
|
-
}
|
|
432
|
-
if (matches.length > 0) {
|
|
433
|
-
return matches.reduce((best, current) => current.root.length > best.root.length ? current : best);
|
|
434
|
-
}
|
|
435
|
-
for (const { pattern, type } of PROJECT_PATTERNS) {
|
|
436
|
-
const match = normalizedPath.match(pattern);
|
|
437
|
-
if (match) {
|
|
438
|
-
return {
|
|
439
|
-
name: match[1],
|
|
440
|
-
root: match[0],
|
|
441
|
-
type
|
|
442
|
-
};
|
|
443
|
-
}
|
|
444
|
-
}
|
|
445
|
-
return {
|
|
446
|
-
name: "root",
|
|
447
|
-
root: "",
|
|
448
|
-
type: structure.rootType ?? "unknown"
|
|
449
|
-
};
|
|
450
|
-
}
|
|
451
|
-
var MAX_SCAN_DEPTH = 4, SKIP_DIRS, PROJECT_PATTERNS, SCOPE_KEYWORDS;
|
|
452
|
-
var init_projectDetector = __esm(() => {
|
|
453
|
-
SKIP_DIRS = new Set([
|
|
454
|
-
"node_modules",
|
|
455
|
-
".git",
|
|
456
|
-
"dist",
|
|
457
|
-
"build",
|
|
458
|
-
".next",
|
|
459
|
-
".nuxt",
|
|
460
|
-
"coverage",
|
|
461
|
-
".raggrep"
|
|
462
|
-
]);
|
|
463
|
-
PROJECT_PATTERNS = [
|
|
464
|
-
{ pattern: /^apps\/([^/]+)/, type: "app", defaultScope: "unknown" },
|
|
465
|
-
{ pattern: /^packages\/([^/]+)/, type: "library", defaultScope: "shared" },
|
|
466
|
-
{ pattern: /^libs\/([^/]+)/, type: "library", defaultScope: "shared" },
|
|
467
|
-
{ pattern: /^services\/([^/]+)/, type: "service", defaultScope: "backend" },
|
|
468
|
-
{ pattern: /^scripts\/([^/]+)/, type: "script", defaultScope: "tooling" },
|
|
469
|
-
{ pattern: /^tools\/([^/]+)/, type: "script", defaultScope: "tooling" }
|
|
470
|
-
];
|
|
471
|
-
SCOPE_KEYWORDS = {
|
|
472
|
-
frontend: [
|
|
473
|
-
"web",
|
|
474
|
-
"webapp",
|
|
475
|
-
"frontend",
|
|
476
|
-
"client",
|
|
477
|
-
"ui",
|
|
478
|
-
"app",
|
|
479
|
-
"mobile",
|
|
480
|
-
"react",
|
|
481
|
-
"vue",
|
|
482
|
-
"angular",
|
|
483
|
-
"next",
|
|
484
|
-
"nuxt"
|
|
485
|
-
],
|
|
486
|
-
backend: [
|
|
487
|
-
"api",
|
|
488
|
-
"server",
|
|
489
|
-
"backend",
|
|
490
|
-
"service",
|
|
491
|
-
"worker",
|
|
492
|
-
"lambda",
|
|
493
|
-
"functions"
|
|
494
|
-
],
|
|
495
|
-
shared: ["shared", "common", "utils", "lib", "core", "types", "models"],
|
|
496
|
-
tooling: [
|
|
497
|
-
"scripts",
|
|
498
|
-
"tools",
|
|
499
|
-
"cli",
|
|
500
|
-
"devtools",
|
|
501
|
-
"build",
|
|
502
|
-
"config",
|
|
503
|
-
"infra"
|
|
504
|
-
],
|
|
505
|
-
unknown: []
|
|
506
|
-
};
|
|
507
|
-
});
|
|
508
|
-
|
|
509
|
-
// src/introspection/conventions/entryPoints.ts
|
|
510
|
-
import * as path3 from "path";
|
|
511
275
|
function getParentFolder(filepath) {
|
|
512
|
-
const dir =
|
|
513
|
-
return
|
|
276
|
+
const dir = path2.dirname(filepath);
|
|
277
|
+
return path2.basename(dir);
|
|
514
278
|
}
|
|
515
279
|
var entryPointConventions;
|
|
516
280
|
var init_entryPoints = __esm(() => {
|
|
@@ -595,11 +359,75 @@ var init_entryPoints = __esm(() => {
|
|
|
595
359
|
return filename === "lib.rs" || filename === "main.rs";
|
|
596
360
|
},
|
|
597
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"]
|
|
598
426
|
}
|
|
599
427
|
];
|
|
600
428
|
});
|
|
601
429
|
|
|
602
|
-
// src/
|
|
430
|
+
// src/domain/services/conventions/configFiles.ts
|
|
603
431
|
var configFileConventions;
|
|
604
432
|
var init_configFiles = __esm(() => {
|
|
605
433
|
configFileConventions = [
|
|
@@ -643,6 +471,157 @@ var init_configFiles = __esm(() => {
|
|
|
643
471
|
match: (filepath, filename) => filename === "bun.lockb" || filename === "bun.lock",
|
|
644
472
|
keywords: ["dependencies", "lock", "bun", "versions"]
|
|
645
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
|
+
},
|
|
646
625
|
{
|
|
647
626
|
id: "tsconfig",
|
|
648
627
|
name: "TypeScript Config",
|
|
@@ -884,7 +863,7 @@ var init_configFiles = __esm(() => {
|
|
|
884
863
|
];
|
|
885
864
|
});
|
|
886
865
|
|
|
887
|
-
// src/
|
|
866
|
+
// src/domain/services/conventions/frameworks/nextjs.ts
|
|
888
867
|
var nextjsConventions, nextjsFramework;
|
|
889
868
|
var init_nextjs = __esm(() => {
|
|
890
869
|
nextjsConventions = [
|
|
@@ -1049,7 +1028,7 @@ var init_nextjs = __esm(() => {
|
|
|
1049
1028
|
};
|
|
1050
1029
|
});
|
|
1051
1030
|
|
|
1052
|
-
// src/
|
|
1031
|
+
// src/domain/services/conventions/frameworks/convex.ts
|
|
1053
1032
|
var convexConventions, convexFramework;
|
|
1054
1033
|
var init_convex = __esm(() => {
|
|
1055
1034
|
convexConventions = [
|
|
@@ -1145,7 +1124,7 @@ var init_convex = __esm(() => {
|
|
|
1145
1124
|
};
|
|
1146
1125
|
});
|
|
1147
1126
|
|
|
1148
|
-
// src/
|
|
1127
|
+
// src/domain/services/conventions/frameworks/index.ts
|
|
1149
1128
|
function getAllFrameworkConventions() {
|
|
1150
1129
|
return frameworkProviders.flatMap((f) => f.conventions);
|
|
1151
1130
|
}
|
|
@@ -1161,26 +1140,21 @@ var init_frameworks = __esm(() => {
|
|
|
1161
1140
|
];
|
|
1162
1141
|
});
|
|
1163
1142
|
|
|
1164
|
-
// src/
|
|
1165
|
-
import * as
|
|
1166
|
-
function
|
|
1143
|
+
// src/domain/services/conventions/index.ts
|
|
1144
|
+
import * as path3 from "path";
|
|
1145
|
+
function getConventions() {
|
|
1167
1146
|
return [
|
|
1168
1147
|
...entryPointConventions,
|
|
1169
1148
|
...configFileConventions,
|
|
1170
|
-
...getAllFrameworkConventions()
|
|
1171
|
-
];
|
|
1172
|
-
}
|
|
1173
|
-
function getConventions() {
|
|
1174
|
-
return [
|
|
1175
|
-
...getAllConventions(),
|
|
1149
|
+
...getAllFrameworkConventions(),
|
|
1176
1150
|
...typeDefinitionConventions,
|
|
1177
1151
|
...testFileConventions
|
|
1178
1152
|
];
|
|
1179
1153
|
}
|
|
1180
1154
|
function getConventionKeywords(filepath) {
|
|
1181
1155
|
const conventions = getConventions();
|
|
1182
|
-
const filename =
|
|
1183
|
-
const extension =
|
|
1156
|
+
const filename = path3.basename(filepath);
|
|
1157
|
+
const extension = path3.extname(filepath);
|
|
1184
1158
|
const keywords = new Set;
|
|
1185
1159
|
for (const convention of conventions) {
|
|
1186
1160
|
try {
|
|
@@ -1227,9 +1201,8 @@ var init_conventions = __esm(() => {
|
|
|
1227
1201
|
keywords: ["types", "definitions", "typescript", "interfaces"],
|
|
1228
1202
|
dynamicKeywords: (filepath) => {
|
|
1229
1203
|
const match = filepath.match(/([^/]+)\.types\.ts$/);
|
|
1230
|
-
if (match)
|
|
1204
|
+
if (match)
|
|
1231
1205
|
return [match[1].toLowerCase()];
|
|
1232
|
-
}
|
|
1233
1206
|
return [];
|
|
1234
1207
|
}
|
|
1235
1208
|
},
|
|
@@ -1252,9 +1225,8 @@ var init_conventions = __esm(() => {
|
|
|
1252
1225
|
keywords: ["test", "spec", "unit test"],
|
|
1253
1226
|
dynamicKeywords: (filepath) => {
|
|
1254
1227
|
const match = filepath.match(/([^/]+)\.(test|spec)\./);
|
|
1255
|
-
if (match)
|
|
1228
|
+
if (match)
|
|
1256
1229
|
return [match[1].toLowerCase()];
|
|
1257
|
-
}
|
|
1258
1230
|
return [];
|
|
1259
1231
|
}
|
|
1260
1232
|
},
|
|
@@ -1269,22 +1241,19 @@ var init_conventions = __esm(() => {
|
|
|
1269
1241
|
];
|
|
1270
1242
|
});
|
|
1271
1243
|
|
|
1272
|
-
// src/introspection
|
|
1273
|
-
import * as
|
|
1244
|
+
// src/domain/services/introspection.ts
|
|
1245
|
+
import * as path4 from "path";
|
|
1274
1246
|
function introspectFile(filepath, structure, fileContent) {
|
|
1275
1247
|
const normalizedPath = filepath.replace(/\\/g, "/");
|
|
1276
1248
|
const segments = normalizedPath.split("/").filter((s) => s.length > 0);
|
|
1277
1249
|
const filename = segments[segments.length - 1] || "";
|
|
1278
|
-
const ext =
|
|
1250
|
+
const ext = path4.extname(filename);
|
|
1279
1251
|
const project = findProjectForFile(normalizedPath, structure);
|
|
1280
1252
|
const language = EXTENSION_TO_LANGUAGE[ext] || "unknown";
|
|
1281
1253
|
const layer = detectLayer(segments, filename);
|
|
1282
1254
|
const domain = detectDomain(segments);
|
|
1283
1255
|
const scope = detectScope(segments, project, layer);
|
|
1284
|
-
|
|
1285
|
-
if (fileContent) {
|
|
1286
|
-
framework = detectFramework(fileContent);
|
|
1287
|
-
}
|
|
1256
|
+
const framework = fileContent ? detectFramework(fileContent) : undefined;
|
|
1288
1257
|
return {
|
|
1289
1258
|
filepath: normalizedPath,
|
|
1290
1259
|
project,
|
|
@@ -1297,21 +1266,81 @@ function introspectFile(filepath, structure, fileContent) {
|
|
|
1297
1266
|
pathSegments: segments.slice(0, -1)
|
|
1298
1267
|
};
|
|
1299
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
|
+
}
|
|
1300
1331
|
function detectLayer(segments, filename) {
|
|
1301
1332
|
const filenameLower = filename.toLowerCase();
|
|
1302
1333
|
for (const [layer, patterns] of Object.entries(LAYER_PATTERNS)) {
|
|
1303
1334
|
for (const pattern of patterns) {
|
|
1304
|
-
if (filenameLower.includes(pattern))
|
|
1335
|
+
if (filenameLower.includes(pattern))
|
|
1305
1336
|
return layer;
|
|
1306
|
-
}
|
|
1307
1337
|
}
|
|
1308
1338
|
}
|
|
1309
1339
|
for (let i = segments.length - 2;i >= 0; i--) {
|
|
1310
1340
|
const segment = segments[i].toLowerCase();
|
|
1311
1341
|
for (const [layer, patterns] of Object.entries(LAYER_PATTERNS)) {
|
|
1312
|
-
if (patterns.includes(segment))
|
|
1342
|
+
if (patterns.includes(segment))
|
|
1313
1343
|
return layer;
|
|
1314
|
-
}
|
|
1315
1344
|
}
|
|
1316
1345
|
}
|
|
1317
1346
|
return;
|
|
@@ -1332,9 +1361,8 @@ function detectDomain(segments) {
|
|
|
1332
1361
|
const segmentLower = segment.toLowerCase();
|
|
1333
1362
|
if (skipSegments.has(segmentLower))
|
|
1334
1363
|
continue;
|
|
1335
|
-
if (DOMAIN_PATTERNS.includes(segmentLower))
|
|
1364
|
+
if (DOMAIN_PATTERNS.includes(segmentLower))
|
|
1336
1365
|
return segmentLower;
|
|
1337
|
-
}
|
|
1338
1366
|
for (const domain of DOMAIN_PATTERNS) {
|
|
1339
1367
|
if (segmentLower.startsWith(domain) || segmentLower.endsWith(domain)) {
|
|
1340
1368
|
return domain;
|
|
@@ -1345,9 +1373,8 @@ function detectDomain(segments) {
|
|
|
1345
1373
|
}
|
|
1346
1374
|
function detectScope(segments, project, layer) {
|
|
1347
1375
|
const projectScope = detectScopeFromName(project.name);
|
|
1348
|
-
if (projectScope !== "unknown")
|
|
1376
|
+
if (projectScope !== "unknown")
|
|
1349
1377
|
return projectScope;
|
|
1350
|
-
}
|
|
1351
1378
|
if (layer) {
|
|
1352
1379
|
switch (layer) {
|
|
1353
1380
|
case "controller":
|
|
@@ -1365,15 +1392,12 @@ function detectScope(segments, project, layer) {
|
|
|
1365
1392
|
}
|
|
1366
1393
|
for (const segment of segments) {
|
|
1367
1394
|
const segmentLower = segment.toLowerCase();
|
|
1368
|
-
if (["server", "api", "backend"].includes(segmentLower))
|
|
1395
|
+
if (["server", "api", "backend"].includes(segmentLower))
|
|
1369
1396
|
return "backend";
|
|
1370
|
-
|
|
1371
|
-
if (["client", "web", "frontend", "ui"].includes(segmentLower)) {
|
|
1397
|
+
if (["client", "web", "frontend", "ui"].includes(segmentLower))
|
|
1372
1398
|
return "frontend";
|
|
1373
|
-
|
|
1374
|
-
if (["shared", "common", "lib", "libs"].includes(segmentLower)) {
|
|
1399
|
+
if (["shared", "common", "lib", "libs"].includes(segmentLower))
|
|
1375
1400
|
return "shared";
|
|
1376
|
-
}
|
|
1377
1401
|
}
|
|
1378
1402
|
return "unknown";
|
|
1379
1403
|
}
|
|
@@ -1387,44 +1411,8 @@ function detectFramework(content) {
|
|
|
1387
1411
|
}
|
|
1388
1412
|
return;
|
|
1389
1413
|
}
|
|
1390
|
-
|
|
1391
|
-
|
|
1392
|
-
const filename = path5.basename(intro.filepath);
|
|
1393
|
-
const filenameWithoutExt = filename.replace(/\.[^.]+$/, "");
|
|
1394
|
-
const filenameParts = filenameWithoutExt.split(/[-_.]/).flatMap((part) => part.split(/(?=[A-Z])/)).map((part) => part.toLowerCase()).filter((part) => part.length > 1);
|
|
1395
|
-
keywords.push(...filenameParts);
|
|
1396
|
-
keywords.push(filenameWithoutExt.toLowerCase());
|
|
1397
|
-
if (intro.project.name && intro.project.name !== "root") {
|
|
1398
|
-
keywords.push(intro.project.name.toLowerCase());
|
|
1399
|
-
}
|
|
1400
|
-
if (intro.scope !== "unknown") {
|
|
1401
|
-
keywords.push(intro.scope);
|
|
1402
|
-
}
|
|
1403
|
-
if (intro.layer) {
|
|
1404
|
-
keywords.push(intro.layer);
|
|
1405
|
-
}
|
|
1406
|
-
if (intro.domain) {
|
|
1407
|
-
keywords.push(intro.domain);
|
|
1408
|
-
}
|
|
1409
|
-
if (intro.language !== "unknown") {
|
|
1410
|
-
keywords.push(intro.language);
|
|
1411
|
-
}
|
|
1412
|
-
if (intro.framework) {
|
|
1413
|
-
keywords.push(intro.framework);
|
|
1414
|
-
}
|
|
1415
|
-
const skipSegments = new Set(["src", "lib", "index"]);
|
|
1416
|
-
for (const segment of intro.pathSegments) {
|
|
1417
|
-
if (!skipSegments.has(segment.toLowerCase()) && segment.length > 2) {
|
|
1418
|
-
keywords.push(segment.toLowerCase());
|
|
1419
|
-
}
|
|
1420
|
-
}
|
|
1421
|
-
const conventionKeywords = getConventionKeywords(intro.filepath);
|
|
1422
|
-
keywords.push(...conventionKeywords);
|
|
1423
|
-
return [...new Set(keywords)];
|
|
1424
|
-
}
|
|
1425
|
-
var LAYER_PATTERNS, DOMAIN_PATTERNS, FRAMEWORK_INDICATORS, EXTENSION_TO_LANGUAGE;
|
|
1426
|
-
var init_fileIntrospector = __esm(() => {
|
|
1427
|
-
init_projectDetector();
|
|
1414
|
+
var LAYER_PATTERNS, DOMAIN_PATTERNS, FRAMEWORK_INDICATORS, EXTENSION_TO_LANGUAGE, SCOPE_KEYWORDS, PROJECT_PATTERNS;
|
|
1415
|
+
var init_introspection = __esm(() => {
|
|
1428
1416
|
init_conventions();
|
|
1429
1417
|
LAYER_PATTERNS = {
|
|
1430
1418
|
controller: ["controller", "api", "routes", "route", "handler"],
|
|
@@ -1543,120 +1531,45 @@ var init_fileIntrospector = __esm(() => {
|
|
|
1543
1531
|
".md": "markdown",
|
|
1544
1532
|
".json": "json",
|
|
1545
1533
|
".yaml": "yaml",
|
|
1546
|
-
".yml": "yaml"
|
|
1534
|
+
".yml": "yaml",
|
|
1535
|
+
".txt": "text"
|
|
1547
1536
|
};
|
|
1548
|
-
|
|
1549
|
-
|
|
1550
|
-
|
|
1551
|
-
|
|
1552
|
-
|
|
1553
|
-
|
|
1554
|
-
|
|
1555
|
-
|
|
1556
|
-
|
|
1557
|
-
|
|
1558
|
-
|
|
1559
|
-
|
|
1560
|
-
|
|
1561
|
-
|
|
1562
|
-
|
|
1563
|
-
|
|
1564
|
-
|
|
1565
|
-
|
|
1566
|
-
|
|
1567
|
-
|
|
1568
|
-
|
|
1569
|
-
|
|
1570
|
-
|
|
1571
|
-
|
|
1572
|
-
|
|
1573
|
-
|
|
1574
|
-
|
|
1575
|
-
|
|
1576
|
-
|
|
1577
|
-
}
|
|
1578
|
-
|
|
1579
|
-
|
|
1580
|
-
|
|
1581
|
-
|
|
1582
|
-
|
|
1583
|
-
|
|
1584
|
-
return this.files.get(filepath);
|
|
1585
|
-
}
|
|
1586
|
-
getAllFiles() {
|
|
1587
|
-
return Array.from(this.files.values());
|
|
1588
|
-
}
|
|
1589
|
-
applyOverrides(intro) {
|
|
1590
|
-
if (!this.config.projects)
|
|
1591
|
-
return;
|
|
1592
|
-
for (const [projectPath, overrides] of Object.entries(this.config.projects)) {
|
|
1593
|
-
if (intro.filepath.startsWith(projectPath + "/") || intro.project.root === projectPath) {
|
|
1594
|
-
if (overrides.scope) {
|
|
1595
|
-
intro.scope = overrides.scope;
|
|
1596
|
-
}
|
|
1597
|
-
if (overrides.framework) {
|
|
1598
|
-
intro.framework = overrides.framework;
|
|
1599
|
-
}
|
|
1600
|
-
break;
|
|
1601
|
-
}
|
|
1602
|
-
}
|
|
1603
|
-
}
|
|
1604
|
-
async save(config) {
|
|
1605
|
-
const introDir = path6.join(getRaggrepDir(this.rootDir, config), "introspection");
|
|
1606
|
-
await fs3.mkdir(introDir, { recursive: true });
|
|
1607
|
-
const projectPath = path6.join(introDir, "_project.json");
|
|
1608
|
-
await fs3.writeFile(projectPath, JSON.stringify({
|
|
1609
|
-
version: "1.0.0",
|
|
1610
|
-
lastUpdated: new Date().toISOString(),
|
|
1611
|
-
structure: this.structure
|
|
1612
|
-
}, null, 2));
|
|
1613
|
-
for (const [filepath, intro] of this.files) {
|
|
1614
|
-
const introFilePath = path6.join(introDir, "files", filepath.replace(/\.[^.]+$/, ".json"));
|
|
1615
|
-
await fs3.mkdir(path6.dirname(introFilePath), { recursive: true });
|
|
1616
|
-
await fs3.writeFile(introFilePath, JSON.stringify(intro, null, 2));
|
|
1617
|
-
}
|
|
1618
|
-
console.log(` [Introspection] Saved metadata for ${this.files.size} files`);
|
|
1619
|
-
}
|
|
1620
|
-
async load(config) {
|
|
1621
|
-
const introDir = path6.join(getRaggrepDir(this.rootDir, config), "introspection");
|
|
1622
|
-
try {
|
|
1623
|
-
const projectPath = path6.join(introDir, "_project.json");
|
|
1624
|
-
const projectContent = await fs3.readFile(projectPath, "utf-8");
|
|
1625
|
-
const projectData = JSON.parse(projectContent);
|
|
1626
|
-
this.structure = projectData.structure;
|
|
1627
|
-
await this.loadFilesRecursive(path6.join(introDir, "files"), "");
|
|
1628
|
-
} catch {
|
|
1629
|
-
this.structure = null;
|
|
1630
|
-
this.files.clear();
|
|
1631
|
-
}
|
|
1632
|
-
}
|
|
1633
|
-
async loadFilesRecursive(basePath, prefix) {
|
|
1634
|
-
try {
|
|
1635
|
-
const entries = await fs3.readdir(basePath, { withFileTypes: true });
|
|
1636
|
-
for (const entry of entries) {
|
|
1637
|
-
const entryPath = path6.join(basePath, entry.name);
|
|
1638
|
-
const relativePath = prefix ? `${prefix}/${entry.name}` : entry.name;
|
|
1639
|
-
if (entry.isDirectory()) {
|
|
1640
|
-
await this.loadFilesRecursive(entryPath, relativePath);
|
|
1641
|
-
} else if (entry.name.endsWith(".json")) {
|
|
1642
|
-
const content = await fs3.readFile(entryPath, "utf-8");
|
|
1643
|
-
const intro = JSON.parse(content);
|
|
1644
|
-
this.files.set(intro.filepath, intro);
|
|
1645
|
-
}
|
|
1646
|
-
}
|
|
1647
|
-
} catch {}
|
|
1648
|
-
}
|
|
1649
|
-
clear() {
|
|
1650
|
-
this.files.clear();
|
|
1651
|
-
this.structure = null;
|
|
1652
|
-
}
|
|
1653
|
-
}
|
|
1654
|
-
var init_introspection = __esm(() => {
|
|
1655
|
-
init_projectDetector();
|
|
1656
|
-
init_fileIntrospector();
|
|
1657
|
-
init_config2();
|
|
1658
|
-
init_fileIntrospector();
|
|
1659
|
-
init_projectDetector();
|
|
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
|
+
];
|
|
1660
1573
|
});
|
|
1661
1574
|
|
|
1662
1575
|
// src/modules/core/symbols.ts
|
|
@@ -1826,8 +1739,8 @@ var exports_core = {};
|
|
|
1826
1739
|
__export(exports_core, {
|
|
1827
1740
|
CoreModule: () => CoreModule
|
|
1828
1741
|
});
|
|
1829
|
-
import * as
|
|
1830
|
-
import * as
|
|
1742
|
+
import * as path5 from "path";
|
|
1743
|
+
import * as fs2 from "fs/promises";
|
|
1831
1744
|
|
|
1832
1745
|
class CoreModule {
|
|
1833
1746
|
id = "core";
|
|
@@ -1845,7 +1758,9 @@ class CoreModule {
|
|
|
1845
1758
|
const contentTokens = tokenize(content);
|
|
1846
1759
|
const intro = ctx.getIntrospection?.(filepath);
|
|
1847
1760
|
const introKeywords = intro ? introspectionToKeywords(intro) : [];
|
|
1848
|
-
const allTokens = [
|
|
1761
|
+
const allTokens = [
|
|
1762
|
+
...new Set([...contentTokens, ...symbolKeywords, ...introKeywords])
|
|
1763
|
+
];
|
|
1849
1764
|
const chunks = this.createChunks(filepath, content, symbols);
|
|
1850
1765
|
const stats = await ctx.getFileStats(filepath);
|
|
1851
1766
|
this.symbolIndex.set(filepath, {
|
|
@@ -1919,8 +1834,8 @@ class CoreModule {
|
|
|
1919
1834
|
}
|
|
1920
1835
|
async finalize(ctx) {
|
|
1921
1836
|
const config = ctx.config;
|
|
1922
|
-
const coreDir =
|
|
1923
|
-
await
|
|
1837
|
+
const coreDir = path5.join(getRaggrepDir(ctx.rootDir, config), "index", "core");
|
|
1838
|
+
await fs2.mkdir(coreDir, { recursive: true });
|
|
1924
1839
|
this.bm25Index = new BM25Index;
|
|
1925
1840
|
for (const [filepath, entry] of this.symbolIndex) {
|
|
1926
1841
|
this.bm25Index.addDocument(filepath, entry.tokens);
|
|
@@ -1931,7 +1846,7 @@ class CoreModule {
|
|
|
1931
1846
|
files: Object.fromEntries(this.symbolIndex),
|
|
1932
1847
|
bm25Data: this.bm25Index.serialize()
|
|
1933
1848
|
};
|
|
1934
|
-
await
|
|
1849
|
+
await fs2.writeFile(path5.join(coreDir, "symbols.json"), JSON.stringify(symbolIndexData, null, 2));
|
|
1935
1850
|
console.log(` [Core] Symbol index built with ${this.symbolIndex.size} files`);
|
|
1936
1851
|
}
|
|
1937
1852
|
async search(query, ctx, options) {
|
|
@@ -2028,10 +1943,10 @@ class CoreModule {
|
|
|
2028
1943
|
return bestChunk;
|
|
2029
1944
|
}
|
|
2030
1945
|
async loadSymbolIndex(rootDir, config) {
|
|
2031
|
-
const coreDir =
|
|
2032
|
-
const symbolsPath =
|
|
1946
|
+
const coreDir = path5.join(getRaggrepDir(rootDir, config), "index", "core");
|
|
1947
|
+
const symbolsPath = path5.join(coreDir, "symbols.json");
|
|
2033
1948
|
try {
|
|
2034
|
-
const content = await
|
|
1949
|
+
const content = await fs2.readFile(symbolsPath, "utf-8");
|
|
2035
1950
|
const data = JSON.parse(content);
|
|
2036
1951
|
this.symbolIndex = new Map(Object.entries(data.files));
|
|
2037
1952
|
if (data.bm25Data) {
|
|
@@ -2056,7 +1971,7 @@ var init_core = __esm(() => {
|
|
|
2056
1971
|
|
|
2057
1972
|
// src/infrastructure/embeddings/transformersEmbedding.ts
|
|
2058
1973
|
import { pipeline, env } from "@xenova/transformers";
|
|
2059
|
-
import * as
|
|
1974
|
+
import * as path6 from "path";
|
|
2060
1975
|
import * as os2 from "os";
|
|
2061
1976
|
|
|
2062
1977
|
class TransformersEmbeddingProvider {
|
|
@@ -2189,7 +2104,7 @@ async function getEmbeddings(texts) {
|
|
|
2189
2104
|
}
|
|
2190
2105
|
var CACHE_DIR, EMBEDDING_MODELS2, EMBEDDING_DIMENSION = 384, BATCH_SIZE = 32, globalProvider = null, globalConfig;
|
|
2191
2106
|
var init_transformersEmbedding = __esm(() => {
|
|
2192
|
-
CACHE_DIR =
|
|
2107
|
+
CACHE_DIR = path6.join(os2.homedir(), ".cache", "raggrep", "models");
|
|
2193
2108
|
env.cacheDir = CACHE_DIR;
|
|
2194
2109
|
env.allowLocalModels = true;
|
|
2195
2110
|
EMBEDDING_MODELS2 = {
|
|
@@ -2613,8 +2528,8 @@ var init_keywords = __esm(() => {
|
|
|
2613
2528
|
});
|
|
2614
2529
|
|
|
2615
2530
|
// src/infrastructure/storage/symbolicIndex.ts
|
|
2616
|
-
import * as
|
|
2617
|
-
import * as
|
|
2531
|
+
import * as fs3 from "fs/promises";
|
|
2532
|
+
import * as path7 from "path";
|
|
2618
2533
|
|
|
2619
2534
|
class SymbolicIndex {
|
|
2620
2535
|
meta = null;
|
|
@@ -2623,7 +2538,7 @@ class SymbolicIndex {
|
|
|
2623
2538
|
symbolicPath;
|
|
2624
2539
|
moduleId;
|
|
2625
2540
|
constructor(indexDir, moduleId) {
|
|
2626
|
-
this.symbolicPath =
|
|
2541
|
+
this.symbolicPath = path7.join(indexDir, "index", moduleId, "symbolic");
|
|
2627
2542
|
this.moduleId = moduleId;
|
|
2628
2543
|
}
|
|
2629
2544
|
async initialize() {
|
|
@@ -2683,18 +2598,18 @@ class SymbolicIndex {
|
|
|
2683
2598
|
throw new Error("Index not initialized");
|
|
2684
2599
|
this.meta.lastUpdated = new Date().toISOString();
|
|
2685
2600
|
this.meta.fileCount = this.fileSummaries.size;
|
|
2686
|
-
await
|
|
2687
|
-
const metaPath =
|
|
2688
|
-
await
|
|
2601
|
+
await fs3.mkdir(this.symbolicPath, { recursive: true });
|
|
2602
|
+
const metaPath = path7.join(this.symbolicPath, "_meta.json");
|
|
2603
|
+
await fs3.writeFile(metaPath, JSON.stringify(this.meta, null, 2));
|
|
2689
2604
|
for (const [filepath, summary] of this.fileSummaries) {
|
|
2690
2605
|
const summaryPath = this.getFileSummaryPath(filepath);
|
|
2691
|
-
await
|
|
2692
|
-
await
|
|
2606
|
+
await fs3.mkdir(path7.dirname(summaryPath), { recursive: true });
|
|
2607
|
+
await fs3.writeFile(summaryPath, JSON.stringify(summary, null, 2));
|
|
2693
2608
|
}
|
|
2694
2609
|
}
|
|
2695
2610
|
async load() {
|
|
2696
|
-
const metaPath =
|
|
2697
|
-
const metaContent = await
|
|
2611
|
+
const metaPath = path7.join(this.symbolicPath, "_meta.json");
|
|
2612
|
+
const metaContent = await fs3.readFile(metaPath, "utf-8");
|
|
2698
2613
|
this.meta = JSON.parse(metaContent);
|
|
2699
2614
|
this.fileSummaries.clear();
|
|
2700
2615
|
await this.loadFileSummariesRecursive(this.symbolicPath);
|
|
@@ -2702,14 +2617,14 @@ class SymbolicIndex {
|
|
|
2702
2617
|
}
|
|
2703
2618
|
async loadFileSummariesRecursive(dir) {
|
|
2704
2619
|
try {
|
|
2705
|
-
const entries = await
|
|
2620
|
+
const entries = await fs3.readdir(dir, { withFileTypes: true });
|
|
2706
2621
|
for (const entry of entries) {
|
|
2707
|
-
const fullPath =
|
|
2622
|
+
const fullPath = path7.join(dir, entry.name);
|
|
2708
2623
|
if (entry.isDirectory()) {
|
|
2709
2624
|
await this.loadFileSummariesRecursive(fullPath);
|
|
2710
2625
|
} else if (entry.name.endsWith(".json") && entry.name !== "_meta.json") {
|
|
2711
2626
|
try {
|
|
2712
|
-
const content = await
|
|
2627
|
+
const content = await fs3.readFile(fullPath, "utf-8");
|
|
2713
2628
|
const summary = JSON.parse(content);
|
|
2714
2629
|
if (summary.filepath) {
|
|
2715
2630
|
this.fileSummaries.set(summary.filepath, summary);
|
|
@@ -2721,18 +2636,18 @@ class SymbolicIndex {
|
|
|
2721
2636
|
}
|
|
2722
2637
|
getFileSummaryPath(filepath) {
|
|
2723
2638
|
const jsonPath = filepath.replace(/\.[^.]+$/, ".json");
|
|
2724
|
-
return
|
|
2639
|
+
return path7.join(this.symbolicPath, jsonPath);
|
|
2725
2640
|
}
|
|
2726
2641
|
async deleteFileSummary(filepath) {
|
|
2727
2642
|
try {
|
|
2728
|
-
await
|
|
2643
|
+
await fs3.unlink(this.getFileSummaryPath(filepath));
|
|
2729
2644
|
} catch {}
|
|
2730
2645
|
this.fileSummaries.delete(filepath);
|
|
2731
2646
|
}
|
|
2732
2647
|
async exists() {
|
|
2733
2648
|
try {
|
|
2734
|
-
const metaPath =
|
|
2735
|
-
await
|
|
2649
|
+
const metaPath = path7.join(this.symbolicPath, "_meta.json");
|
|
2650
|
+
await fs3.access(metaPath);
|
|
2736
2651
|
return true;
|
|
2737
2652
|
} catch {
|
|
2738
2653
|
return false;
|
|
@@ -2771,7 +2686,7 @@ __export(exports_typescript, {
|
|
|
2771
2686
|
DEFAULT_TOP_K: () => DEFAULT_TOP_K2,
|
|
2772
2687
|
DEFAULT_MIN_SCORE: () => DEFAULT_MIN_SCORE2
|
|
2773
2688
|
});
|
|
2774
|
-
import * as
|
|
2689
|
+
import * as path8 from "path";
|
|
2775
2690
|
|
|
2776
2691
|
class TypeScriptModule {
|
|
2777
2692
|
id = "language/typescript";
|
|
@@ -2965,16 +2880,16 @@ class TypeScriptModule {
|
|
|
2965
2880
|
while ((match = importRegex.exec(content)) !== null) {
|
|
2966
2881
|
const importPath = match[1];
|
|
2967
2882
|
if (importPath.startsWith(".")) {
|
|
2968
|
-
const dir =
|
|
2969
|
-
const resolved =
|
|
2883
|
+
const dir = path8.dirname(filepath);
|
|
2884
|
+
const resolved = path8.normalize(path8.join(dir, importPath));
|
|
2970
2885
|
references.push(resolved);
|
|
2971
2886
|
}
|
|
2972
2887
|
}
|
|
2973
2888
|
while ((match = requireRegex.exec(content)) !== null) {
|
|
2974
2889
|
const importPath = match[1];
|
|
2975
2890
|
if (importPath.startsWith(".")) {
|
|
2976
|
-
const dir =
|
|
2977
|
-
const resolved =
|
|
2891
|
+
const dir = path8.dirname(filepath);
|
|
2892
|
+
const resolved = path8.normalize(path8.join(dir, importPath));
|
|
2978
2893
|
references.push(resolved);
|
|
2979
2894
|
}
|
|
2980
2895
|
}
|
|
@@ -3025,20 +2940,275 @@ async function registerBuiltInModules() {
|
|
|
3025
2940
|
registry.register(new TypeScriptModule2);
|
|
3026
2941
|
}
|
|
3027
2942
|
|
|
3028
|
-
// src/
|
|
2943
|
+
// src/infrastructure/introspection/IntrospectionIndex.ts
|
|
2944
|
+
import * as path10 from "path";
|
|
2945
|
+
import * as fs5 from "fs/promises";
|
|
2946
|
+
|
|
2947
|
+
// src/infrastructure/introspection/projectDetector.ts
|
|
2948
|
+
import * as path9 from "path";
|
|
2949
|
+
import * as fs4 from "fs/promises";
|
|
2950
|
+
var MAX_SCAN_DEPTH = 4;
|
|
2951
|
+
var SKIP_DIRS = new Set([
|
|
2952
|
+
"node_modules",
|
|
2953
|
+
".git",
|
|
2954
|
+
"dist",
|
|
2955
|
+
"build",
|
|
2956
|
+
".next",
|
|
2957
|
+
".nuxt",
|
|
2958
|
+
"coverage",
|
|
2959
|
+
".raggrep"
|
|
2960
|
+
]);
|
|
2961
|
+
async function scanForPackageJsons(rootDir, currentDir = "", depth = 0) {
|
|
2962
|
+
if (depth > MAX_SCAN_DEPTH)
|
|
2963
|
+
return [];
|
|
2964
|
+
const results = [];
|
|
2965
|
+
const fullDir = currentDir ? path9.join(rootDir, currentDir) : rootDir;
|
|
2966
|
+
try {
|
|
2967
|
+
const entries = await fs4.readdir(fullDir, { withFileTypes: true });
|
|
2968
|
+
const hasPackageJson = entries.some((e) => e.isFile() && e.name === "package.json");
|
|
2969
|
+
if (hasPackageJson && currentDir) {
|
|
2970
|
+
const info = await parsePackageJson(rootDir, currentDir);
|
|
2971
|
+
if (info)
|
|
2972
|
+
results.push(info);
|
|
2973
|
+
}
|
|
2974
|
+
for (const entry of entries) {
|
|
2975
|
+
if (!entry.isDirectory())
|
|
2976
|
+
continue;
|
|
2977
|
+
if (SKIP_DIRS.has(entry.name))
|
|
2978
|
+
continue;
|
|
2979
|
+
const subPath = currentDir ? `${currentDir}/${entry.name}` : entry.name;
|
|
2980
|
+
const subResults = await scanForPackageJsons(rootDir, subPath, depth + 1);
|
|
2981
|
+
results.push(...subResults);
|
|
2982
|
+
}
|
|
2983
|
+
} catch {}
|
|
2984
|
+
return results;
|
|
2985
|
+
}
|
|
2986
|
+
async function parsePackageJson(rootDir, relativePath) {
|
|
2987
|
+
try {
|
|
2988
|
+
const packageJsonPath = path9.join(rootDir, relativePath, "package.json");
|
|
2989
|
+
const content = await fs4.readFile(packageJsonPath, "utf-8");
|
|
2990
|
+
const pkg = JSON.parse(content);
|
|
2991
|
+
const name = pkg.name || path9.basename(relativePath);
|
|
2992
|
+
const deps = { ...pkg.dependencies, ...pkg.devDependencies };
|
|
2993
|
+
let type = "unknown";
|
|
2994
|
+
if (deps["next"] || deps["react"] || deps["vue"] || deps["svelte"]) {
|
|
2995
|
+
type = "app";
|
|
2996
|
+
} else if (deps["express"] || deps["fastify"] || deps["koa"] || deps["hono"]) {
|
|
2997
|
+
type = "service";
|
|
2998
|
+
} else if (pkg.main || pkg.exports) {
|
|
2999
|
+
type = "library";
|
|
3000
|
+
}
|
|
3001
|
+
const hasWorkspaces = Boolean(pkg.workspaces);
|
|
3002
|
+
return { name, relativePath, type, hasWorkspaces };
|
|
3003
|
+
} catch {
|
|
3004
|
+
return null;
|
|
3005
|
+
}
|
|
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
|
+
}
|
|
3023
|
+
async function detectProjectStructure(rootDir) {
|
|
3024
|
+
const projectMap = new Map;
|
|
3025
|
+
let isMonorepo = false;
|
|
3026
|
+
try {
|
|
3027
|
+
const entries = await fs4.readdir(rootDir, { withFileTypes: true });
|
|
3028
|
+
const dirNames = entries.filter((e) => e.isDirectory()).map((e) => e.name);
|
|
3029
|
+
const monorepoPatterns = ["apps", "packages", "libs", "services"];
|
|
3030
|
+
const hasMonorepoStructure = monorepoPatterns.some((p) => dirNames.includes(p));
|
|
3031
|
+
if (hasMonorepoStructure) {
|
|
3032
|
+
isMonorepo = true;
|
|
3033
|
+
for (const pattern of monorepoPatterns) {
|
|
3034
|
+
if (!dirNames.includes(pattern))
|
|
3035
|
+
continue;
|
|
3036
|
+
const patternDir = path9.join(rootDir, pattern);
|
|
3037
|
+
try {
|
|
3038
|
+
const subDirs = await fs4.readdir(patternDir, { withFileTypes: true });
|
|
3039
|
+
for (const subDir of subDirs) {
|
|
3040
|
+
if (!subDir.isDirectory())
|
|
3041
|
+
continue;
|
|
3042
|
+
const projectRoot = `${pattern}/${subDir.name}`;
|
|
3043
|
+
const type = getProjectType(pattern);
|
|
3044
|
+
projectMap.set(projectRoot, {
|
|
3045
|
+
name: subDir.name,
|
|
3046
|
+
root: projectRoot,
|
|
3047
|
+
type
|
|
3048
|
+
});
|
|
3049
|
+
}
|
|
3050
|
+
} catch {}
|
|
3051
|
+
}
|
|
3052
|
+
}
|
|
3053
|
+
const packageJsons = await scanForPackageJsons(rootDir);
|
|
3054
|
+
for (const pkg of packageJsons) {
|
|
3055
|
+
if (pkg.hasWorkspaces)
|
|
3056
|
+
isMonorepo = true;
|
|
3057
|
+
if (packageJsons.length > 1)
|
|
3058
|
+
isMonorepo = true;
|
|
3059
|
+
projectMap.set(pkg.relativePath, {
|
|
3060
|
+
name: pkg.name,
|
|
3061
|
+
root: pkg.relativePath,
|
|
3062
|
+
type: pkg.type
|
|
3063
|
+
});
|
|
3064
|
+
}
|
|
3065
|
+
let rootType = "unknown";
|
|
3066
|
+
try {
|
|
3067
|
+
const rootPkgPath = path9.join(rootDir, "package.json");
|
|
3068
|
+
const rootPkg = JSON.parse(await fs4.readFile(rootPkgPath, "utf-8"));
|
|
3069
|
+
if (rootPkg.workspaces)
|
|
3070
|
+
isMonorepo = true;
|
|
3071
|
+
const deps = { ...rootPkg.dependencies, ...rootPkg.devDependencies };
|
|
3072
|
+
if (deps["next"] || deps["react"] || deps["vue"]) {
|
|
3073
|
+
rootType = "app";
|
|
3074
|
+
} else if (deps["express"] || deps["fastify"] || deps["koa"]) {
|
|
3075
|
+
rootType = "service";
|
|
3076
|
+
}
|
|
3077
|
+
} catch {}
|
|
3078
|
+
const projects = Array.from(projectMap.values()).sort((a, b) => a.root.length - b.root.length);
|
|
3079
|
+
return {
|
|
3080
|
+
projects,
|
|
3081
|
+
isMonorepo,
|
|
3082
|
+
rootType: isMonorepo ? undefined : rootType
|
|
3083
|
+
};
|
|
3084
|
+
} catch {
|
|
3085
|
+
return {
|
|
3086
|
+
projects: [],
|
|
3087
|
+
isMonorepo: false,
|
|
3088
|
+
rootType: "unknown"
|
|
3089
|
+
};
|
|
3090
|
+
}
|
|
3091
|
+
}
|
|
3092
|
+
|
|
3093
|
+
// src/infrastructure/introspection/IntrospectionIndex.ts
|
|
3029
3094
|
init_introspection();
|
|
3095
|
+
init_config2();
|
|
3030
3096
|
|
|
3097
|
+
class IntrospectionIndex {
|
|
3098
|
+
rootDir;
|
|
3099
|
+
structure = null;
|
|
3100
|
+
files = new Map;
|
|
3101
|
+
config = {};
|
|
3102
|
+
constructor(rootDir) {
|
|
3103
|
+
this.rootDir = rootDir;
|
|
3104
|
+
}
|
|
3105
|
+
async initialize() {
|
|
3106
|
+
this.structure = await detectProjectStructure(this.rootDir);
|
|
3107
|
+
try {
|
|
3108
|
+
const configPath = path10.join(this.rootDir, ".raggrep", "config.json");
|
|
3109
|
+
const configContent = await fs5.readFile(configPath, "utf-8");
|
|
3110
|
+
const config = JSON.parse(configContent);
|
|
3111
|
+
this.config = config.introspection || {};
|
|
3112
|
+
} catch {}
|
|
3113
|
+
}
|
|
3114
|
+
getStructure() {
|
|
3115
|
+
return this.structure;
|
|
3116
|
+
}
|
|
3117
|
+
addFile(filepath, content) {
|
|
3118
|
+
if (!this.structure) {
|
|
3119
|
+
throw new Error("IntrospectionIndex not initialized");
|
|
3120
|
+
}
|
|
3121
|
+
const intro = introspectFile(filepath, this.structure, content);
|
|
3122
|
+
this.applyOverrides(intro);
|
|
3123
|
+
this.files.set(filepath, intro);
|
|
3124
|
+
return intro;
|
|
3125
|
+
}
|
|
3126
|
+
getFile(filepath) {
|
|
3127
|
+
return this.files.get(filepath);
|
|
3128
|
+
}
|
|
3129
|
+
getAllFiles() {
|
|
3130
|
+
return Array.from(this.files.values());
|
|
3131
|
+
}
|
|
3132
|
+
applyOverrides(intro) {
|
|
3133
|
+
if (!this.config.projects)
|
|
3134
|
+
return;
|
|
3135
|
+
for (const [projectPath, overrides] of Object.entries(this.config.projects)) {
|
|
3136
|
+
if (intro.filepath.startsWith(projectPath + "/") || intro.project.root === projectPath) {
|
|
3137
|
+
if (overrides.scope) {
|
|
3138
|
+
intro.scope = overrides.scope;
|
|
3139
|
+
}
|
|
3140
|
+
if (overrides.framework) {
|
|
3141
|
+
intro.framework = overrides.framework;
|
|
3142
|
+
}
|
|
3143
|
+
break;
|
|
3144
|
+
}
|
|
3145
|
+
}
|
|
3146
|
+
}
|
|
3147
|
+
async save(config) {
|
|
3148
|
+
const introDir = path10.join(getRaggrepDir(this.rootDir, config), "introspection");
|
|
3149
|
+
await fs5.mkdir(introDir, { recursive: true });
|
|
3150
|
+
const projectPath = path10.join(introDir, "_project.json");
|
|
3151
|
+
await fs5.writeFile(projectPath, JSON.stringify({
|
|
3152
|
+
version: "1.0.0",
|
|
3153
|
+
lastUpdated: new Date().toISOString(),
|
|
3154
|
+
structure: this.structure
|
|
3155
|
+
}, null, 2));
|
|
3156
|
+
for (const [filepath, intro] of this.files) {
|
|
3157
|
+
const introFilePath = path10.join(introDir, "files", filepath.replace(/\.[^.]+$/, ".json"));
|
|
3158
|
+
await fs5.mkdir(path10.dirname(introFilePath), { recursive: true });
|
|
3159
|
+
await fs5.writeFile(introFilePath, JSON.stringify(intro, null, 2));
|
|
3160
|
+
}
|
|
3161
|
+
console.log(` [Introspection] Saved metadata for ${this.files.size} files`);
|
|
3162
|
+
}
|
|
3163
|
+
async load(config) {
|
|
3164
|
+
const introDir = path10.join(getRaggrepDir(this.rootDir, config), "introspection");
|
|
3165
|
+
try {
|
|
3166
|
+
const projectPath = path10.join(introDir, "_project.json");
|
|
3167
|
+
const projectContent = await fs5.readFile(projectPath, "utf-8");
|
|
3168
|
+
const projectData = JSON.parse(projectContent);
|
|
3169
|
+
this.structure = projectData.structure;
|
|
3170
|
+
await this.loadFilesRecursive(path10.join(introDir, "files"), "");
|
|
3171
|
+
} catch {
|
|
3172
|
+
this.structure = null;
|
|
3173
|
+
this.files.clear();
|
|
3174
|
+
}
|
|
3175
|
+
}
|
|
3176
|
+
async loadFilesRecursive(basePath, prefix) {
|
|
3177
|
+
try {
|
|
3178
|
+
const entries = await fs5.readdir(basePath, { withFileTypes: true });
|
|
3179
|
+
for (const entry of entries) {
|
|
3180
|
+
const entryPath = path10.join(basePath, entry.name);
|
|
3181
|
+
const relativePath = prefix ? `${prefix}/${entry.name}` : entry.name;
|
|
3182
|
+
if (entry.isDirectory()) {
|
|
3183
|
+
await this.loadFilesRecursive(entryPath, relativePath);
|
|
3184
|
+
} else if (entry.name.endsWith(".json")) {
|
|
3185
|
+
const content = await fs5.readFile(entryPath, "utf-8");
|
|
3186
|
+
const intro = JSON.parse(content);
|
|
3187
|
+
this.files.set(intro.filepath, intro);
|
|
3188
|
+
}
|
|
3189
|
+
}
|
|
3190
|
+
} catch {}
|
|
3191
|
+
}
|
|
3192
|
+
clear() {
|
|
3193
|
+
this.files.clear();
|
|
3194
|
+
this.structure = null;
|
|
3195
|
+
}
|
|
3196
|
+
}
|
|
3031
3197
|
// src/app/indexer/watcher.ts
|
|
3032
3198
|
import { watch } from "chokidar";
|
|
3033
3199
|
init_config2();
|
|
3034
3200
|
|
|
3035
3201
|
// src/app/indexer/index.ts
|
|
3202
|
+
var INDEX_SCHEMA_VERSION = "1.0.0";
|
|
3036
3203
|
async function indexDirectory(rootDir, options = {}) {
|
|
3037
3204
|
const verbose = options.verbose ?? false;
|
|
3205
|
+
const quiet = options.quiet ?? false;
|
|
3038
3206
|
rootDir = path11.resolve(rootDir);
|
|
3039
3207
|
const location = getIndexLocation(rootDir);
|
|
3040
|
-
|
|
3041
|
-
|
|
3208
|
+
if (!quiet) {
|
|
3209
|
+
console.log(`Indexing directory: ${rootDir}`);
|
|
3210
|
+
console.log(`Index location: ${location.indexDir}`);
|
|
3211
|
+
}
|
|
3042
3212
|
const config = await loadConfig(rootDir);
|
|
3043
3213
|
const introspection = new IntrospectionIndex(rootDir);
|
|
3044
3214
|
await introspection.initialize();
|
|
@@ -3051,16 +3221,24 @@ async function indexDirectory(rootDir, options = {}) {
|
|
|
3051
3221
|
await registerBuiltInModules();
|
|
3052
3222
|
const enabledModules = registry.getEnabled(config);
|
|
3053
3223
|
if (enabledModules.length === 0) {
|
|
3054
|
-
|
|
3224
|
+
if (!quiet) {
|
|
3225
|
+
console.log("No modules enabled. Check your configuration.");
|
|
3226
|
+
}
|
|
3055
3227
|
return [];
|
|
3056
3228
|
}
|
|
3057
|
-
|
|
3229
|
+
if (!quiet) {
|
|
3230
|
+
console.log(`Enabled modules: ${enabledModules.map((m) => m.id).join(", ")}`);
|
|
3231
|
+
}
|
|
3058
3232
|
const files = await findFiles(rootDir, config);
|
|
3059
|
-
|
|
3233
|
+
if (!quiet) {
|
|
3234
|
+
console.log(`Found ${files.length} files to index`);
|
|
3235
|
+
}
|
|
3060
3236
|
const results = [];
|
|
3061
3237
|
for (const module of enabledModules) {
|
|
3062
|
-
|
|
3238
|
+
if (!quiet) {
|
|
3239
|
+
console.log(`
|
|
3063
3240
|
[${module.name}] Starting indexing...`);
|
|
3241
|
+
}
|
|
3064
3242
|
const moduleConfig = getModuleConfig(config, module.id);
|
|
3065
3243
|
if (module.initialize && moduleConfig) {
|
|
3066
3244
|
const configWithOverrides = { ...moduleConfig };
|
|
@@ -3075,7 +3253,9 @@ async function indexDirectory(rootDir, options = {}) {
|
|
|
3075
3253
|
const result = await indexWithModule(rootDir, files, module, config, verbose, introspection);
|
|
3076
3254
|
results.push(result);
|
|
3077
3255
|
if (module.finalize) {
|
|
3078
|
-
|
|
3256
|
+
if (!quiet) {
|
|
3257
|
+
console.log(`[${module.name}] Building secondary indexes...`);
|
|
3258
|
+
}
|
|
3079
3259
|
const ctx = {
|
|
3080
3260
|
rootDir,
|
|
3081
3261
|
config,
|
|
@@ -3091,7 +3271,9 @@ async function indexDirectory(rootDir, options = {}) {
|
|
|
3091
3271
|
};
|
|
3092
3272
|
await module.finalize(ctx);
|
|
3093
3273
|
}
|
|
3094
|
-
|
|
3274
|
+
if (!quiet) {
|
|
3275
|
+
console.log(`[${module.name}] Complete: ${result.indexed} indexed, ${result.skipped} skipped, ${result.errors} errors`);
|
|
3276
|
+
}
|
|
3095
3277
|
}
|
|
3096
3278
|
await introspection.save(config);
|
|
3097
3279
|
await updateGlobalManifest(rootDir, enabledModules, config);
|
|
@@ -3202,7 +3384,7 @@ async function writeFileIndex(rootDir, moduleId, filepath, fileIndex, config) {
|
|
|
3202
3384
|
async function updateGlobalManifest(rootDir, modules, config) {
|
|
3203
3385
|
const manifestPath = getGlobalManifestPath(rootDir, config);
|
|
3204
3386
|
const manifest = {
|
|
3205
|
-
version:
|
|
3387
|
+
version: INDEX_SCHEMA_VERSION,
|
|
3206
3388
|
lastUpdated: new Date().toISOString(),
|
|
3207
3389
|
modules: modules.map((m) => m.id)
|
|
3208
3390
|
};
|
|
@@ -3372,6 +3554,20 @@ async function loadGlobalManifest(rootDir, config) {
|
|
|
3372
3554
|
return null;
|
|
3373
3555
|
}
|
|
3374
3556
|
}
|
|
3557
|
+
function formatModuleName(moduleId) {
|
|
3558
|
+
switch (moduleId) {
|
|
3559
|
+
case "core":
|
|
3560
|
+
return "Core";
|
|
3561
|
+
case "language/typescript":
|
|
3562
|
+
return "TypeScript";
|
|
3563
|
+
default:
|
|
3564
|
+
if (moduleId.startsWith("language/")) {
|
|
3565
|
+
const lang = moduleId.replace("language/", "");
|
|
3566
|
+
return lang.charAt(0).toUpperCase() + lang.slice(1);
|
|
3567
|
+
}
|
|
3568
|
+
return moduleId;
|
|
3569
|
+
}
|
|
3570
|
+
}
|
|
3375
3571
|
function formatSearchResults(results) {
|
|
3376
3572
|
if (results.length === 0) {
|
|
3377
3573
|
return "No results found.";
|
|
@@ -3387,6 +3583,7 @@ function formatSearchResults(results) {
|
|
|
3387
3583
|
output += `${i + 1}. ${location}${nameInfo}
|
|
3388
3584
|
`;
|
|
3389
3585
|
output += ` Score: ${(result.score * 100).toFixed(1)}% | Type: ${chunk.type}`;
|
|
3586
|
+
output += ` | via ${formatModuleName(result.moduleId)}`;
|
|
3390
3587
|
if (chunk.isExported) {
|
|
3391
3588
|
output += " | exported";
|
|
3392
3589
|
}
|
|
@@ -3430,4 +3627,4 @@ export {
|
|
|
3430
3627
|
cleanup
|
|
3431
3628
|
};
|
|
3432
3629
|
|
|
3433
|
-
//# debugId=
|
|
3630
|
+
//# debugId=DEB2F8AAF72AF0A164756E2164756E21
|