| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166 |
- import {
- chmodSync,
- existsSync,
- mkdirSync,
- readdirSync,
- unlinkSync,
- } from 'node:fs';
- import { join } from 'node:path';
- import { spawn } from 'bun';
- import { extractZip } from '../../utils';
- export function findFileRecursive(
- dir: string,
- filename: string,
- ): string | null {
- try {
- const entries = readdirSync(dir, { withFileTypes: true, recursive: true });
- for (const entry of entries) {
- if (entry.isFile() && entry.name === filename) {
- return join(entry.parentPath ?? dir, entry.name);
- }
- }
- } catch {
- return null;
- }
- return null;
- }
- const RG_VERSION = '14.1.1';
- // Platform key format: ${process.platform}-${process.arch} (consistent with ast-grep)
- const PLATFORM_CONFIG: Record<
- string,
- { platform: string; extension: 'tar.gz' | 'zip' } | undefined
- > = {
- 'darwin-arm64': { platform: 'aarch64-apple-darwin', extension: 'tar.gz' },
- 'darwin-x64': { platform: 'x86_64-apple-darwin', extension: 'tar.gz' },
- 'linux-arm64': { platform: 'aarch64-unknown-linux-gnu', extension: 'tar.gz' },
- 'linux-x64': { platform: 'x86_64-unknown-linux-musl', extension: 'tar.gz' },
- 'win32-x64': { platform: 'x86_64-pc-windows-msvc', extension: 'zip' },
- };
- function getPlatformKey(): string {
- return `${process.platform}-${process.arch}`;
- }
- function getInstallDir(): string {
- const homeDir = process.env.HOME || process.env.USERPROFILE || '.';
- return join(homeDir, '.cache', 'oh-my-opencode-slim', 'bin');
- }
- function getRgPath(): string {
- const isWindows = process.platform === 'win32';
- return join(getInstallDir(), isWindows ? 'rg.exe' : 'rg');
- }
- async function downloadFile(url: string, destPath: string): Promise<void> {
- const response = await fetch(url);
- if (!response.ok) {
- throw new Error(
- `Failed to download: ${response.status} ${response.statusText}`,
- );
- }
- const buffer = await response.arrayBuffer();
- await Bun.write(destPath, buffer);
- }
- async function extractTarGz(
- archivePath: string,
- destDir: string,
- ): Promise<void> {
- const args = ['tar', '-xzf', archivePath, '--strip-components=1'];
- if (process.platform === 'darwin') {
- args.push('--include=*/rg');
- } else if (process.platform === 'linux') {
- args.push('--wildcards', '*/rg');
- }
- const proc = spawn(args, {
- cwd: destDir,
- stdout: 'pipe',
- stderr: 'pipe',
- });
- const exitCode = await proc.exited;
- if (exitCode !== 0) {
- const stderr = await new Response(proc.stderr).text();
- throw new Error(`Failed to extract tar.gz: ${stderr}`);
- }
- }
- async function extractZipArchive(
- archivePath: string,
- destDir: string,
- ): Promise<void> {
- await extractZip(archivePath, destDir);
- const binaryName = process.platform === 'win32' ? 'rg.exe' : 'rg';
- const foundPath = findFileRecursive(destDir, binaryName);
- if (foundPath) {
- const destPath = join(destDir, binaryName);
- if (foundPath !== destPath) {
- const { renameSync } = await import('node:fs');
- renameSync(foundPath, destPath);
- }
- }
- }
- export async function downloadAndInstallRipgrep(): Promise<string> {
- const platformKey = getPlatformKey();
- const config = PLATFORM_CONFIG[platformKey];
- if (!config) {
- throw new Error(`Unsupported platform: ${platformKey}`);
- }
- const installDir = getInstallDir();
- const rgPath = getRgPath();
- if (existsSync(rgPath)) {
- return rgPath;
- }
- mkdirSync(installDir, { recursive: true });
- const filename = `ripgrep-${RG_VERSION}-${config.platform}.${config.extension}`;
- const url = `https://github.com/BurntSushi/ripgrep/releases/download/${RG_VERSION}/${filename}`;
- const archivePath = join(installDir, filename);
- try {
- console.log(`[oh-my-opencode-slim] Downloading ripgrep...`);
- await downloadFile(url, archivePath);
- if (config.extension === 'tar.gz') {
- await extractTarGz(archivePath, installDir);
- } else {
- await extractZipArchive(archivePath, installDir);
- }
- if (process.platform !== 'win32') {
- chmodSync(rgPath, 0o755);
- }
- if (!existsSync(rgPath)) {
- throw new Error('ripgrep binary not found after extraction');
- }
- console.log(`[oh-my-opencode-slim] ripgrep ready.`);
- return rgPath;
- } finally {
- if (existsSync(archivePath)) {
- try {
- unlinkSync(archivePath);
- } catch {
- // Cleanup failures are non-critical
- }
- }
- }
- }
- export function getInstalledRipgrepPath(): string | null {
- const rgPath = getRgPath();
- return existsSync(rgPath) ? rgPath : null;
- }
|