feat(v2): auto-detect Claude CLI path and pass to SDK via pathToClaudeCodeExecutable
Both sidecar runners (agent-runner.ts and agent-runner-deno.ts) now include findClaudeCli() which checks common paths (~/.local/bin/claude, ~/.claude/local/claude, /usr/local/bin/claude, /usr/bin/claude) and falls back to `which claude`. The resolved path is passed to the SDK query() options as pathToClaudeCodeExecutable. If the CLI is not found, an agent_error is emitted immediately instead of a cryptic SDK failure.
This commit is contained in:
parent
14b62da729
commit
d35b3dc7fc
2 changed files with 68 additions and 0 deletions
|
|
@ -71,10 +71,16 @@ async function handleQuery(msg: QueryMessage) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!claudePath) {
|
||||||
|
send({ type: "agent_error", sessionId, message: "Claude CLI not found. Install Claude Code first." });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const q = query({
|
const q = query({
|
||||||
prompt,
|
prompt,
|
||||||
options: {
|
options: {
|
||||||
|
pathToClaudeCodeExecutable: claudePath,
|
||||||
abortController: controller,
|
abortController: controller,
|
||||||
cwd: cwd || Deno.cwd(),
|
cwd: cwd || Deno.cwd(),
|
||||||
env: cleanEnv,
|
env: cleanEnv,
|
||||||
|
|
@ -144,6 +150,32 @@ function handleStop(msg: StopMessage) {
|
||||||
controller.abort();
|
controller.abort();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function findClaudeCli(): string | undefined {
|
||||||
|
const home = Deno.env.get("HOME") ?? Deno.env.get("USERPROFILE") ?? "";
|
||||||
|
const candidates = [
|
||||||
|
`${home}/.local/bin/claude`,
|
||||||
|
`${home}/.claude/local/claude`,
|
||||||
|
"/usr/local/bin/claude",
|
||||||
|
"/usr/bin/claude",
|
||||||
|
];
|
||||||
|
for (const p of candidates) {
|
||||||
|
try { Deno.statSync(p); return p; } catch { /* not found */ }
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
const proc = new Deno.Command("which", { args: ["claude"], stdout: "piped", stderr: "null" });
|
||||||
|
const out = new TextDecoder().decode(proc.outputSync().stdout).trim();
|
||||||
|
if (out) return out.split("\n")[0];
|
||||||
|
} catch { /* not found */ }
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
const claudePath = findClaudeCli();
|
||||||
|
if (claudePath) {
|
||||||
|
log(`Found Claude CLI at ${claudePath}`);
|
||||||
|
} else {
|
||||||
|
log("WARNING: Claude CLI not found — agent sessions will fail");
|
||||||
|
}
|
||||||
|
|
||||||
// Main: read NDJSON from stdin
|
// Main: read NDJSON from stdin
|
||||||
log("Sidecar started (Deno)");
|
log("Sidecar started (Deno)");
|
||||||
send({ type: "ready" });
|
send({ type: "ready" });
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,10 @@
|
||||||
|
|
||||||
import { stdin, stdout, stderr } from 'process';
|
import { stdin, stdout, stderr } from 'process';
|
||||||
import { createInterface } from 'readline';
|
import { createInterface } from 'readline';
|
||||||
|
import { execSync } from 'child_process';
|
||||||
|
import { existsSync } from 'fs';
|
||||||
|
import { join } from 'path';
|
||||||
|
import { homedir } from 'os';
|
||||||
import { query, type Query } from '@anthropic-ai/claude-agent-sdk';
|
import { query, type Query } from '@anthropic-ai/claude-agent-sdk';
|
||||||
|
|
||||||
const rl = createInterface({ input: stdin });
|
const rl = createInterface({ input: stdin });
|
||||||
|
|
@ -81,9 +85,15 @@ async function handleQuery(msg: QueryMessage) {
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
if (!claudePath) {
|
||||||
|
send({ type: 'agent_error', sessionId, message: 'Claude CLI not found. Install Claude Code first.' });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const q = query({
|
const q = query({
|
||||||
prompt,
|
prompt,
|
||||||
options: {
|
options: {
|
||||||
|
pathToClaudeCodeExecutable: claudePath,
|
||||||
abortController: controller,
|
abortController: controller,
|
||||||
cwd: cwd || process.cwd(),
|
cwd: cwd || process.cwd(),
|
||||||
env: cleanEnv,
|
env: cleanEnv,
|
||||||
|
|
@ -155,5 +165,31 @@ function handleStop(msg: StopMessage) {
|
||||||
session.controller.abort();
|
session.controller.abort();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function findClaudeCli(): string | undefined {
|
||||||
|
// Check common locations
|
||||||
|
const candidates = [
|
||||||
|
join(homedir(), '.local', 'bin', 'claude'),
|
||||||
|
join(homedir(), '.claude', 'local', 'claude'),
|
||||||
|
'/usr/local/bin/claude',
|
||||||
|
'/usr/bin/claude',
|
||||||
|
];
|
||||||
|
for (const p of candidates) {
|
||||||
|
if (existsSync(p)) return p;
|
||||||
|
}
|
||||||
|
// Fall back to which/where
|
||||||
|
try {
|
||||||
|
return execSync('which claude 2>/dev/null || where claude 2>nul', { encoding: 'utf-8' }).trim().split('\n')[0];
|
||||||
|
} catch {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const claudePath = findClaudeCli();
|
||||||
|
if (claudePath) {
|
||||||
|
log(`Found Claude CLI at ${claudePath}`);
|
||||||
|
} else {
|
||||||
|
log('WARNING: Claude CLI not found — agent sessions will fail');
|
||||||
|
}
|
||||||
|
|
||||||
log('Sidecar started');
|
log('Sidecar started');
|
||||||
send({ type: 'ready' });
|
send({ type: 'ready' });
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue