mirror of
https://github.com/claude-code-best/claude-code.git
synced 2026-06-18 14:25:51 +00:00
Fix/ripgrep fallback (#1273)
* fix: tmp 目录改用 os.tmpdir() + ripgrep 缺失时自动 fallback 系统 rg 1. Shell.ts / imagePaste.ts / filesystem.ts: Linux/macOS 默认 tmp 路径 从硬编码 '/tmp' 改为 os.tmpdir(),自动适配 Termux/Android 等无 /tmp 的环境;macOS 桌面零变化;CLAUDE_CODE_TMPDIR 仍优先级最高。 2. ripgrep.ts: builtin rg 二进制缺失时(Android/Termux、不完整安装) 自动 fallback 到 PATH 上的系统 rg,通过 note 字段携带人读提示; /doctor 渲染 note;init 启动时写一行 stderr warning。 Co-Authored-By: glm-5.2 <zai-org@claude-code-best.win> * fix: review fix — ripgrep note 文案修正 + init catch 加调试日志 - ripgrep "no ripgrep available" note 去掉无意义的 USE_BUILTIN_RIPGREP=0 建议 - init.ts ripgrep status check 的空 catch 加 logForDebugging Co-Authored-By: glm-5.2 <zai-org@claude-code-best.win> --------- Co-authored-by: glm-5.2 <zai-org@claude-code-best.win>
This commit is contained in:
75
src/utils/__tests__/ripgrepConfig.test.ts
Normal file
75
src/utils/__tests__/ripgrepConfig.test.ts
Normal file
@@ -0,0 +1,75 @@
|
||||
import { afterAll, beforeAll, describe, expect, test } from 'bun:test'
|
||||
import { mkdirSync, rmSync, writeFileSync } from 'fs'
|
||||
import { join } from 'path'
|
||||
|
||||
// Test the pure fallback function directly — no mock.module needed,
|
||||
// so this test cannot pollute other tests in the same Bun process.
|
||||
// See CLAUDE.md "Mock 使用规范" for why we avoid business-module mocking.
|
||||
const { resolveBuiltinWithFallback } = await import('../ripgrep.js')
|
||||
|
||||
// Real temp dir with a real (or removed) fake rg binary to control existsSync.
|
||||
const tmpDir = join(
|
||||
globalThis.process.env.TMPDIR || '/tmp',
|
||||
'ripgrep-config-test',
|
||||
)
|
||||
const vendorDir = join(
|
||||
tmpDir,
|
||||
'vendor',
|
||||
'ripgrep',
|
||||
`${process.arch}-${process.platform}`,
|
||||
)
|
||||
const rgPath = join(vendorDir, process.platform === 'win32' ? 'rg.exe' : 'rg')
|
||||
|
||||
describe('resolveBuiltinWithFallback', () => {
|
||||
beforeAll(() => {
|
||||
mkdirSync(vendorDir, { recursive: true })
|
||||
writeFileSync(rgPath, '')
|
||||
})
|
||||
|
||||
afterAll(() => {
|
||||
rmSync(tmpDir, { recursive: true, force: true })
|
||||
})
|
||||
|
||||
test('builtin exists -> mode=builtin, no note', () => {
|
||||
const result = resolveBuiltinWithFallback(rgPath)
|
||||
expect(result.mode).toBe('builtin')
|
||||
expect(result.command).toBe(rgPath)
|
||||
expect(result.note).toBeUndefined()
|
||||
})
|
||||
|
||||
test('builtin missing + system rg available -> mode=system, note set', () => {
|
||||
rmSync(rgPath)
|
||||
const result = resolveBuiltinWithFallback(
|
||||
rgPath,
|
||||
'/usr/local/bin/rg', // explicit system rg path
|
||||
'testplatform',
|
||||
)
|
||||
expect(result.mode).toBe('system')
|
||||
expect(result.command).toBe('rg')
|
||||
expect(result.note).toContain('fallback')
|
||||
expect(result.note).toContain('testplatform')
|
||||
// Restore for subsequent tests
|
||||
writeFileSync(rgPath, '')
|
||||
})
|
||||
|
||||
test('builtin missing + system rg missing -> mode=builtin, note set', () => {
|
||||
rmSync(rgPath)
|
||||
const result = resolveBuiltinWithFallback(
|
||||
rgPath,
|
||||
null, // no system rg
|
||||
'testplatform',
|
||||
)
|
||||
expect(result.mode).toBe('builtin')
|
||||
expect(result.command).toBe(rgPath)
|
||||
expect(result.note).toContain('no ripgrep available')
|
||||
expect(result.note).toContain('testplatform')
|
||||
writeFileSync(rgPath, '')
|
||||
})
|
||||
|
||||
test('uses process.platform when platform param omitted', () => {
|
||||
rmSync(rgPath)
|
||||
const result = resolveBuiltinWithFallback(rgPath, null)
|
||||
expect(result.note).toContain(process.platform)
|
||||
writeFileSync(rgPath, '')
|
||||
})
|
||||
})
|
||||
Reference in New Issue
Block a user