37 lines
1.1 KiB
TypeScript
37 lines
1.1 KiB
TypeScript
|
|
import { execSync } from 'node:child_process'
|
||
|
|
import { existsSync } from 'node:fs'
|
||
|
|
import { homedir } from 'node:os'
|
||
|
|
import { join } from 'node:path'
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Resolve the absolute path to the standalone `claude` binary.
|
||
|
|
*
|
||
|
|
* When Nitro bundles @anthropic-ai/claude-agent-sdk, the SDK's internal
|
||
|
|
* `import.meta.url`-based resolution to find its own `cli.js` breaks.
|
||
|
|
* Instead we locate the standalone native binary and pass it via
|
||
|
|
* `pathToClaudeCodeExecutable` — the SDK detects non-.js paths as native
|
||
|
|
* binaries and spawns them directly (no `node` wrapper needed).
|
||
|
|
*/
|
||
|
|
export function resolveClaudeCli(): string | undefined {
|
||
|
|
// 1. Try `which claude` (works when PATH is correctly set)
|
||
|
|
try {
|
||
|
|
const p = execSync('which claude 2>/dev/null', {
|
||
|
|
encoding: 'utf-8',
|
||
|
|
timeout: 3000,
|
||
|
|
}).trim()
|
||
|
|
if (p && existsSync(p)) return p
|
||
|
|
} catch { /* not in PATH */ }
|
||
|
|
|
||
|
|
// 2. Common install locations
|
||
|
|
const candidates = [
|
||
|
|
join(homedir(), '.local', 'bin', 'claude'),
|
||
|
|
'/usr/local/bin/claude',
|
||
|
|
'/opt/homebrew/bin/claude',
|
||
|
|
]
|
||
|
|
for (const c of candidates) {
|
||
|
|
if (existsSync(c)) return c
|
||
|
|
}
|
||
|
|
|
||
|
|
return undefined
|
||
|
|
}
|