fix: expand PATH search for claude binary in packaged app
The claude-status endpoint now searches common installation paths (/usr/local/bin, /opt/homebrew/bin, ~/.npm-global/bin, ~/.local/bin, ~/.claude/bin) and uses `which` with expanded PATH as fallback, fixing "Disconnected" status in packaged builds. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
1 parent
43e79dec04
commit
2c5280cd77
1 file changed
+62
-3
@@ -1,14 +1,73 @@
|
||||
import { NextResponse } from 'next/server';
|
||||
import { execFile } from 'child_process';
|
||||
import { execFile, execFileSync } from 'child_process';
|
||||
import { promisify } from 'util';
|
||||
import os from 'os';
|
||||
import path from 'path';
|
||||
|
||||
const execFileAsync = promisify(execFile);
|
||||
|
||||
function getExpandedPath(): string {
|
||||
const home = os.homedir();
|
||||
const extra = [
|
||||
'/usr/local/bin',
|
||||
'/opt/homebrew/bin',
|
||||
'/usr/bin',
|
||||
'/bin',
|
||||
path.join(home, '.npm-global', 'bin'),
|
||||
path.join(home, '.nvm', 'current', 'bin'),
|
||||
path.join(home, '.local', 'bin'),
|
||||
path.join(home, '.claude', 'bin'),
|
||||
];
|
||||
const current = process.env.PATH || '';
|
||||
const parts = current.split(':');
|
||||
for (const p of extra) {
|
||||
if (!parts.includes(p)) parts.push(p);
|
||||
}
|
||||
return parts.join(':');
|
||||
}
|
||||
|
||||
function findClaudePath(): string | null {
|
||||
const home = os.homedir();
|
||||
const candidates = [
|
||||
'/usr/local/bin/claude',
|
||||
'/opt/homebrew/bin/claude',
|
||||
path.join(home, '.npm-global', 'bin', 'claude'),
|
||||
path.join(home, '.local', 'bin', 'claude'),
|
||||
path.join(home, '.claude', 'bin', 'claude'),
|
||||
];
|
||||
|
||||
for (const p of candidates) {
|
||||
try {
|
||||
execFileSync(p, ['--version'], { timeout: 3000, stdio: 'pipe' });
|
||||
return p;
|
||||
} catch {
|
||||
// not found, try next
|
||||
}
|
||||
}
|
||||
|
||||
// Fallback: use `which claude` with expanded PATH
|
||||
try {
|
||||
const result = execFileSync('/usr/bin/which', ['claude'], {
|
||||
timeout: 3000,
|
||||
stdio: 'pipe',
|
||||
env: { ...process.env, PATH: getExpandedPath() },
|
||||
});
|
||||
return result.toString().trim() || null;
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
export async function GET() {
|
||||
try {
|
||||
const { stdout } = await execFileAsync('claude', ['--version'], {
|
||||
const claudePath = findClaudePath();
|
||||
if (!claudePath) {
|
||||
return NextResponse.json({ connected: false, version: null });
|
||||
}
|
||||
|
||||
const { stdout } = await execFileAsync(claudePath, ['--version'], {
|
||||
timeout: 5000,
|
||||
env: { ...process.env, PATH: process.env.PATH },
|
||||
env: { ...process.env, PATH: getExpandedPath() },
|
||||
});
|
||||
const version = stdout.trim();
|
||||
return NextResponse.json({ connected: true, version });
|
||||
|
||||
Reference in new issue
Block a user