raggrep 0.12.3 → 0.13.2
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 +58 -14
- package/dist/app/cli/opencode/index.d.ts +10 -0
- package/dist/app/cli/opencode/install-skill.d.ts +30 -0
- package/dist/app/cli/opencode/install-tool.d.ts +28 -0
- package/dist/app/cli/opencode/version-check.d.ts +30 -0
- package/dist/cli/main.js +629 -122
- package/dist/cli/main.js.map +9 -6
- package/dist/index.js +47 -13
- package/dist/index.js.map +4 -4
- package/dist/infrastructure/logger/progressManager.d.ts +1 -1
- package/package.json +1 -1
package/dist/cli/main.js
CHANGED
|
@@ -355,16 +355,30 @@ class ProgressManager {
|
|
|
355
355
|
}
|
|
356
356
|
this.logger.clearProgress();
|
|
357
357
|
}
|
|
358
|
-
reportProgress(completed, total, message) {
|
|
358
|
+
reportProgress(completed, total, message, indexed, skipped) {
|
|
359
359
|
this.state = {
|
|
360
360
|
completed,
|
|
361
361
|
total,
|
|
362
362
|
message,
|
|
363
|
+
indexed,
|
|
364
|
+
skipped,
|
|
363
365
|
timestamp: Date.now()
|
|
364
366
|
};
|
|
365
367
|
}
|
|
366
368
|
writeProgress() {
|
|
367
|
-
|
|
369
|
+
let progressMessage = ` [${this.state.completed}/${this.state.total}] ${this.state.message}`;
|
|
370
|
+
if (this.state.indexed !== undefined || this.state.skipped !== undefined) {
|
|
371
|
+
const parts2 = [];
|
|
372
|
+
if (this.state.indexed !== undefined && this.state.indexed > 0) {
|
|
373
|
+
parts2.push(`${this.state.indexed} indexed`);
|
|
374
|
+
}
|
|
375
|
+
if (this.state.skipped !== undefined && this.state.skipped > 0) {
|
|
376
|
+
parts2.push(`${this.state.skipped} skipped`);
|
|
377
|
+
}
|
|
378
|
+
if (parts2.length > 0) {
|
|
379
|
+
progressMessage += ` (${parts2.join(", ")})`;
|
|
380
|
+
}
|
|
381
|
+
}
|
|
368
382
|
this.logger.progress(progressMessage);
|
|
369
383
|
}
|
|
370
384
|
}
|
|
@@ -12095,6 +12109,8 @@ async function indexDirectory(rootDir, options = {}) {
|
|
|
12095
12109
|
const moduleStart = Date.now();
|
|
12096
12110
|
logger.info(`
|
|
12097
12111
|
[${module2.name}] Starting indexing...`);
|
|
12112
|
+
const moduleFiles = module2.supportsFile ? files.filter((f) => module2.supportsFile(f)) : files;
|
|
12113
|
+
logger.info(` Processing ${moduleFiles.length} files...`);
|
|
12098
12114
|
const moduleConfig = getModuleConfig(config, module2.id);
|
|
12099
12115
|
if (module2.initialize && moduleConfig) {
|
|
12100
12116
|
const configWithOverrides = { ...moduleConfig };
|
|
@@ -12110,8 +12126,6 @@ async function indexDirectory(rootDir, options = {}) {
|
|
|
12110
12126
|
};
|
|
12111
12127
|
await module2.initialize(configWithOverrides);
|
|
12112
12128
|
}
|
|
12113
|
-
const moduleFiles = module2.supportsFile ? files.filter((f) => module2.supportsFile(f)) : files;
|
|
12114
|
-
logger.info(` Processing ${moduleFiles.length} files...`);
|
|
12115
12129
|
const result = await indexWithModule(rootDir, moduleFiles, module2, config, verbose, introspection, logger, concurrency);
|
|
12116
12130
|
results.push(result);
|
|
12117
12131
|
if (module2.finalize) {
|
|
@@ -12346,11 +12360,12 @@ async function ensureIndexFresh(rootDir, options = {}) {
|
|
|
12346
12360
|
const totalToProcess = filesToProcess.length;
|
|
12347
12361
|
const progressManager = new ProgressManager(logger);
|
|
12348
12362
|
progressManager.start();
|
|
12363
|
+
let indexedCount = 0;
|
|
12364
|
+
let mtimeUpdatedCount = 0;
|
|
12349
12365
|
const processChangedFile = async (fileToProcess) => {
|
|
12350
12366
|
const { filepath, relativePath, lastModified, isNew, existingContentHash } = fileToProcess;
|
|
12351
12367
|
if (isLikelyBinary(filepath)) {
|
|
12352
12368
|
completedCount++;
|
|
12353
|
-
logger.debug(` Skipping ${relativePath} (binary file)`);
|
|
12354
12369
|
return { relativePath, status: "unchanged" };
|
|
12355
12370
|
}
|
|
12356
12371
|
try {
|
|
@@ -12358,6 +12373,7 @@ async function ensureIndexFresh(rootDir, options = {}) {
|
|
|
12358
12373
|
const contentHash = computeContentHash(content);
|
|
12359
12374
|
if (!isNew && existingContentHash && existingContentHash === contentHash) {
|
|
12360
12375
|
completedCount++;
|
|
12376
|
+
mtimeUpdatedCount++;
|
|
12361
12377
|
return {
|
|
12362
12378
|
relativePath,
|
|
12363
12379
|
status: "mtime_updated",
|
|
@@ -12366,7 +12382,8 @@ async function ensureIndexFresh(rootDir, options = {}) {
|
|
|
12366
12382
|
};
|
|
12367
12383
|
}
|
|
12368
12384
|
completedCount++;
|
|
12369
|
-
|
|
12385
|
+
indexedCount++;
|
|
12386
|
+
progressManager.reportProgress(completedCount, totalToProcess, `Indexing: ${relativePath}`, indexedCount, mtimeUpdatedCount);
|
|
12370
12387
|
introspection.addFile(relativePath, content);
|
|
12371
12388
|
const fileIndex = await module2.indexFile(relativePath, content, ctx);
|
|
12372
12389
|
if (!fileIndex) {
|
|
@@ -12427,6 +12444,19 @@ async function ensureIndexFresh(rootDir, options = {}) {
|
|
|
12427
12444
|
break;
|
|
12428
12445
|
}
|
|
12429
12446
|
}
|
|
12447
|
+
if (totalIndexed > 0 || mtimeUpdates > 0) {
|
|
12448
|
+
const parts2 = [];
|
|
12449
|
+
if (totalIndexed > 0) {
|
|
12450
|
+
parts2.push(`${totalIndexed} indexed`);
|
|
12451
|
+
}
|
|
12452
|
+
if (mtimeUpdates > 0) {
|
|
12453
|
+
parts2.push(`${mtimeUpdates} mtime-only`);
|
|
12454
|
+
}
|
|
12455
|
+
if (totalRemoved > 0) {
|
|
12456
|
+
parts2.push(`${totalRemoved} removed`);
|
|
12457
|
+
}
|
|
12458
|
+
logger.info(` [${module2.name}] ${parts2.join(", ")}`);
|
|
12459
|
+
}
|
|
12430
12460
|
const hasManifestChanges = totalIndexed > 0 || totalRemoved > 0 || mtimeUpdates > 0;
|
|
12431
12461
|
if (hasManifestChanges) {
|
|
12432
12462
|
manifest.lastUpdated = new Date().toISOString();
|
|
@@ -12527,19 +12557,18 @@ async function indexWithModule(rootDir, files, module2, config, verbose, introsp
|
|
|
12527
12557
|
const progressManager = new ProgressManager(logger);
|
|
12528
12558
|
progressManager.start();
|
|
12529
12559
|
let completedCount = 0;
|
|
12560
|
+
let indexedCount = 0;
|
|
12561
|
+
let skippedCount = 0;
|
|
12530
12562
|
const processFile = async (filepath, _index) => {
|
|
12531
12563
|
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
|
-
}
|
|
12537
12564
|
try {
|
|
12538
12565
|
const stats = await fs8.stat(filepath);
|
|
12539
12566
|
const lastModified = stats.mtime.toISOString();
|
|
12540
12567
|
const existingEntry = manifest.files[relativePath];
|
|
12541
12568
|
if (existingEntry && existingEntry.lastModified === lastModified) {
|
|
12542
12569
|
completedCount++;
|
|
12570
|
+
skippedCount++;
|
|
12571
|
+
progressManager.reportProgress(completedCount, totalFiles, `Processing: ${relativePath}`, indexedCount, skippedCount);
|
|
12543
12572
|
logger.debug(` [${completedCount}/${totalFiles}] Skipped ${relativePath} (unchanged)`);
|
|
12544
12573
|
return { relativePath, status: "skipped" };
|
|
12545
12574
|
}
|
|
@@ -12547,6 +12576,8 @@ async function indexWithModule(rootDir, files, module2, config, verbose, introsp
|
|
|
12547
12576
|
const contentHash = computeContentHash(content);
|
|
12548
12577
|
if (existingEntry?.contentHash && existingEntry.contentHash === contentHash) {
|
|
12549
12578
|
completedCount++;
|
|
12579
|
+
skippedCount++;
|
|
12580
|
+
progressManager.reportProgress(completedCount, totalFiles, `Processing: ${relativePath}`, indexedCount, skippedCount);
|
|
12550
12581
|
logger.debug(` [${completedCount}/${totalFiles}] Skipped ${relativePath} (content unchanged)`);
|
|
12551
12582
|
return {
|
|
12552
12583
|
relativePath,
|
|
@@ -12557,9 +12588,12 @@ async function indexWithModule(rootDir, files, module2, config, verbose, introsp
|
|
|
12557
12588
|
}
|
|
12558
12589
|
introspection.addFile(relativePath, content);
|
|
12559
12590
|
completedCount++;
|
|
12560
|
-
|
|
12591
|
+
indexedCount++;
|
|
12592
|
+
progressManager.reportProgress(completedCount, totalFiles, `Processing: ${relativePath}`, indexedCount, skippedCount);
|
|
12561
12593
|
const fileIndex = await module2.indexFile(relativePath, content, ctx);
|
|
12562
12594
|
if (!fileIndex) {
|
|
12595
|
+
skippedCount++;
|
|
12596
|
+
progressManager.reportProgress(completedCount, totalFiles, `Processing: ${relativePath}`, indexedCount, skippedCount);
|
|
12563
12597
|
logger.debug(` [${completedCount}/${totalFiles}] Skipped ${relativePath} (no chunks)`);
|
|
12564
12598
|
return { relativePath, status: "skipped" };
|
|
12565
12599
|
}
|
|
@@ -14488,13 +14522,533 @@ var init_search = __esm(() => {
|
|
|
14488
14522
|
init_indexer();
|
|
14489
14523
|
});
|
|
14490
14524
|
|
|
14525
|
+
// src/app/cli/opencode/version-check.ts
|
|
14526
|
+
function parseOpenCodeVersion(version) {
|
|
14527
|
+
const match2 = version.match(/v?(\d+)\.(\d+)\.(\d+)/);
|
|
14528
|
+
if (!match2) {
|
|
14529
|
+
return null;
|
|
14530
|
+
}
|
|
14531
|
+
return {
|
|
14532
|
+
major: parseInt(match2[1], 10),
|
|
14533
|
+
minor: parseInt(match2[2], 10),
|
|
14534
|
+
patch: parseInt(match2[3], 10)
|
|
14535
|
+
};
|
|
14536
|
+
}
|
|
14537
|
+
function supportsSkills(version) {
|
|
14538
|
+
const parsed = parseOpenCodeVersion(version);
|
|
14539
|
+
if (!parsed) {
|
|
14540
|
+
return true;
|
|
14541
|
+
}
|
|
14542
|
+
if (parsed.major > 1)
|
|
14543
|
+
return true;
|
|
14544
|
+
if (parsed.major === 1 && parsed.minor > 0)
|
|
14545
|
+
return true;
|
|
14546
|
+
if (parsed.major === 1 && parsed.minor === 0 && parsed.patch >= 186)
|
|
14547
|
+
return true;
|
|
14548
|
+
return false;
|
|
14549
|
+
}
|
|
14550
|
+
function getInstallationMethod(openCodeVersion) {
|
|
14551
|
+
if (!openCodeVersion) {
|
|
14552
|
+
return "skill";
|
|
14553
|
+
}
|
|
14554
|
+
return supportsSkills(openCodeVersion) ? "skill" : "tool";
|
|
14555
|
+
}
|
|
14556
|
+
async function detectOpenCodeVersion() {
|
|
14557
|
+
try {
|
|
14558
|
+
const os4 = await import("os");
|
|
14559
|
+
const fs10 = await import("fs/promises");
|
|
14560
|
+
const path25 = await import("path");
|
|
14561
|
+
const homeDir = os4.homedir();
|
|
14562
|
+
const possiblePaths = [
|
|
14563
|
+
path25.join(homeDir, ".local", "share", "opencode", "package.json"),
|
|
14564
|
+
path25.join(homeDir, ".config", "opencode", "package.json"),
|
|
14565
|
+
path25.join(homeDir, ".npm", "global", "node_modules", "opencode", "package.json")
|
|
14566
|
+
];
|
|
14567
|
+
for (const packagePath of possiblePaths) {
|
|
14568
|
+
try {
|
|
14569
|
+
const content = await fs10.readFile(packagePath, "utf-8");
|
|
14570
|
+
const pkg = JSON.parse(content);
|
|
14571
|
+
if (pkg.version) {
|
|
14572
|
+
return pkg.version;
|
|
14573
|
+
}
|
|
14574
|
+
} catch {}
|
|
14575
|
+
}
|
|
14576
|
+
try {
|
|
14577
|
+
const { spawn } = await import("child_process");
|
|
14578
|
+
return new Promise((resolve6) => {
|
|
14579
|
+
const proc = spawn("opencode", ["--version"], { stdio: "pipe" });
|
|
14580
|
+
let version = "";
|
|
14581
|
+
proc.stdout.on("data", (data) => {
|
|
14582
|
+
version += data.toString();
|
|
14583
|
+
});
|
|
14584
|
+
proc.on("close", (code) => {
|
|
14585
|
+
if (code === 0) {
|
|
14586
|
+
const match2 = version.match(/v?(\d+\.\d+\.\d+)/);
|
|
14587
|
+
resolve6(match2 ? match2[1] : null);
|
|
14588
|
+
} else {
|
|
14589
|
+
resolve6(null);
|
|
14590
|
+
}
|
|
14591
|
+
});
|
|
14592
|
+
setTimeout(() => {
|
|
14593
|
+
proc.kill();
|
|
14594
|
+
resolve6(null);
|
|
14595
|
+
}, 3000);
|
|
14596
|
+
});
|
|
14597
|
+
} catch {}
|
|
14598
|
+
return null;
|
|
14599
|
+
} catch {
|
|
14600
|
+
return null;
|
|
14601
|
+
}
|
|
14602
|
+
}
|
|
14603
|
+
|
|
14604
|
+
// src/app/cli/opencode/install-tool.ts
|
|
14605
|
+
async function installTool(options = {}) {
|
|
14606
|
+
const { logger, checkForOldSkill = true } = options;
|
|
14607
|
+
const os4 = await import("os");
|
|
14608
|
+
const fs10 = await import("fs/promises");
|
|
14609
|
+
const path25 = await import("path");
|
|
14610
|
+
const homeDir = os4.homedir();
|
|
14611
|
+
const toolDir = path25.join(homeDir, ".config", "opencode", "tool");
|
|
14612
|
+
const toolPath = path25.join(toolDir, "raggrep.ts");
|
|
14613
|
+
let removedOldSkill = false;
|
|
14614
|
+
const toolContent = `import { tool } from "@opencode-ai/plugin";
|
|
14615
|
+
|
|
14616
|
+
/**
|
|
14617
|
+
* Check if raggrep is installed globally
|
|
14618
|
+
*/
|
|
14619
|
+
async function isRagrepInstalled(): Promise<boolean> {
|
|
14620
|
+
try {
|
|
14621
|
+
const proc = Bun.spawn(['raggrep', '--version'], { stdout: 'pipe', stderr: 'pipe' });
|
|
14622
|
+
await proc.exited;
|
|
14623
|
+
return proc.exitCode === 0;
|
|
14624
|
+
} catch {
|
|
14625
|
+
return false;
|
|
14626
|
+
}
|
|
14627
|
+
}
|
|
14628
|
+
|
|
14629
|
+
/**
|
|
14630
|
+
* Get the installed raggrep version
|
|
14631
|
+
*/
|
|
14632
|
+
async function getRagrepVersion(): Promise<string | null> {
|
|
14633
|
+
try {
|
|
14634
|
+
const proc = Bun.spawn(['raggrep', '--version'], { stdout: 'pipe', stderr: 'pipe' });
|
|
14635
|
+
const output = await new Response(proc.stdout).text();
|
|
14636
|
+
const match = output.match(/v([\\\\d.]+)/);
|
|
14637
|
+
return match ? match[1] : null;
|
|
14638
|
+
} catch {
|
|
14639
|
+
return null;
|
|
14640
|
+
}
|
|
14641
|
+
}
|
|
14642
|
+
|
|
14643
|
+
export default tool({
|
|
14644
|
+
description:
|
|
14645
|
+
"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.",
|
|
14646
|
+
args: {
|
|
14647
|
+
query: tool.schema
|
|
14648
|
+
.string()
|
|
14649
|
+
.describe(
|
|
14650
|
+
"Natural language search query describing what you want to find. Be specific: 'auth middleware that checks JWT', 'React hooks for data fetching', 'database connection pool config'. This is MUCH faster than reading files manually."
|
|
14651
|
+
),
|
|
14652
|
+
filter: tool.schema
|
|
14653
|
+
.array(tool.schema.string())
|
|
14654
|
+
.describe(
|
|
14655
|
+
"Array of path prefixes or glob patterns to narrow search scope (OR logic). If user mentions a directory, use it. Otherwise infer from context. Common patterns: ['src/auth'], ['*.tsx', 'components/'], ['api/', 'routes/'], ['docs/', '*.md'], ['*.test.ts']. For broad search use ['src/'] or ['**/*']."
|
|
14656
|
+
),
|
|
14657
|
+
top: tool.schema
|
|
14658
|
+
.number()
|
|
14659
|
+
.optional()
|
|
14660
|
+
.describe("Number of results to return (default: 10)"),
|
|
14661
|
+
minScore: tool.schema
|
|
14662
|
+
.number()
|
|
14663
|
+
.optional()
|
|
14664
|
+
.describe("Minimum similarity score 0-1 (default: 0.15)"),
|
|
14665
|
+
type: tool.schema
|
|
14666
|
+
.string()
|
|
14667
|
+
.optional()
|
|
14668
|
+
.describe(
|
|
14669
|
+
"Filter by single file extension without dot (e.g., 'ts', 'tsx', 'js', 'md'). Prefer using 'filter' with glob patterns like '*.ts' for more flexibility."
|
|
14670
|
+
),
|
|
14671
|
+
},
|
|
14672
|
+
async execute(args) {
|
|
14673
|
+
const installed = await isRagrepInstalled();
|
|
14674
|
+
|
|
14675
|
+
if (!installed) {
|
|
14676
|
+
return \`Error: raggrep is not installed globally.
|
|
14677
|
+
|
|
14678
|
+
Please install raggrep using one of the following commands:
|
|
14679
|
+
npm install -g raggrep@latest
|
|
14680
|
+
pnpm install -g raggrep@latest
|
|
14681
|
+
|
|
14682
|
+
After installation, raggrep will be available for use.\`;
|
|
14683
|
+
}
|
|
14684
|
+
|
|
14685
|
+
const cmdArgs = [args.query];
|
|
14686
|
+
|
|
14687
|
+
if (args.top !== undefined) {
|
|
14688
|
+
cmdArgs.push("--top", String(args.top));
|
|
14689
|
+
}
|
|
14690
|
+
if (args.minScore !== undefined) {
|
|
14691
|
+
cmdArgs.push("--min-score", String(args.minScore));
|
|
14692
|
+
}
|
|
14693
|
+
if (args.type !== undefined) {
|
|
14694
|
+
cmdArgs.push("--type", args.type);
|
|
14695
|
+
}
|
|
14696
|
+
if (args.filter !== undefined && args.filter.length > 0) {
|
|
14697
|
+
for (const f of args.filter) {
|
|
14698
|
+
cmdArgs.push("--filter", f);
|
|
14699
|
+
}
|
|
14700
|
+
}
|
|
14701
|
+
|
|
14702
|
+
const proc = Bun.spawn(['raggrep', 'query', ...cmdArgs], { stdout: 'pipe' });
|
|
14703
|
+
const result = await new Response(proc.stdout).text();
|
|
14704
|
+
return result.trim();
|
|
14705
|
+
},
|
|
14706
|
+
});
|
|
14707
|
+
`;
|
|
14708
|
+
try {
|
|
14709
|
+
if (checkForOldSkill) {
|
|
14710
|
+
const oldSkillDir = path25.join(homeDir, ".config", "opencode", "skill", "raggrep");
|
|
14711
|
+
const oldSkillPath = path25.join(oldSkillDir, "SKILL.md");
|
|
14712
|
+
let oldSkillExists = false;
|
|
14713
|
+
try {
|
|
14714
|
+
await fs10.access(oldSkillPath);
|
|
14715
|
+
oldSkillExists = true;
|
|
14716
|
+
} catch {}
|
|
14717
|
+
if (oldSkillExists) {
|
|
14718
|
+
const message2 = "Found existing raggrep skill from previous installation.";
|
|
14719
|
+
const locationMessage = ` Location: ${oldSkillPath}`;
|
|
14720
|
+
if (logger) {
|
|
14721
|
+
logger.info(message2);
|
|
14722
|
+
logger.info(locationMessage);
|
|
14723
|
+
} else {
|
|
14724
|
+
console.log(message2);
|
|
14725
|
+
console.log(locationMessage);
|
|
14726
|
+
}
|
|
14727
|
+
const readline = await import("readline");
|
|
14728
|
+
const rl = readline.createInterface({
|
|
14729
|
+
input: process.stdin,
|
|
14730
|
+
output: process.stdout
|
|
14731
|
+
});
|
|
14732
|
+
const answer = await new Promise((resolve6) => {
|
|
14733
|
+
rl.question("Remove the existing skill and install tool? (Y/n): ", resolve6);
|
|
14734
|
+
});
|
|
14735
|
+
rl.close();
|
|
14736
|
+
const shouldDelete = answer.toLowerCase() !== "n";
|
|
14737
|
+
if (shouldDelete) {
|
|
14738
|
+
try {
|
|
14739
|
+
await fs10.unlink(oldSkillPath);
|
|
14740
|
+
const skillDirContents = await fs10.readdir(oldSkillDir);
|
|
14741
|
+
if (skillDirContents.length === 0) {
|
|
14742
|
+
try {
|
|
14743
|
+
await fs10.rmdir(oldSkillDir);
|
|
14744
|
+
console.log("✓ Removed old skill directory.");
|
|
14745
|
+
} catch (rmdirError) {
|
|
14746
|
+
console.log("✓ Removed old skill file. (Directory not empty or other error)");
|
|
14747
|
+
}
|
|
14748
|
+
} else {
|
|
14749
|
+
console.log("✓ Removed old skill file. (Directory not empty, keeping structure)");
|
|
14750
|
+
}
|
|
14751
|
+
removedOldSkill = true;
|
|
14752
|
+
const successMessage = "✓ Removed old skill file.";
|
|
14753
|
+
if (logger) {
|
|
14754
|
+
logger.info(successMessage);
|
|
14755
|
+
} else {
|
|
14756
|
+
console.log(successMessage);
|
|
14757
|
+
}
|
|
14758
|
+
} catch (error) {
|
|
14759
|
+
const warnMessage = `Warning: Could not remove old skill file: ${error}`;
|
|
14760
|
+
if (logger) {
|
|
14761
|
+
logger.warn(warnMessage);
|
|
14762
|
+
} else {
|
|
14763
|
+
console.warn(warnMessage);
|
|
14764
|
+
}
|
|
14765
|
+
}
|
|
14766
|
+
} else {
|
|
14767
|
+
const keepMessage = "Keeping existing skill. Tool installation cancelled.";
|
|
14768
|
+
if (logger) {
|
|
14769
|
+
logger.info(keepMessage);
|
|
14770
|
+
} else {
|
|
14771
|
+
console.log(keepMessage);
|
|
14772
|
+
}
|
|
14773
|
+
return {
|
|
14774
|
+
success: false,
|
|
14775
|
+
message: keepMessage
|
|
14776
|
+
};
|
|
14777
|
+
}
|
|
14778
|
+
}
|
|
14779
|
+
}
|
|
14780
|
+
await fs10.mkdir(toolDir, { recursive: true });
|
|
14781
|
+
await fs10.writeFile(toolPath, toolContent, "utf-8");
|
|
14782
|
+
const message = `Installed raggrep tool for OpenCode.
|
|
14783
|
+
Location: ${toolPath}
|
|
14784
|
+
|
|
14785
|
+
The raggrep tool is now available in OpenCode.`;
|
|
14786
|
+
if (logger) {
|
|
14787
|
+
logger.info(message);
|
|
14788
|
+
} else {
|
|
14789
|
+
console.log(message);
|
|
14790
|
+
}
|
|
14791
|
+
return {
|
|
14792
|
+
success: true,
|
|
14793
|
+
toolPath,
|
|
14794
|
+
message,
|
|
14795
|
+
removedOldSkill
|
|
14796
|
+
};
|
|
14797
|
+
} catch (error) {
|
|
14798
|
+
const message = `Error installing OpenCode tool: ${error}`;
|
|
14799
|
+
if (logger) {
|
|
14800
|
+
logger.error(message);
|
|
14801
|
+
} else {
|
|
14802
|
+
console.error(message);
|
|
14803
|
+
}
|
|
14804
|
+
return {
|
|
14805
|
+
success: false,
|
|
14806
|
+
message
|
|
14807
|
+
};
|
|
14808
|
+
}
|
|
14809
|
+
}
|
|
14810
|
+
|
|
14811
|
+
// src/app/cli/opencode/install-skill.ts
|
|
14812
|
+
async function installSkill(options = {}) {
|
|
14813
|
+
const { logger, checkForOldTool = true } = options;
|
|
14814
|
+
const os4 = await import("os");
|
|
14815
|
+
const fs10 = await import("fs/promises");
|
|
14816
|
+
const path25 = await import("path");
|
|
14817
|
+
const homeDir = os4.homedir();
|
|
14818
|
+
const skillDir = path25.join(homeDir, ".config", "opencode", "skill", "raggrep");
|
|
14819
|
+
const skillPath = path25.join(skillDir, "SKILL.md");
|
|
14820
|
+
const skillContent = `---
|
|
14821
|
+
name: raggrep
|
|
14822
|
+
description: AST-powered semantic code search that understands intent, not just text. Superior to grep/rg - finds functions, classes, and logic even when keywords differ. Saves 10x tool calls by searching the actual code structure.
|
|
14823
|
+
license: MIT
|
|
14824
|
+
compatibility: opencode
|
|
14825
|
+
metadata:
|
|
14826
|
+
audience: developers
|
|
14827
|
+
use_case: code-discovery
|
|
14828
|
+
---
|
|
14829
|
+
|
|
14830
|
+
## What I do
|
|
14831
|
+
|
|
14832
|
+
I'm a **MUCH better alternative to grep/rg** for code search. I provide semantic search that actually **understands your code** rather than just matching text:
|
|
14833
|
+
|
|
14834
|
+
- **Parse code using AST** to extract functions, classes, variables, and symbols with full context
|
|
14835
|
+
- **Understand code structure** and relationships across files
|
|
14836
|
+
- **Search by intent** - find "authentication logic" even if the code uses "auth", "login", "verifyToken", etc.
|
|
14837
|
+
- **Find relevant code** even when exact keywords don't appear anywhere in the source
|
|
14838
|
+
- **Save ~10x tool calls** compared to manually reading files or using grep
|
|
14839
|
+
|
|
14840
|
+
## When to use me
|
|
14841
|
+
|
|
14842
|
+
Use me when you need to:
|
|
14843
|
+
- **Find WHERE code is located** (functions, components, services)
|
|
14844
|
+
- **Understand HOW code is structured** (architecture, patterns, dependencies)
|
|
14845
|
+
- **Discover RELATED code** across multiple files
|
|
14846
|
+
- **Get a QUICK overview** of a topic or feature area
|
|
14847
|
+
|
|
14848
|
+
## How to use me
|
|
14849
|
+
|
|
14850
|
+
First, install raggrep if not already available:
|
|
14851
|
+
\`\`\`bash
|
|
14852
|
+
# Install raggrep globally
|
|
14853
|
+
npm install -g raggrep
|
|
14854
|
+
# or
|
|
14855
|
+
pnpm add -g raggrep
|
|
14856
|
+
\`\`\`
|
|
14857
|
+
|
|
14858
|
+
### Step 1: Index your codebase
|
|
14859
|
+
\`\`\`bash
|
|
14860
|
+
# Navigate to your project directory and index it
|
|
14861
|
+
cd /path/to/your/project
|
|
14862
|
+
raggrep index
|
|
14863
|
+
\`\`\`
|
|
14864
|
+
|
|
14865
|
+
### Step 2: Use semantic search
|
|
14866
|
+
\`\`\`bash
|
|
14867
|
+
# Search for specific functionality
|
|
14868
|
+
raggrep query "user authentication"
|
|
14869
|
+
|
|
14870
|
+
# Search with filters
|
|
14871
|
+
raggrep query "React hooks for data fetching" --filter "src/components"
|
|
14872
|
+
|
|
14873
|
+
# Search with specific file types
|
|
14874
|
+
raggrep query "database connection" --type ts
|
|
14875
|
+
|
|
14876
|
+
# Get more results
|
|
14877
|
+
raggrep query "error handling" --top 15
|
|
14878
|
+
\`\`\`
|
|
14879
|
+
|
|
14880
|
+
### Step 3: Use in OpenCode agents
|
|
14881
|
+
|
|
14882
|
+
Load this skill in your agent conversation:
|
|
14883
|
+
\`\`\`
|
|
14884
|
+
skill({ name: "raggrep" })
|
|
14885
|
+
\`\`\`
|
|
14886
|
+
|
|
14887
|
+
Then the agent can use raggrep commands to search your codebase efficiently.
|
|
14888
|
+
|
|
14889
|
+
## Why I'm Better Than grep/rg
|
|
14890
|
+
|
|
14891
|
+
❌ **grep/rg limitations:**
|
|
14892
|
+
- Only matches literal text patterns
|
|
14893
|
+
- Can't understand code structure or intent
|
|
14894
|
+
- Requires exact keyword matches
|
|
14895
|
+
- Often returns irrelevant results
|
|
14896
|
+
|
|
14897
|
+
✅ **My advantages:**
|
|
14898
|
+
- Understands code semantics and intent
|
|
14899
|
+
- Finds relevant code even with different terminology
|
|
14900
|
+
- Works with AST-extracted symbols, not just raw text
|
|
14901
|
+
- Provides contextual, ranked results
|
|
14902
|
+
|
|
14903
|
+
## Search Examples
|
|
14904
|
+
|
|
14905
|
+
Instead of using grep/rg or manually reading files:
|
|
14906
|
+
|
|
14907
|
+
❌ **DON'T do this:**
|
|
14908
|
+
- \`rg "auth" --type ts\` (might miss middleware, login, verifyToken)
|
|
14909
|
+
- Read: auth.ts, middleware.ts, index.ts to find auth logic
|
|
14910
|
+
- Read: App.tsx, components/*, pages/* to find React components
|
|
14911
|
+
- Read: db.ts, config.ts, models/* to find database code
|
|
14912
|
+
|
|
14913
|
+
✅ **DO this instead:**
|
|
14914
|
+
- \`raggrep query "Find the auth middleware"\` (finds ALL auth-related code)
|
|
14915
|
+
- \`raggrep query "Where are React components?"\`
|
|
14916
|
+
- \`raggrep query "Database connection logic?"\`
|
|
14917
|
+
- \`raggrep query "Error handling patterns"\`
|
|
14918
|
+
|
|
14919
|
+
## Best Practices
|
|
14920
|
+
|
|
14921
|
+
1. **Think intent, not keywords**: "user authentication logic" works better than \`rg "auth"\`
|
|
14922
|
+
2. **Use filters strategically**: \`--filter "src/auth"\`, \`--filter "*.test.ts"\`
|
|
14923
|
+
3. **Adjust result count**: Use \`--top 5\` for focused results, \`--top 20\` for comprehensive search
|
|
14924
|
+
4. **Replace grep/rg habits**: Instead of \`rg "pattern"\`, try \`raggrep query "what the code does"\`
|
|
14925
|
+
|
|
14926
|
+
**Result**: 10x fewer tool calls, BETTER results, deeper code understanding.
|
|
14927
|
+
`;
|
|
14928
|
+
let removedOldTool = false;
|
|
14929
|
+
try {
|
|
14930
|
+
if (checkForOldTool) {
|
|
14931
|
+
const oldToolDir = path25.join(homeDir, ".config", "opencode", "tool");
|
|
14932
|
+
const oldToolPath = path25.join(oldToolDir, "raggrep.ts");
|
|
14933
|
+
let oldToolExists = false;
|
|
14934
|
+
try {
|
|
14935
|
+
await fs10.access(oldToolPath);
|
|
14936
|
+
oldToolExists = true;
|
|
14937
|
+
} catch {}
|
|
14938
|
+
if (oldToolExists) {
|
|
14939
|
+
const message2 = "Found old raggrep tool file from previous version.";
|
|
14940
|
+
const locationMessage = ` Location: ${oldToolPath}`;
|
|
14941
|
+
if (logger) {
|
|
14942
|
+
logger.info(message2);
|
|
14943
|
+
logger.info(locationMessage);
|
|
14944
|
+
} else {
|
|
14945
|
+
console.log(message2);
|
|
14946
|
+
console.log(locationMessage);
|
|
14947
|
+
}
|
|
14948
|
+
const readline = await import("readline");
|
|
14949
|
+
const rl = readline.createInterface({
|
|
14950
|
+
input: process.stdin,
|
|
14951
|
+
output: process.stdout
|
|
14952
|
+
});
|
|
14953
|
+
const answer = await new Promise((resolve6) => {
|
|
14954
|
+
rl.question("Do you want to remove the old tool file? (Y/n): ", resolve6);
|
|
14955
|
+
});
|
|
14956
|
+
rl.close();
|
|
14957
|
+
const shouldDelete = answer.toLowerCase() !== "n";
|
|
14958
|
+
if (shouldDelete) {
|
|
14959
|
+
try {
|
|
14960
|
+
await fs10.unlink(oldToolPath);
|
|
14961
|
+
const toolDirContents = await fs10.readdir(oldToolDir);
|
|
14962
|
+
if (toolDirContents.length === 0) {
|
|
14963
|
+
try {
|
|
14964
|
+
await fs10.rmdir(oldToolDir);
|
|
14965
|
+
console.log("✓ Removed old tool directory.");
|
|
14966
|
+
} catch (rmdirError) {
|
|
14967
|
+
console.log("✓ Removed old tool file. (Directory not empty or other error)");
|
|
14968
|
+
}
|
|
14969
|
+
} else {
|
|
14970
|
+
console.log("✓ Removed old tool file. (Directory not empty, keeping structure)");
|
|
14971
|
+
}
|
|
14972
|
+
removedOldTool = true;
|
|
14973
|
+
const successMessage = "✓ Removed old tool file.";
|
|
14974
|
+
if (logger) {
|
|
14975
|
+
logger.info(successMessage);
|
|
14976
|
+
} else {
|
|
14977
|
+
console.log(successMessage);
|
|
14978
|
+
}
|
|
14979
|
+
} catch (error) {
|
|
14980
|
+
const warnMessage = `Warning: Could not remove old tool file: ${error}`;
|
|
14981
|
+
if (logger) {
|
|
14982
|
+
logger.warn(warnMessage);
|
|
14983
|
+
} else {
|
|
14984
|
+
console.warn(warnMessage);
|
|
14985
|
+
}
|
|
14986
|
+
}
|
|
14987
|
+
} else {
|
|
14988
|
+
const keepMessage = "Keeping old tool file.";
|
|
14989
|
+
if (logger) {
|
|
14990
|
+
logger.info(keepMessage);
|
|
14991
|
+
} else {
|
|
14992
|
+
console.log(keepMessage);
|
|
14993
|
+
}
|
|
14994
|
+
}
|
|
14995
|
+
}
|
|
14996
|
+
}
|
|
14997
|
+
await fs10.mkdir(skillDir, { recursive: true });
|
|
14998
|
+
await fs10.writeFile(skillPath, skillContent, "utf-8");
|
|
14999
|
+
const message = `Installed raggrep skill for OpenCode.
|
|
15000
|
+
Location: ${skillPath}
|
|
15001
|
+
|
|
15002
|
+
The raggrep skill is now available to OpenCode agents.
|
|
15003
|
+
|
|
15004
|
+
To use this skill:
|
|
15005
|
+
1. Install raggrep: npm install -g raggrep
|
|
15006
|
+
2. Index your codebase: raggrep index
|
|
15007
|
+
3. In OpenCode, load the skill: skill({ name: "raggrep" })`;
|
|
15008
|
+
if (logger) {
|
|
15009
|
+
logger.info(message);
|
|
15010
|
+
} else {
|
|
15011
|
+
console.log(message);
|
|
15012
|
+
}
|
|
15013
|
+
return {
|
|
15014
|
+
success: true,
|
|
15015
|
+
skillPath,
|
|
15016
|
+
message,
|
|
15017
|
+
removedOldTool
|
|
15018
|
+
};
|
|
15019
|
+
} catch (error) {
|
|
15020
|
+
const message = `Error installing OpenCode skill: ${error}`;
|
|
15021
|
+
if (logger) {
|
|
15022
|
+
logger.error(message);
|
|
15023
|
+
} else {
|
|
15024
|
+
console.error(message);
|
|
15025
|
+
}
|
|
15026
|
+
return {
|
|
15027
|
+
success: false,
|
|
15028
|
+
message
|
|
15029
|
+
};
|
|
15030
|
+
}
|
|
15031
|
+
}
|
|
15032
|
+
|
|
15033
|
+
// src/app/cli/opencode/index.ts
|
|
15034
|
+
var exports_opencode = {};
|
|
15035
|
+
__export(exports_opencode, {
|
|
15036
|
+
supportsSkills: () => supportsSkills,
|
|
15037
|
+
parseOpenCodeVersion: () => parseOpenCodeVersion,
|
|
15038
|
+
installTool: () => installTool,
|
|
15039
|
+
installSkill: () => installSkill,
|
|
15040
|
+
getInstallationMethod: () => getInstallationMethod,
|
|
15041
|
+
detectOpenCodeVersion: () => detectOpenCodeVersion
|
|
15042
|
+
});
|
|
15043
|
+
var init_opencode = () => {};
|
|
15044
|
+
|
|
14491
15045
|
// src/app/cli/main.ts
|
|
14492
15046
|
init_embeddings();
|
|
14493
15047
|
init_logger();
|
|
14494
15048
|
// package.json
|
|
14495
15049
|
var package_default = {
|
|
14496
15050
|
name: "raggrep",
|
|
14497
|
-
version: "0.
|
|
15051
|
+
version: "0.13.2",
|
|
14498
15052
|
description: "Local filesystem-based RAG system for codebases - semantic search using local embeddings",
|
|
14499
15053
|
type: "module",
|
|
14500
15054
|
main: "./dist/index.js",
|
|
@@ -14593,6 +15147,8 @@ function parseFlags(args3) {
|
|
|
14593
15147
|
verbose: false,
|
|
14594
15148
|
watch: false,
|
|
14595
15149
|
timing: false,
|
|
15150
|
+
forceTool: false,
|
|
15151
|
+
forceSkill: false,
|
|
14596
15152
|
remaining: []
|
|
14597
15153
|
};
|
|
14598
15154
|
for (let i2 = 0;i2 < args3.length; i2++) {
|
|
@@ -14654,6 +15210,10 @@ function parseFlags(args3) {
|
|
|
14654
15210
|
console.error('--filter requires a path or glob pattern (e.g., src/auth, "*.ts")');
|
|
14655
15211
|
process.exit(1);
|
|
14656
15212
|
}
|
|
15213
|
+
} else if (arg === "--tool") {
|
|
15214
|
+
flags2.forceTool = true;
|
|
15215
|
+
} else if (arg === "--skill") {
|
|
15216
|
+
flags2.forceSkill = true;
|
|
14657
15217
|
} else if (!arg.startsWith("-")) {
|
|
14658
15218
|
flags2.remaining.push(arg);
|
|
14659
15219
|
}
|
|
@@ -14970,129 +15530,76 @@ Examples:
|
|
|
14970
15530
|
const subcommand = flags2.remaining[0];
|
|
14971
15531
|
if (flags2.help || !subcommand) {
|
|
14972
15532
|
console.log(`
|
|
14973
|
-
raggrep opencode - Manage
|
|
15533
|
+
raggrep opencode - Manage OpenCode integration
|
|
14974
15534
|
|
|
14975
15535
|
Usage:
|
|
14976
|
-
raggrep opencode <subcommand>
|
|
15536
|
+
raggrep opencode <subcommand> [options]
|
|
14977
15537
|
|
|
14978
15538
|
Subcommands:
|
|
14979
|
-
install Install or update
|
|
15539
|
+
install Install or update raggrep for OpenCode
|
|
15540
|
+
|
|
15541
|
+
Options:
|
|
15542
|
+
--tool Force tool-based installation (default)
|
|
15543
|
+
--skill Force skill-based installation
|
|
14980
15544
|
|
|
14981
15545
|
Description:
|
|
14982
|
-
Installs
|
|
14983
|
-
|
|
15546
|
+
Installs raggrep for OpenCode with mutual exclusivity:
|
|
15547
|
+
- Tool installation (default): ~/.config/opencode/tool/raggrep.ts
|
|
15548
|
+
- Skill installation: ~/.config/opencode/skill/raggrep/SKILL.md
|
|
15549
|
+
Installing one will prompt to remove the other (default: yes)
|
|
14984
15550
|
|
|
14985
15551
|
Examples:
|
|
14986
|
-
raggrep opencode install
|
|
15552
|
+
raggrep opencode install # Install tool (default)
|
|
15553
|
+
raggrep opencode install --tool # Force tool installation
|
|
15554
|
+
raggrep opencode install --skill # Force skill installation
|
|
14987
15555
|
`);
|
|
14988
15556
|
process.exit(0);
|
|
14989
15557
|
}
|
|
14990
15558
|
if (subcommand === "install") {
|
|
14991
|
-
|
|
14992
|
-
|
|
14993
|
-
|
|
14994
|
-
|
|
14995
|
-
const
|
|
14996
|
-
|
|
14997
|
-
|
|
14998
|
-
|
|
14999
|
-
|
|
15000
|
-
|
|
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
|
-
|
|
15027
|
-
export default tool({
|
|
15028
|
-
description:
|
|
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.",
|
|
15030
|
-
args: {
|
|
15031
|
-
query: tool.schema
|
|
15032
|
-
.string()
|
|
15033
|
-
.describe(
|
|
15034
|
-
"Natural language search query describing what you want to find. Be specific: 'auth middleware that checks JWT', 'React hooks for data fetching', 'database connection pool config'. This is MUCH faster than reading files manually."
|
|
15035
|
-
),
|
|
15036
|
-
filter: tool.schema
|
|
15037
|
-
.array(tool.schema.string())
|
|
15038
|
-
.describe(
|
|
15039
|
-
"Array of path prefixes or glob patterns to narrow search scope (OR logic). If user mentions a directory, use it. Otherwise infer from context. Common patterns: ['src/auth'], ['*.tsx', 'components/'], ['api/', 'routes/'], ['docs/', '*.md'], ['*.test.ts']. For broad search use ['src/'] or ['**/*']."
|
|
15040
|
-
),
|
|
15041
|
-
top: tool.schema
|
|
15042
|
-
.number()
|
|
15043
|
-
.optional()
|
|
15044
|
-
.describe("Number of results to return (default: 10)"),
|
|
15045
|
-
minScore: tool.schema
|
|
15046
|
-
.number()
|
|
15047
|
-
.optional()
|
|
15048
|
-
.describe("Minimum similarity score 0-1 (default: 0.15)"),
|
|
15049
|
-
type: tool.schema
|
|
15050
|
-
.string()
|
|
15051
|
-
.optional()
|
|
15052
|
-
.describe(
|
|
15053
|
-
"Filter by single file extension without dot (e.g., 'ts', 'tsx', 'js', 'md'). Prefer using 'filter' with glob patterns like '*.ts' for more flexibility."
|
|
15054
|
-
),
|
|
15055
|
-
},
|
|
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
|
-
|
|
15064
|
-
const cmdArgs = [args.query];
|
|
15065
|
-
|
|
15066
|
-
if (args.top !== undefined) {
|
|
15067
|
-
cmdArgs.push("--top", String(args.top));
|
|
15068
|
-
}
|
|
15069
|
-
if (args.minScore !== undefined) {
|
|
15070
|
-
cmdArgs.push("--min-score", String(args.minScore));
|
|
15071
|
-
}
|
|
15072
|
-
if (args.type !== undefined) {
|
|
15073
|
-
cmdArgs.push("--type", args.type);
|
|
15074
|
-
}
|
|
15075
|
-
if (args.filter !== undefined && args.filter.length > 0) {
|
|
15076
|
-
for (const f of args.filter) {
|
|
15077
|
-
cmdArgs.push("--filter", f);
|
|
15078
|
-
}
|
|
15079
|
-
}
|
|
15080
|
-
|
|
15081
|
-
const proc = Bun.spawn([executor, 'raggrep', 'query', ...cmdArgs], { stdout: 'pipe' });
|
|
15082
|
-
const result = await new Response(proc.stdout).text();
|
|
15083
|
-
return result.trim();
|
|
15084
|
-
},
|
|
15085
|
-
});
|
|
15086
|
-
`;
|
|
15559
|
+
if (flags2.forceTool && flags2.forceSkill) {
|
|
15560
|
+
console.error("Error: --tool and --skill flags are mutually exclusive");
|
|
15561
|
+
process.exit(1);
|
|
15562
|
+
}
|
|
15563
|
+
const {
|
|
15564
|
+
detectOpenCodeVersion: detectOpenCodeVersion2,
|
|
15565
|
+
getInstallationMethod: getInstallationMethod2,
|
|
15566
|
+
installTool: installTool2,
|
|
15567
|
+
installSkill: installSkill2
|
|
15568
|
+
} = await Promise.resolve().then(() => (init_opencode(), exports_opencode));
|
|
15087
15569
|
try {
|
|
15088
|
-
|
|
15089
|
-
|
|
15090
|
-
|
|
15091
|
-
|
|
15570
|
+
let method;
|
|
15571
|
+
if (flags2.forceTool) {
|
|
15572
|
+
method = "tool";
|
|
15573
|
+
} else if (flags2.forceSkill) {
|
|
15574
|
+
method = "skill";
|
|
15575
|
+
} else {
|
|
15576
|
+
method = "tool";
|
|
15577
|
+
}
|
|
15578
|
+
console.log("RAGgrep OpenCode Installer");
|
|
15579
|
+
console.log(`==========================
|
|
15580
|
+
`);
|
|
15581
|
+
if (flags2.forceTool) {
|
|
15582
|
+
console.log("Forced tool-based installation (--tool flag)");
|
|
15583
|
+
} else if (flags2.forceSkill) {
|
|
15584
|
+
console.log("Forced skill-based installation (--skill flag)");
|
|
15585
|
+
} else {
|
|
15586
|
+
console.log("Default tool-based installation");
|
|
15587
|
+
}
|
|
15588
|
+
console.log(`Installing ${method}...
|
|
15589
|
+
`);
|
|
15590
|
+
let result;
|
|
15591
|
+
if (method === "tool") {
|
|
15592
|
+
result = await installTool2({ checkForOldSkill: true });
|
|
15593
|
+
} else {
|
|
15594
|
+
result = await installSkill2({ checkForOldTool: true });
|
|
15595
|
+
}
|
|
15596
|
+
if (!result.success) {
|
|
15597
|
+
process.exit(1);
|
|
15598
|
+
}
|
|
15092
15599
|
console.log(`
|
|
15093
|
-
|
|
15600
|
+
Installation completed successfully!`);
|
|
15094
15601
|
} catch (error) {
|
|
15095
|
-
console.error("Error
|
|
15602
|
+
console.error("Error during installation:", error);
|
|
15096
15603
|
process.exit(1);
|
|
15097
15604
|
}
|
|
15098
15605
|
} else {
|
|
@@ -15137,4 +15644,4 @@ Run 'raggrep <command> --help' for more information.
|
|
|
15137
15644
|
}
|
|
15138
15645
|
main();
|
|
15139
15646
|
|
|
15140
|
-
//# debugId=
|
|
15647
|
+
//# debugId=5CD6138213DBFFD864756E2164756E21
|