Skip to content

Commit 316cdc1

Browse files
committed
fix(ast-grep): validate binary before using, prioritize homebrew path
- Add isValidBinary() check: file must be >10KB (placeholder files are ~100 bytes) - Check homebrew paths first on macOS (most reliable) - Check cached binary second - npm package paths last (prone to placeholder issues) Fixes ENOEXEC error when @ast-grep/cli has placeholder instead of real binary
1 parent f19cd8f commit 316cdc1

File tree

1 file changed

+25
-16
lines changed

1 file changed

+25
-16
lines changed

src/tools/ast-grep/constants.ts

Lines changed: 25 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -22,16 +22,39 @@ function getPlatformPackageName(): string | null {
2222
return platformMap[`${platform}-${arch}`] ?? null
2323
}
2424

25+
function isValidBinary(filePath: string): boolean {
26+
try {
27+
const stats = require("fs").statSync(filePath)
28+
return stats.size > 10000
29+
} catch {
30+
return false
31+
}
32+
}
33+
2534
export function findSgCliPathSync(): string | null {
2635
const binaryName = process.platform === "win32" ? "sg.exe" : "sg"
2736

37+
if (process.platform === "darwin") {
38+
const homebrewPaths = ["/opt/homebrew/bin/sg", "/usr/local/bin/sg"]
39+
for (const path of homebrewPaths) {
40+
if (existsSync(path) && isValidBinary(path)) {
41+
return path
42+
}
43+
}
44+
}
45+
46+
const cachedPath = getCachedBinaryPath()
47+
if (cachedPath && isValidBinary(cachedPath)) {
48+
return cachedPath
49+
}
50+
2851
try {
2952
const require = createRequire(import.meta.url)
3053
const cliPkgPath = require.resolve("@ast-grep/cli/package.json")
3154
const cliDir = dirname(cliPkgPath)
3255
const sgPath = join(cliDir, binaryName)
3356

34-
if (existsSync(sgPath)) {
57+
if (existsSync(sgPath) && isValidBinary(sgPath)) {
3558
return sgPath
3659
}
3760
} catch {
@@ -47,28 +70,14 @@ export function findSgCliPathSync(): string | null {
4770
const astGrepName = process.platform === "win32" ? "ast-grep.exe" : "ast-grep"
4871
const binaryPath = join(pkgDir, astGrepName)
4972

50-
if (existsSync(binaryPath)) {
73+
if (existsSync(binaryPath) && isValidBinary(binaryPath)) {
5174
return binaryPath
5275
}
5376
} catch {
5477
// Platform-specific package not installed
5578
}
5679
}
5780

58-
if (process.platform === "darwin") {
59-
const homebrewPaths = ["/opt/homebrew/bin/sg", "/usr/local/bin/sg"]
60-
for (const path of homebrewPaths) {
61-
if (existsSync(path)) {
62-
return path
63-
}
64-
}
65-
}
66-
67-
const cachedPath = getCachedBinaryPath()
68-
if (cachedPath) {
69-
return cachedPath
70-
}
71-
7281
return null
7382
}
7483

0 commit comments

Comments
 (0)