raggrep 0.12.1 → 0.12.3
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/dist/cli/main.js +262 -19
- package/dist/cli/main.js.map +9 -7
- package/dist/index.js +224 -6
- package/dist/index.js.map +8 -6
- package/dist/infrastructure/logger/index.d.ts +2 -0
- package/dist/infrastructure/logger/multiModuleProgressManager.d.ts +19 -0
- package/dist/infrastructure/logger/progressManager.d.ts +17 -0
- package/package.json +1 -1
package/dist/cli/main.js
CHANGED
|
@@ -290,11 +290,13 @@ class InlineProgressLogger {
|
|
|
290
290
|
}
|
|
291
291
|
}
|
|
292
292
|
progress(message) {
|
|
293
|
-
|
|
294
|
-
|
|
293
|
+
const maxCols = 120;
|
|
294
|
+
process.stdout.write("\r" + message);
|
|
295
|
+
const padding = Math.max(0, maxCols - message.length);
|
|
295
296
|
if (padding > 0) {
|
|
296
297
|
process.stdout.write(" ".repeat(padding));
|
|
297
298
|
}
|
|
299
|
+
process.stdout.write("\r");
|
|
298
300
|
this.lastProgressLength = message.length;
|
|
299
301
|
this.hasProgress = true;
|
|
300
302
|
}
|
|
@@ -325,6 +327,116 @@ function createSilentLogger() {
|
|
|
325
327
|
return new SilentLogger;
|
|
326
328
|
}
|
|
327
329
|
|
|
330
|
+
// src/infrastructure/logger/progressManager.ts
|
|
331
|
+
class ProgressManager {
|
|
332
|
+
logger;
|
|
333
|
+
state = {
|
|
334
|
+
completed: 0,
|
|
335
|
+
total: 0,
|
|
336
|
+
message: "",
|
|
337
|
+
timestamp: 0
|
|
338
|
+
};
|
|
339
|
+
intervalId = null;
|
|
340
|
+
constructor(logger) {
|
|
341
|
+
this.logger = logger;
|
|
342
|
+
}
|
|
343
|
+
start() {
|
|
344
|
+
if (this.intervalId) {
|
|
345
|
+
return;
|
|
346
|
+
}
|
|
347
|
+
this.intervalId = setInterval(() => {
|
|
348
|
+
this.writeProgress();
|
|
349
|
+
}, PROGRESS_UPDATE_INTERVAL_MS);
|
|
350
|
+
}
|
|
351
|
+
stop() {
|
|
352
|
+
if (this.intervalId) {
|
|
353
|
+
clearInterval(this.intervalId);
|
|
354
|
+
this.intervalId = null;
|
|
355
|
+
}
|
|
356
|
+
this.logger.clearProgress();
|
|
357
|
+
}
|
|
358
|
+
reportProgress(completed, total, message) {
|
|
359
|
+
this.state = {
|
|
360
|
+
completed,
|
|
361
|
+
total,
|
|
362
|
+
message,
|
|
363
|
+
timestamp: Date.now()
|
|
364
|
+
};
|
|
365
|
+
}
|
|
366
|
+
writeProgress() {
|
|
367
|
+
const progressMessage = ` [${this.state.completed}/${this.state.total}] ${this.state.message}`;
|
|
368
|
+
this.logger.progress(progressMessage);
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
var PROGRESS_UPDATE_INTERVAL_MS = 50;
|
|
372
|
+
|
|
373
|
+
// src/infrastructure/logger/multiModuleProgressManager.ts
|
|
374
|
+
class MultiModuleProgressManager {
|
|
375
|
+
logger;
|
|
376
|
+
modules = new Map;
|
|
377
|
+
intervalId = null;
|
|
378
|
+
constructor(logger) {
|
|
379
|
+
this.logger = logger;
|
|
380
|
+
}
|
|
381
|
+
start() {
|
|
382
|
+
if (this.intervalId) {
|
|
383
|
+
return;
|
|
384
|
+
}
|
|
385
|
+
this.intervalId = setInterval(() => {
|
|
386
|
+
this.writeProgress();
|
|
387
|
+
}, PROGRESS_UPDATE_INTERVAL_MS2);
|
|
388
|
+
}
|
|
389
|
+
stop() {
|
|
390
|
+
if (this.intervalId) {
|
|
391
|
+
clearInterval(this.intervalId);
|
|
392
|
+
this.intervalId = null;
|
|
393
|
+
}
|
|
394
|
+
this.logger.clearProgress();
|
|
395
|
+
}
|
|
396
|
+
registerModule(moduleId, moduleName, totalFiles) {
|
|
397
|
+
this.modules.set(moduleId, {
|
|
398
|
+
moduleName,
|
|
399
|
+
completed: 0,
|
|
400
|
+
total: totalFiles,
|
|
401
|
+
currentFile: "",
|
|
402
|
+
active: true
|
|
403
|
+
});
|
|
404
|
+
}
|
|
405
|
+
unregisterModule(moduleId) {
|
|
406
|
+
const module2 = this.modules.get(moduleId);
|
|
407
|
+
if (module2) {
|
|
408
|
+
module2.active = false;
|
|
409
|
+
}
|
|
410
|
+
}
|
|
411
|
+
reportProgress(moduleId, completed, currentFile) {
|
|
412
|
+
const module2 = this.modules.get(moduleId);
|
|
413
|
+
if (!module2) {
|
|
414
|
+
return;
|
|
415
|
+
}
|
|
416
|
+
module2.completed = completed;
|
|
417
|
+
module2.currentFile = currentFile;
|
|
418
|
+
}
|
|
419
|
+
writeProgress() {
|
|
420
|
+
const activeModules = Array.from(this.modules.values()).filter((m) => m.active);
|
|
421
|
+
if (activeModules.length === 0) {
|
|
422
|
+
return;
|
|
423
|
+
}
|
|
424
|
+
if (activeModules.length === 1) {
|
|
425
|
+
const m = activeModules[0];
|
|
426
|
+
const progressMessage = `[${m.moduleName}] ${m.completed}/${m.total}: ${m.currentFile}`;
|
|
427
|
+
this.logger.progress(progressMessage);
|
|
428
|
+
} else {
|
|
429
|
+
const parts2 = activeModules.map((m) => {
|
|
430
|
+
const percent = m.total > 0 ? Math.round(m.completed / m.total * 100) : 100;
|
|
431
|
+
return `[${m.moduleName} ${m.completed}/${m.total} ${percent}%]`;
|
|
432
|
+
});
|
|
433
|
+
const progressMessage = parts2.join(" ");
|
|
434
|
+
this.logger.progress(progressMessage);
|
|
435
|
+
}
|
|
436
|
+
}
|
|
437
|
+
}
|
|
438
|
+
var PROGRESS_UPDATE_INTERVAL_MS2 = 50;
|
|
439
|
+
|
|
328
440
|
// src/infrastructure/logger/index.ts
|
|
329
441
|
var init_logger = () => {};
|
|
330
442
|
|
|
@@ -932,7 +1044,24 @@ var init_config = __esm(() => {
|
|
|
932
1044
|
".pytest_cache",
|
|
933
1045
|
"*.egg-info",
|
|
934
1046
|
".idea",
|
|
935
|
-
".raggrep"
|
|
1047
|
+
".raggrep",
|
|
1048
|
+
".DS_Store",
|
|
1049
|
+
"Thumbs.db",
|
|
1050
|
+
".env",
|
|
1051
|
+
".env.local",
|
|
1052
|
+
".env.development.local",
|
|
1053
|
+
".env.test.local",
|
|
1054
|
+
".env.production.local",
|
|
1055
|
+
"*.lock",
|
|
1056
|
+
"package-lock.json",
|
|
1057
|
+
"yarn.lock",
|
|
1058
|
+
"pnpm-lock.yaml",
|
|
1059
|
+
"Cargo.lock",
|
|
1060
|
+
"poetry.lock",
|
|
1061
|
+
"Gemfile.lock",
|
|
1062
|
+
"go.sum",
|
|
1063
|
+
"*.min.js",
|
|
1064
|
+
"*.min.css"
|
|
936
1065
|
];
|
|
937
1066
|
DEFAULT_EXTENSIONS = [
|
|
938
1067
|
".ts",
|
|
@@ -12215,8 +12344,15 @@ async function ensureIndexFresh(rootDir, options = {}) {
|
|
|
12215
12344
|
}
|
|
12216
12345
|
let completedCount = 0;
|
|
12217
12346
|
const totalToProcess = filesToProcess.length;
|
|
12347
|
+
const progressManager = new ProgressManager(logger);
|
|
12348
|
+
progressManager.start();
|
|
12218
12349
|
const processChangedFile = async (fileToProcess) => {
|
|
12219
12350
|
const { filepath, relativePath, lastModified, isNew, existingContentHash } = fileToProcess;
|
|
12351
|
+
if (isLikelyBinary(filepath)) {
|
|
12352
|
+
completedCount++;
|
|
12353
|
+
logger.debug(` Skipping ${relativePath} (binary file)`);
|
|
12354
|
+
return { relativePath, status: "unchanged" };
|
|
12355
|
+
}
|
|
12220
12356
|
try {
|
|
12221
12357
|
const content = await fs8.readFile(filepath, "utf-8");
|
|
12222
12358
|
const contentHash = computeContentHash(content);
|
|
@@ -12230,7 +12366,7 @@ async function ensureIndexFresh(rootDir, options = {}) {
|
|
|
12230
12366
|
};
|
|
12231
12367
|
}
|
|
12232
12368
|
completedCount++;
|
|
12233
|
-
|
|
12369
|
+
progressManager.reportProgress(completedCount, totalToProcess, `Indexing: ${relativePath}`);
|
|
12234
12370
|
introspection.addFile(relativePath, content);
|
|
12235
12371
|
const fileIndex = await module2.indexFile(relativePath, content, ctx);
|
|
12236
12372
|
if (!fileIndex) {
|
|
@@ -12253,6 +12389,7 @@ async function ensureIndexFresh(rootDir, options = {}) {
|
|
|
12253
12389
|
const concurrency = options.concurrency ?? DEFAULT_CONCURRENCY;
|
|
12254
12390
|
const results = await parallelMap(filesToProcess, processChangedFile, concurrency);
|
|
12255
12391
|
indexingMs += Date.now() - indexingStart;
|
|
12392
|
+
progressManager.stop();
|
|
12256
12393
|
totalUnchanged += unchangedCount;
|
|
12257
12394
|
logger.clearProgress();
|
|
12258
12395
|
let mtimeUpdates = 0;
|
|
@@ -12387,9 +12524,16 @@ async function indexWithModule(rootDir, files, module2, config, verbose, introsp
|
|
|
12387
12524
|
getIntrospection: (filepath) => introspection.getFile(filepath)
|
|
12388
12525
|
};
|
|
12389
12526
|
const totalFiles = files.length;
|
|
12527
|
+
const progressManager = new ProgressManager(logger);
|
|
12528
|
+
progressManager.start();
|
|
12390
12529
|
let completedCount = 0;
|
|
12391
12530
|
const processFile = async (filepath, _index) => {
|
|
12392
12531
|
const relativePath = path22.relative(rootDir, filepath);
|
|
12532
|
+
if (isLikelyBinary(filepath)) {
|
|
12533
|
+
completedCount++;
|
|
12534
|
+
logger.debug(` [${completedCount}/${totalFiles}] Skipped ${relativePath} (binary file)`);
|
|
12535
|
+
return { relativePath, status: "skipped" };
|
|
12536
|
+
}
|
|
12393
12537
|
try {
|
|
12394
12538
|
const stats = await fs8.stat(filepath);
|
|
12395
12539
|
const lastModified = stats.mtime.toISOString();
|
|
@@ -12413,7 +12557,7 @@ async function indexWithModule(rootDir, files, module2, config, verbose, introsp
|
|
|
12413
12557
|
}
|
|
12414
12558
|
introspection.addFile(relativePath, content);
|
|
12415
12559
|
completedCount++;
|
|
12416
|
-
|
|
12560
|
+
progressManager.reportProgress(completedCount, totalFiles, `Processing: ${relativePath}`);
|
|
12417
12561
|
const fileIndex = await module2.indexFile(relativePath, content, ctx);
|
|
12418
12562
|
if (!fileIndex) {
|
|
12419
12563
|
logger.debug(` [${completedCount}/${totalFiles}] Skipped ${relativePath} (no chunks)`);
|
|
@@ -12434,6 +12578,7 @@ async function indexWithModule(rootDir, files, module2, config, verbose, introsp
|
|
|
12434
12578
|
};
|
|
12435
12579
|
logger.debug(` Using concurrency: ${concurrency}`);
|
|
12436
12580
|
const results = await parallelMap(files, processFile, concurrency);
|
|
12581
|
+
progressManager.stop();
|
|
12437
12582
|
logger.clearProgress();
|
|
12438
12583
|
for (const item of results) {
|
|
12439
12584
|
if (!item.success) {
|
|
@@ -12473,6 +12618,79 @@ async function indexWithModule(rootDir, files, module2, config, verbose, introsp
|
|
|
12473
12618
|
await writeModuleManifest(rootDir, module2.id, manifest, config);
|
|
12474
12619
|
return result;
|
|
12475
12620
|
}
|
|
12621
|
+
function isLikelyBinary(filepath) {
|
|
12622
|
+
const ext = path22.extname(filepath).toLowerCase();
|
|
12623
|
+
const basename15 = path22.basename(filepath).toLowerCase();
|
|
12624
|
+
const binaryExtensions = new Set([
|
|
12625
|
+
".png",
|
|
12626
|
+
".jpg",
|
|
12627
|
+
".jpeg",
|
|
12628
|
+
".gif",
|
|
12629
|
+
".ico",
|
|
12630
|
+
".svg",
|
|
12631
|
+
".webp",
|
|
12632
|
+
".bmp",
|
|
12633
|
+
".tiff",
|
|
12634
|
+
".pdf",
|
|
12635
|
+
".doc",
|
|
12636
|
+
".docx",
|
|
12637
|
+
".xls",
|
|
12638
|
+
".xlsx",
|
|
12639
|
+
".ppt",
|
|
12640
|
+
".pptx",
|
|
12641
|
+
".zip",
|
|
12642
|
+
".tar",
|
|
12643
|
+
".gz",
|
|
12644
|
+
".7z",
|
|
12645
|
+
".rar",
|
|
12646
|
+
".bz2",
|
|
12647
|
+
".exe",
|
|
12648
|
+
".dll",
|
|
12649
|
+
".so",
|
|
12650
|
+
".dylib",
|
|
12651
|
+
".bin",
|
|
12652
|
+
".dat",
|
|
12653
|
+
".obj",
|
|
12654
|
+
".o",
|
|
12655
|
+
".mp3",
|
|
12656
|
+
".mp4",
|
|
12657
|
+
".wav",
|
|
12658
|
+
".avi",
|
|
12659
|
+
".mov",
|
|
12660
|
+
".flac",
|
|
12661
|
+
".ogg",
|
|
12662
|
+
".woff",
|
|
12663
|
+
".woff2",
|
|
12664
|
+
".ttf",
|
|
12665
|
+
".eot",
|
|
12666
|
+
".otf"
|
|
12667
|
+
]);
|
|
12668
|
+
if (binaryExtensions.has(ext)) {
|
|
12669
|
+
return true;
|
|
12670
|
+
}
|
|
12671
|
+
const minifiedPatterns = [
|
|
12672
|
+
".min.js",
|
|
12673
|
+
".min.css",
|
|
12674
|
+
".bundle.js",
|
|
12675
|
+
".bundle.css",
|
|
12676
|
+
".prod.js",
|
|
12677
|
+
".prod.css",
|
|
12678
|
+
".chunk.js",
|
|
12679
|
+
".chunk.css"
|
|
12680
|
+
];
|
|
12681
|
+
if (minifiedPatterns.some((pattern) => filepath.includes(pattern))) {
|
|
12682
|
+
return true;
|
|
12683
|
+
}
|
|
12684
|
+
const systemFiles = [
|
|
12685
|
+
".ds_store",
|
|
12686
|
+
"thumbs.db",
|
|
12687
|
+
"desktop.ini"
|
|
12688
|
+
];
|
|
12689
|
+
if (systemFiles.includes(basename15)) {
|
|
12690
|
+
return true;
|
|
12691
|
+
}
|
|
12692
|
+
return false;
|
|
12693
|
+
}
|
|
12476
12694
|
async function findFilesWithStats(rootDir, config, lastIndexStarted) {
|
|
12477
12695
|
const validExtensions = new Set(config.extensions);
|
|
12478
12696
|
const ignoreDirs = new Set(config.ignorePaths);
|
|
@@ -14276,7 +14494,7 @@ init_logger();
|
|
|
14276
14494
|
// package.json
|
|
14277
14495
|
var package_default = {
|
|
14278
14496
|
name: "raggrep",
|
|
14279
|
-
version: "0.12.
|
|
14497
|
+
version: "0.12.3",
|
|
14280
14498
|
description: "Local filesystem-based RAG system for codebases - semantic search using local embeddings",
|
|
14281
14499
|
type: "module",
|
|
14282
14500
|
main: "./dist/index.js",
|
|
@@ -14778,6 +14996,34 @@ Examples:
|
|
|
14778
14996
|
const toolPath = path25.join(toolDir, "raggrep.ts");
|
|
14779
14997
|
const toolContent = `import { tool } from "@opencode-ai/plugin";
|
|
14780
14998
|
|
|
14999
|
+
/**
|
|
15000
|
+
* Get the package executor command (pnpx if available, otherwise npx)
|
|
15001
|
+
*/
|
|
15002
|
+
async function getExecutor(): Promise<string> {
|
|
15003
|
+
try {
|
|
15004
|
+
// Try to find pnpm first (faster)
|
|
15005
|
+
await Bun.spawn(['pnpm', '--version'], { stdout: 'pipe', stderr: 'pipe' }).exited;
|
|
15006
|
+
return 'pnpx';
|
|
15007
|
+
} catch {
|
|
15008
|
+
// Fall back to npx
|
|
15009
|
+
return 'npx';
|
|
15010
|
+
}
|
|
15011
|
+
}
|
|
15012
|
+
|
|
15013
|
+
/**
|
|
15014
|
+
* Get the installed raggrep version
|
|
15015
|
+
*/
|
|
15016
|
+
async function getRagrepVersion(executor: string): Promise<string | null> {
|
|
15017
|
+
try {
|
|
15018
|
+
const proc = Bun.spawn([executor, 'raggrep', '--version'], { stdout: 'pipe', stderr: 'pipe' });
|
|
15019
|
+
const output = await new Response(proc.stdout).text();
|
|
15020
|
+
const match = output.match(/v([\\d.]+)/);
|
|
15021
|
+
return match ? match[1] : null;
|
|
15022
|
+
} catch {
|
|
15023
|
+
return null;
|
|
15024
|
+
}
|
|
15025
|
+
}
|
|
15026
|
+
|
|
14781
15027
|
export default tool({
|
|
14782
15028
|
description:
|
|
14783
15029
|
"Semantic code search powered by RAG - understands INTENT, not just literal text. Parses code using AST to extract functions, classes, and symbols with full context. Finds relevant code even when exact keywords don't match. Superior to grep for exploratory searches like 'authentication logic', 'error handling patterns', or 'configuration loading'.\\n\\n\uD83C\uDFAF USE THIS TOOL FIRST when you need to:\\n• Find WHERE code is located (functions, components, services)\\n• Understand HOW code is structured\\n• Discover RELATED code across multiple files\\n• Get a QUICK overview of a topic\\n\\n❌ DON'T read multiple files manually when you can:\\n raggrep(\\"user authentication\\", { filter: [\\"src/\\"] })\\n\\n✅ INSTEAD of reading files one-by-one, search semantically:\\n • \\"Find the auth middleware\\" vs read: auth.ts, middleware.ts, index.ts...\\n • \\"Where are React components?\\" vs read: App.tsx, components/*, pages/*...\\n • \\"Database connection logic?\\" vs read: db.ts, config.ts, models/*...\\n • \\"Error handling patterns\\" vs read: error.ts, middleware.ts, handlers/*...\\n\\nThis saves ~10x tool calls and provides BETTER context by showing related code across the entire codebase.",
|
|
@@ -14808,6 +15054,13 @@ export default tool({
|
|
|
14808
15054
|
),
|
|
14809
15055
|
},
|
|
14810
15056
|
async execute(args) {
|
|
15057
|
+
const executor = await getExecutor();
|
|
15058
|
+
const version = await getRagrepVersion(executor);
|
|
15059
|
+
|
|
15060
|
+
if (!version) {
|
|
15061
|
+
return \`Error: raggrep not found. Install it with: \${executor} install -g raggrep\`;
|
|
15062
|
+
}
|
|
15063
|
+
|
|
14811
15064
|
const cmdArgs = [args.query];
|
|
14812
15065
|
|
|
14813
15066
|
if (args.top !== undefined) {
|
|
@@ -14825,7 +15078,7 @@ export default tool({
|
|
|
14825
15078
|
}
|
|
14826
15079
|
}
|
|
14827
15080
|
|
|
14828
|
-
const proc = Bun.spawn(['raggrep', 'query', ...cmdArgs], { stdout: 'pipe' });
|
|
15081
|
+
const proc = Bun.spawn([executor, 'raggrep', 'query', ...cmdArgs], { stdout: 'pipe' });
|
|
14829
15082
|
const result = await new Response(proc.stdout).text();
|
|
14830
15083
|
return result.trim();
|
|
14831
15084
|
},
|
|
@@ -14833,19 +15086,9 @@ export default tool({
|
|
|
14833
15086
|
`;
|
|
14834
15087
|
try {
|
|
14835
15088
|
await fs10.mkdir(toolDir, { recursive: true });
|
|
14836
|
-
let action = "Installed";
|
|
14837
|
-
const backupPath = toolPath + ".backup";
|
|
14838
|
-
try {
|
|
14839
|
-
await fs10.access(toolPath);
|
|
14840
|
-
await fs10.copyFile(toolPath, backupPath);
|
|
14841
|
-
action = "Updated";
|
|
14842
|
-
} catch {}
|
|
14843
15089
|
await fs10.writeFile(toolPath, toolContent, "utf-8");
|
|
14844
|
-
console.log(
|
|
15090
|
+
console.log(`Installed raggrep tool for opencode.`);
|
|
14845
15091
|
console.log(` Location: ${toolPath}`);
|
|
14846
|
-
if (action === "Updated") {
|
|
14847
|
-
console.log(` Backup: ${backupPath}`);
|
|
14848
|
-
}
|
|
14849
15092
|
console.log(`
|
|
14850
15093
|
The raggrep tool is now available in opencode.`);
|
|
14851
15094
|
} catch (error) {
|
|
@@ -14894,4 +15137,4 @@ Run 'raggrep <command> --help' for more information.
|
|
|
14894
15137
|
}
|
|
14895
15138
|
main();
|
|
14896
15139
|
|
|
14897
|
-
//# debugId=
|
|
15140
|
+
//# debugId=0D7443A2D252636E64756E2164756E21
|