Files
oh-my-opencode/src/shared/ripgrep-cli.ts
T
YeonGyu-Kim 70ddc01e10 refactor: remove AI slop from refactored files
Behavior-preserving cleanup of AI-generated code smells in 5 files authored/moved by this PR:

- src/hooks/model-fallback/fallback-state-controller.ts (-47/+47 net reorganization, redundant defensiveness removed)
- src/shared/model-string-parser.ts (-4 LOC obvious-comment cleanup)
- src/shared/ripgrep-cli.ts (-13 LOC obvious comments + redundant defensive checks)
- src/tools/delegate-task/tool-description.ts (-6 LOC)
- src/tools/look-at/look-at-input-preparer.ts (-6 LOC)

Targets: obvious comments that restate code, over-defensive null checks on guaranteed values, redundant existence checks. No public API signatures changed, no type hints removed, no new abstractions introduced. Full test suite still passes.
2026-04-18 03:01:51 +09:00

115 lines
2.8 KiB
TypeScript

import { spawnSync } from "node:child_process"
import { existsSync } from "node:fs"
import { dirname, join } from "node:path"
import { downloadAndInstallRipgrep, getInstalledRipgrepPath } from "../tools/grep/downloader"
import { getDataDir } from "./data-path"
import { log } from "./logger"
import { PUBLISHED_PACKAGE_NAME } from "./plugin-identity"
export type GrepBackend = "rg" | "grep"
export interface ResolvedCli {
path: string
backend: GrepBackend
}
export const DEFAULT_RG_THREADS = 4
let cachedCli: ResolvedCli | null = null
let autoInstallAttempted = false
function findExecutable(name: string): string | null {
const isWindows = process.platform === "win32"
const cmd = isWindows ? "where" : "which"
try {
const result = spawnSync(cmd, [name], { encoding: "utf-8", timeout: 5000 })
if (result.status === 0 && result.stdout.trim()) {
return result.stdout.trim().split("\n")[0]
}
} catch {
return null
}
return null
}
function getOpenCodeBundledRg(): string | null {
const execPath = process.execPath
const execDir = dirname(execPath)
const isWindows = process.platform === "win32"
const rgName = isWindows ? "rg.exe" : "rg"
const candidates = [
join(getDataDir(), "opencode", "bin", rgName),
join(execDir, rgName),
join(execDir, "bin", rgName),
join(execDir, "..", "bin", rgName),
join(execDir, "..", "libexec", rgName),
]
for (const candidate of candidates) {
if (existsSync(candidate)) {
return candidate
}
}
return null
}
export function resolveGrepCli(): ResolvedCli {
if (cachedCli) {
return cachedCli
}
const rgPath = getOpenCodeBundledRg() ?? findExecutable("rg") ?? getInstalledRipgrepPath()
if (rgPath) {
cachedCli = { path: rgPath, backend: "rg" }
return cachedCli
}
const grep = findExecutable("grep")
if (grep) {
cachedCli = { path: grep, backend: "grep" }
return cachedCli
}
cachedCli = { path: "rg", backend: "rg" }
return cachedCli
}
export async function resolveGrepCliWithAutoInstall(): Promise<ResolvedCli> {
const current = resolveGrepCli()
if (current.backend === "rg" && current.path !== "rg") {
return current
}
if (autoInstallAttempted) {
return current
}
autoInstallAttempted = true
try {
const rgPath = await downloadAndInstallRipgrep()
cachedCli = { path: rgPath, backend: "rg" }
return cachedCli
} catch (error) {
const message = error instanceof Error ? error.message : String(error)
if (current.backend === "grep") {
log(`[${PUBLISHED_PACKAGE_NAME}] Failed to auto-install ripgrep. Falling back to GNU grep.`, {
error: message,
grep_path: current.path,
})
} else {
log(`[${PUBLISHED_PACKAGE_NAME}] Failed to auto-install ripgrep and GNU grep was not found.`, {
error: message,
})
}
return current
}
}