mirror of
https://github.com/claude-code-best/claude-code.git
synced 2026-06-15 12:55:51 +00:00
style: 完成所有文件的lint
This commit is contained in:
@@ -11,29 +11,39 @@
|
||||
* bun run scripts/postinstall.js
|
||||
*/
|
||||
|
||||
const { existsSync, mkdirSync, readFileSync, renameSync, rmSync, statSync, writeFileSync, chmodSync } =
|
||||
require("fs")
|
||||
const { spawnSync } = require("child_process")
|
||||
const { setDefaultResultOrder } = require("node:dns")
|
||||
const path = require("path")
|
||||
const os = require("os")
|
||||
const {
|
||||
existsSync,
|
||||
mkdirSync,
|
||||
readFileSync,
|
||||
renameSync,
|
||||
rmSync,
|
||||
statSync,
|
||||
writeFileSync,
|
||||
chmodSync,
|
||||
} = require('fs')
|
||||
const { spawnSync } = require('child_process')
|
||||
const { setDefaultResultOrder } = require('node:dns')
|
||||
const path = require('path')
|
||||
const os = require('os')
|
||||
|
||||
// Prefer IPv4 first — Bun on Windows sometimes fails GitHub over broken IPv6 paths.
|
||||
try {
|
||||
setDefaultResultOrder("ipv4first")
|
||||
setDefaultResultOrder('ipv4first')
|
||||
} catch {
|
||||
/* ignore */
|
||||
}
|
||||
|
||||
// --- Config ---
|
||||
|
||||
const RG_VERSION = "15.0.1"
|
||||
const RG_VERSION = '15.0.1'
|
||||
const DEFAULT_RELEASE_BASE = `https://github.com/microsoft/ripgrep-prebuilt/releases/download/v${RG_VERSION}`
|
||||
const MIRROR_RELEASE_BASE = `https://ghproxy.net/https://github.com/microsoft/ripgrep-prebuilt/releases/download/v${RG_VERSION}`
|
||||
const RELEASE_BASE = (process.env.RIPGREP_DOWNLOAD_BASE ?? DEFAULT_RELEASE_BASE).replace(/\/$/, "")
|
||||
const RELEASE_BASE = (
|
||||
process.env.RIPGREP_DOWNLOAD_BASE ?? DEFAULT_RELEASE_BASE
|
||||
).replace(/\/$/, '')
|
||||
|
||||
const scriptDir = path.dirname(__filename)
|
||||
const projectRoot = path.resolve(scriptDir, "..")
|
||||
const projectRoot = path.resolve(scriptDir, '..')
|
||||
|
||||
// --- Platform mapping ---
|
||||
|
||||
@@ -41,27 +51,29 @@ function getPlatformMapping() {
|
||||
const arch = process.arch
|
||||
const platform = process.platform
|
||||
|
||||
if (platform === "darwin") {
|
||||
if (arch === "arm64") return { target: "aarch64-apple-darwin", ext: "tar.gz" }
|
||||
if (arch === "x64") return { target: "x86_64-apple-darwin", ext: "tar.gz" }
|
||||
if (platform === 'darwin') {
|
||||
if (arch === 'arm64')
|
||||
return { target: 'aarch64-apple-darwin', ext: 'tar.gz' }
|
||||
if (arch === 'x64') return { target: 'x86_64-apple-darwin', ext: 'tar.gz' }
|
||||
throw new Error(`Unsupported macOS arch: ${arch}`)
|
||||
}
|
||||
|
||||
if (platform === "win32") {
|
||||
if (arch === "x64") return { target: "x86_64-pc-windows-msvc", ext: "zip" }
|
||||
if (arch === "arm64") return { target: "aarch64-pc-windows-msvc", ext: "zip" }
|
||||
if (platform === 'win32') {
|
||||
if (arch === 'x64') return { target: 'x86_64-pc-windows-msvc', ext: 'zip' }
|
||||
if (arch === 'arm64')
|
||||
return { target: 'aarch64-pc-windows-msvc', ext: 'zip' }
|
||||
throw new Error(`Unsupported Windows arch: ${arch}`)
|
||||
}
|
||||
|
||||
if (platform === "linux") {
|
||||
if (platform === 'linux') {
|
||||
const isMusl = detectMusl()
|
||||
if (arch === "x64") {
|
||||
return { target: "x86_64-unknown-linux-musl", ext: "tar.gz" }
|
||||
if (arch === 'x64') {
|
||||
return { target: 'x86_64-unknown-linux-musl', ext: 'tar.gz' }
|
||||
}
|
||||
if (arch === "arm64") {
|
||||
if (arch === 'arm64') {
|
||||
return isMusl
|
||||
? { target: "aarch64-unknown-linux-musl", ext: "tar.gz" }
|
||||
: { target: "aarch64-unknown-linux-gnu", ext: "tar.gz" }
|
||||
? { target: 'aarch64-unknown-linux-musl', ext: 'tar.gz' }
|
||||
: { target: 'aarch64-unknown-linux-gnu', ext: 'tar.gz' }
|
||||
}
|
||||
throw new Error(`Unsupported Linux arch: ${arch}`)
|
||||
}
|
||||
@@ -70,7 +82,7 @@ function getPlatformMapping() {
|
||||
}
|
||||
|
||||
function detectMusl() {
|
||||
const muslArch = process.arch === "x64" ? "x86_64" : "aarch64"
|
||||
const muslArch = process.arch === 'x64' ? 'x86_64' : 'aarch64'
|
||||
try {
|
||||
statSync(`/lib/libc.musl-${muslArch}.so.1`)
|
||||
return true
|
||||
@@ -82,24 +94,30 @@ function detectMusl() {
|
||||
// --- Paths ---
|
||||
|
||||
function getVendorDir() {
|
||||
if (existsSync(path.join(projectRoot, "src"))) {
|
||||
return path.resolve(projectRoot, "src", "utils", "vendor", "ripgrep")
|
||||
if (existsSync(path.join(projectRoot, 'src'))) {
|
||||
return path.resolve(projectRoot, 'src', 'utils', 'vendor', 'ripgrep')
|
||||
}
|
||||
return path.resolve(projectRoot, "dist", "vendor", "ripgrep")
|
||||
return path.resolve(projectRoot, 'dist', 'vendor', 'ripgrep')
|
||||
}
|
||||
|
||||
function getBinaryPath() {
|
||||
const dir = getVendorDir()
|
||||
const subdir = `${process.arch}-${process.platform}`
|
||||
const binary = process.platform === "win32" ? "rg.exe" : "rg"
|
||||
const binary = process.platform === 'win32' ? 'rg.exe' : 'rg'
|
||||
return path.resolve(dir, subdir, binary)
|
||||
}
|
||||
|
||||
// --- Download helpers ---
|
||||
|
||||
function proxyEnvSet() {
|
||||
const v = (s) => (s ?? "").trim()
|
||||
return !!(v(process.env.HTTPS_PROXY) || v(process.env.HTTP_PROXY) || v(process.env.ALL_PROXY) || v(process.env.https_proxy) || v(process.env.http_proxy))
|
||||
const v = s => (s ?? '').trim()
|
||||
return !!(
|
||||
v(process.env.HTTPS_PROXY) ||
|
||||
v(process.env.HTTP_PROXY) ||
|
||||
v(process.env.ALL_PROXY) ||
|
||||
v(process.env.https_proxy) ||
|
||||
v(process.env.http_proxy)
|
||||
)
|
||||
}
|
||||
|
||||
function tryPowerShellDownload(url, dest) {
|
||||
@@ -107,17 +125,24 @@ function tryPowerShellDownload(url, dest) {
|
||||
const d = dest.replace(/'/g, "''")
|
||||
const cmd = `Invoke-WebRequest -Uri '${u}' -OutFile '${d}' -UseBasicParsing`
|
||||
const result = spawnSync(
|
||||
"powershell.exe",
|
||||
["-NoProfile", "-NonInteractive", "-ExecutionPolicy", "Bypass", "-Command", cmd],
|
||||
{ stdio: "pipe", windowsHide: true },
|
||||
'powershell.exe',
|
||||
[
|
||||
'-NoProfile',
|
||||
'-NonInteractive',
|
||||
'-ExecutionPolicy',
|
||||
'Bypass',
|
||||
'-Command',
|
||||
cmd,
|
||||
],
|
||||
{ stdio: 'pipe', windowsHide: true },
|
||||
)
|
||||
return result.status === 0 && existsSync(dest) && statSync(dest).size > 0
|
||||
}
|
||||
|
||||
function tryCurlDownload(url, dest) {
|
||||
const curl = process.platform === "win32" ? "curl.exe" : "curl"
|
||||
const result = spawnSync(curl, ["-fsSL", "-L", "--fail", "-o", dest, url], {
|
||||
stdio: "pipe",
|
||||
const curl = process.platform === 'win32' ? 'curl.exe' : 'curl'
|
||||
const result = spawnSync(curl, ['-fsSL', '-L', '--fail', '-o', dest, url], {
|
||||
stdio: 'pipe',
|
||||
windowsHide: true,
|
||||
})
|
||||
return result.status === 0 && existsSync(dest) && statSync(dest).size > 0
|
||||
@@ -126,20 +151,22 @@ function tryCurlDownload(url, dest) {
|
||||
async function fetchRelease(url) {
|
||||
if (proxyEnvSet()) {
|
||||
// Dynamic require so it works in node without bundling issues
|
||||
const undici = require("undici")
|
||||
const undici = require('undici')
|
||||
return await undici.fetch(url, {
|
||||
redirect: "follow",
|
||||
redirect: 'follow',
|
||||
dispatcher: new undici.EnvHttpProxyAgent(),
|
||||
})
|
||||
}
|
||||
// Node 18+ has global fetch, Bun has it too
|
||||
return await fetch(url, { redirect: "follow" })
|
||||
return await fetch(url, { redirect: 'follow' })
|
||||
}
|
||||
|
||||
async function downloadUrlToBuffer(url) {
|
||||
const response = await fetchRelease(url)
|
||||
if (!response.ok) {
|
||||
throw new Error(`Download failed: ${response.status} ${response.statusText}`)
|
||||
throw new Error(
|
||||
`Download failed: ${response.status} ${response.statusText}`,
|
||||
)
|
||||
}
|
||||
return Buffer.from(await response.arrayBuffer())
|
||||
}
|
||||
@@ -152,11 +179,14 @@ async function downloadUrlToBufferWithFallback(url) {
|
||||
firstError = e
|
||||
}
|
||||
|
||||
const tmpRoot = path.join(os.tmpdir(), `ripgrep-dl-${process.pid}-${Date.now()}`)
|
||||
const tmpFile = path.join(tmpRoot, "archive")
|
||||
const tmpRoot = path.join(
|
||||
os.tmpdir(),
|
||||
`ripgrep-dl-${process.pid}-${Date.now()}`,
|
||||
)
|
||||
const tmpFile = path.join(tmpRoot, 'archive')
|
||||
mkdirSync(tmpRoot, { recursive: true })
|
||||
try {
|
||||
if (process.platform === "win32" && tryPowerShellDownload(url, tmpFile)) {
|
||||
if (process.platform === 'win32' && tryPowerShellDownload(url, tmpFile)) {
|
||||
return readFileSync(tmpFile)
|
||||
}
|
||||
if (tryCurlDownload(url, tmpFile)) {
|
||||
@@ -172,8 +202,8 @@ async function downloadUrlToBufferWithFallback(url) {
|
||||
// --- Extract ---
|
||||
|
||||
function findZipEntryKey(files, want) {
|
||||
return Object.keys(files).find((k) => {
|
||||
const norm = k.replace(/\\/g, "/")
|
||||
return Object.keys(files).find(k => {
|
||||
const norm = k.replace(/\\/g, '/')
|
||||
return norm === want || norm.endsWith(`/${want}`)
|
||||
})
|
||||
}
|
||||
@@ -183,7 +213,7 @@ async function extractZip(buffer, binaryPath, extractedBinary) {
|
||||
// Try fflate first (bundled dep)
|
||||
let fflateError
|
||||
try {
|
||||
const { unzipSync } = require("fflate")
|
||||
const { unzipSync } = require('fflate')
|
||||
const unzipped = unzipSync(new Uint8Array(buffer))
|
||||
const key = findZipEntryKey(unzipped, extractedBinary)
|
||||
if (!key) {
|
||||
@@ -196,7 +226,7 @@ async function extractZip(buffer, binaryPath, extractedBinary) {
|
||||
}
|
||||
|
||||
// Fallback: PowerShell Expand-Archive or unzip CLI
|
||||
const tmpDir = path.join(binaryDir, ".tmp-download")
|
||||
const tmpDir = path.join(binaryDir, '.tmp-download')
|
||||
rmSync(tmpDir, { recursive: true, force: true })
|
||||
mkdirSync(tmpDir, { recursive: true })
|
||||
try {
|
||||
@@ -205,12 +235,19 @@ async function extractZip(buffer, binaryPath, extractedBinary) {
|
||||
writeFileSync(archivePath, buffer)
|
||||
|
||||
let extracted = false
|
||||
if (process.platform === "win32") {
|
||||
if (process.platform === 'win32') {
|
||||
const psCmd = `Expand-Archive -Path '${archivePath.replace(/'/g, "''")}' -DestinationPath '${tmpDir.replace(/'/g, "''")}' -Force`
|
||||
const psResult = spawnSync(
|
||||
"powershell.exe",
|
||||
["-NoProfile", "-NonInteractive", "-ExecutionPolicy", "Bypass", "-Command", psCmd],
|
||||
{ stdio: "pipe", windowsHide: true },
|
||||
'powershell.exe',
|
||||
[
|
||||
'-NoProfile',
|
||||
'-NonInteractive',
|
||||
'-ExecutionPolicy',
|
||||
'Bypass',
|
||||
'-Command',
|
||||
psCmd,
|
||||
],
|
||||
{ stdio: 'pipe', windowsHide: true },
|
||||
)
|
||||
if (psResult.status === 0) {
|
||||
extracted = true
|
||||
@@ -218,11 +255,18 @@ async function extractZip(buffer, binaryPath, extractedBinary) {
|
||||
}
|
||||
|
||||
if (!extracted) {
|
||||
const result = spawnSync("unzip", ["-o", archivePath, "-d", tmpDir], { stdio: "pipe" })
|
||||
const result = spawnSync('unzip', ['-o', archivePath, '-d', tmpDir], {
|
||||
stdio: 'pipe',
|
||||
})
|
||||
if (result.status !== 0) {
|
||||
const unzipErr = result.stderr?.toString().trim() || "command not found"
|
||||
const fflateMsg = fflateError instanceof Error ? fflateError.message : String(fflateError)
|
||||
throw new Error(`zip extraction failed (fflate: ${fflateMsg}; unzip: ${unzipErr})`)
|
||||
const unzipErr = result.stderr?.toString().trim() || 'command not found'
|
||||
const fflateMsg =
|
||||
fflateError instanceof Error
|
||||
? fflateError.message
|
||||
: String(fflateError)
|
||||
throw new Error(
|
||||
`zip extraction failed (fflate: ${fflateMsg}; unzip: ${unzipErr})`,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -238,13 +282,15 @@ async function extractZip(buffer, binaryPath, extractedBinary) {
|
||||
|
||||
async function extractTarGz(buffer, binaryPath, extractedBinary, assetName) {
|
||||
const binaryDir = path.dirname(binaryPath)
|
||||
const tmpDir = path.join(binaryDir, ".tmp-download")
|
||||
const tmpDir = path.join(binaryDir, '.tmp-download')
|
||||
rmSync(tmpDir, { recursive: true, force: true })
|
||||
mkdirSync(tmpDir, { recursive: true })
|
||||
try {
|
||||
const archivePath = path.join(tmpDir, assetName)
|
||||
writeFileSync(archivePath, buffer)
|
||||
const result = spawnSync("tar", ["xzf", archivePath, "-C", tmpDir], { stdio: "pipe" })
|
||||
const result = spawnSync('tar', ['xzf', archivePath, '-C', tmpDir], {
|
||||
stdio: 'pipe',
|
||||
})
|
||||
if (result.status !== 0) {
|
||||
throw new Error(`tar extract failed: ${result.stderr?.toString()}`)
|
||||
}
|
||||
@@ -267,7 +313,7 @@ async function downloadAndExtract() {
|
||||
const binaryPath = getBinaryPath()
|
||||
const binaryDir = path.dirname(binaryPath)
|
||||
|
||||
const force = process.argv.includes("--force")
|
||||
const force = process.argv.includes('--force')
|
||||
if (!force && existsSync(binaryPath)) {
|
||||
const stat = statSync(binaryPath)
|
||||
if (stat.size > 0) {
|
||||
@@ -278,11 +324,11 @@ async function downloadAndExtract() {
|
||||
|
||||
console.log(`[ripgrep] Downloading v${RG_VERSION} for ${target}...`)
|
||||
|
||||
const extractedBinary = process.platform === "win32" ? "rg.exe" : "rg"
|
||||
const extractedBinary = process.platform === 'win32' ? 'rg.exe' : 'rg'
|
||||
|
||||
const mirrors = [RELEASE_BASE]
|
||||
if (RELEASE_BASE === DEFAULT_RELEASE_BASE.replace(/\/$/, "")) {
|
||||
mirrors.push(MIRROR_RELEASE_BASE.replace(/\/$/, ""))
|
||||
if (RELEASE_BASE === DEFAULT_RELEASE_BASE.replace(/\/$/, '')) {
|
||||
mirrors.push(MIRROR_RELEASE_BASE.replace(/\/$/, ''))
|
||||
}
|
||||
|
||||
let buffer
|
||||
@@ -294,7 +340,9 @@ async function downloadAndExtract() {
|
||||
buffer = await downloadUrlToBufferWithFallback(url)
|
||||
break
|
||||
} catch (e) {
|
||||
console.warn(`[ripgrep] Download from ${base} failed: ${e instanceof Error ? e.message : e}`)
|
||||
console.warn(
|
||||
`[ripgrep] Download from ${base} failed: ${e instanceof Error ? e.message : e}`,
|
||||
)
|
||||
lastError = e
|
||||
}
|
||||
}
|
||||
@@ -307,13 +355,13 @@ async function downloadAndExtract() {
|
||||
|
||||
mkdirSync(binaryDir, { recursive: true })
|
||||
|
||||
if (ext === "tar.gz") {
|
||||
if (ext === 'tar.gz') {
|
||||
await extractTarGz(buffer, binaryPath, extractedBinary, assetName)
|
||||
} else {
|
||||
await extractZip(buffer, binaryPath, extractedBinary)
|
||||
}
|
||||
|
||||
if (process.platform !== "win32") {
|
||||
if (process.platform !== 'win32') {
|
||||
chmodSync(binaryPath, 0o755)
|
||||
}
|
||||
|
||||
@@ -321,7 +369,7 @@ async function downloadAndExtract() {
|
||||
} catch (e) {
|
||||
const msg = e instanceof Error ? e.message : String(e)
|
||||
const hint =
|
||||
"Check network or set HTTPS_PROXY. If GitHub is blocked, set RIPGREP_DOWNLOAD_BASE to a mirror (see script header)."
|
||||
'Check network or set HTTPS_PROXY. If GitHub is blocked, set RIPGREP_DOWNLOAD_BASE to a mirror (see script header).'
|
||||
throw new Error(`${msg} ${hint}`)
|
||||
}
|
||||
}
|
||||
@@ -330,10 +378,12 @@ async function main() {
|
||||
await downloadAndExtract()
|
||||
}
|
||||
|
||||
main().catch((error) => {
|
||||
main().catch(error => {
|
||||
const msg = error instanceof Error ? error.message : String(error)
|
||||
console.error(`[postinstall] ripgrep download failed (non-fatal): ${msg}`)
|
||||
console.error(`[postinstall] You can install ripgrep manually: https://github.com/BurntSushi/ripgrep#installation`)
|
||||
console.error(
|
||||
`[postinstall] You can install ripgrep manually: https://github.com/BurntSushi/ripgrep#installation`,
|
||||
)
|
||||
// Never exit with error code — postinstall must not break install
|
||||
process.exit(0)
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user