Fix: Add cross-platform Claude path detection to feature branch
Applied v4.2.11 fix from main branch: - Implemented explicit which/where command execution - Unix/macOS: Uses 'which claude' command - Windows: Uses 'where claude' command (CMD and PowerShell compatible) - Fallback to CLAUDE_CODE_PATH environment variable - Handles Windows multiple results (takes first match) Technical changes: - Added findClaudePath() helper using child_process.execSync - Platform detection via process.platform === 'win32' - Updated src/sdk/worker.ts with explicit path detection - Updated src/services/worker-service.ts with explicit path detection - Built worker-service.cjs reflects changes This fixes SDK auto-detection failure that returned undefined path. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
File diff suppressed because one or more lines are too long
+34
-2
@@ -13,6 +13,7 @@ declare global {
|
|||||||
|
|
||||||
import net from 'net';
|
import net from 'net';
|
||||||
import { unlinkSync, existsSync } from 'fs';
|
import { unlinkSync, existsSync } from 'fs';
|
||||||
|
import { execSync } from 'child_process';
|
||||||
import { query } from '@anthropic-ai/claude-agent-sdk';
|
import { query } from '@anthropic-ai/claude-agent-sdk';
|
||||||
import type { SDKUserMessage, SDKSystemMessage } from '@anthropic-ai/claude-agent-sdk';
|
import type { SDKUserMessage, SDKSystemMessage } from '@anthropic-ai/claude-agent-sdk';
|
||||||
import { SessionStore } from '../services/sqlite/SessionStore.js';
|
import { SessionStore } from '../services/sqlite/SessionStore.js';
|
||||||
@@ -24,6 +25,35 @@ import type { SDKSession } from './prompts.js';
|
|||||||
const MODEL = 'claude-sonnet-4-5';
|
const MODEL = 'claude-sonnet-4-5';
|
||||||
const DISALLOWED_TOOLS = ['Glob', 'Grep', 'ListMcpResourcesTool', 'WebSearch'];
|
const DISALLOWED_TOOLS = ['Glob', 'Grep', 'ListMcpResourcesTool', 'WebSearch'];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Find Claude Code executable path using which (Unix/Mac) or where (Windows)
|
||||||
|
*/
|
||||||
|
function findClaudePath(): string {
|
||||||
|
try {
|
||||||
|
// Try environment variable first
|
||||||
|
if (process.env.CLAUDE_CODE_PATH) {
|
||||||
|
return process.env.CLAUDE_CODE_PATH;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Use which on Unix/Mac, where on Windows
|
||||||
|
const command = process.platform === 'win32' ? 'where claude' : 'which claude';
|
||||||
|
const result = execSync(command, { encoding: 'utf8' }).trim();
|
||||||
|
|
||||||
|
// On Windows, 'where' returns multiple lines if there are multiple matches, take the first
|
||||||
|
const path = result.split('\n')[0].trim();
|
||||||
|
|
||||||
|
if (!path) {
|
||||||
|
throw new Error('Claude executable not found in PATH');
|
||||||
|
}
|
||||||
|
|
||||||
|
console.error(`[SDK Worker] Found Claude executable: ${path}`);
|
||||||
|
return path;
|
||||||
|
} catch (error: any) {
|
||||||
|
console.error('[SDK Worker] Failed to find Claude executable:', error.message);
|
||||||
|
throw new Error('Claude Code executable not found. Please ensure claude is in your PATH or set CLAUDE_CODE_PATH environment variable.');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
interface ObservationMessage {
|
interface ObservationMessage {
|
||||||
type: 'observation';
|
type: 'observation';
|
||||||
tool_name: string;
|
tool_name: string;
|
||||||
@@ -282,14 +312,16 @@ class SDKWorker {
|
|||||||
* Run SDK agent with streaming input mode
|
* Run SDK agent with streaming input mode
|
||||||
*/
|
*/
|
||||||
private async runSDKAgent(): Promise<void> {
|
private async runSDKAgent(): Promise<void> {
|
||||||
// Find Claude Code executable
|
const claudePath = findClaudePath();
|
||||||
|
console.error(`[SDK Worker DEBUG] Using Claude executable: ${claudePath}`);
|
||||||
|
|
||||||
const queryResult = query({
|
const queryResult = query({
|
||||||
prompt: this.createMessageGenerator(),
|
prompt: this.createMessageGenerator(),
|
||||||
options: {
|
options: {
|
||||||
model: MODEL,
|
model: MODEL,
|
||||||
disallowedTools: DISALLOWED_TOOLS,
|
disallowedTools: DISALLOWED_TOOLS,
|
||||||
abortController: this.abortController
|
abortController: this.abortController,
|
||||||
|
pathToClaudeCodeExecutable: claudePath
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -12,11 +12,41 @@ import { parseObservations, parseSummary } from '../sdk/parser.js';
|
|||||||
import type { SDKSession } from '../sdk/prompts.js';
|
import type { SDKSession } from '../sdk/prompts.js';
|
||||||
import { logger } from '../utils/logger.js';
|
import { logger } from '../utils/logger.js';
|
||||||
import { ensureAllDataDirs } from '../shared/paths.js';
|
import { ensureAllDataDirs } from '../shared/paths.js';
|
||||||
|
import { execSync } from 'child_process';
|
||||||
|
|
||||||
const MODEL = process.env.CLAUDE_MEM_MODEL || 'claude-sonnet-4-5';
|
const MODEL = process.env.CLAUDE_MEM_MODEL || 'claude-sonnet-4-5';
|
||||||
const DISALLOWED_TOOLS = ['Glob', 'Grep', 'ListMcpResourcesTool', 'WebSearch'];
|
const DISALLOWED_TOOLS = ['Glob', 'Grep', 'ListMcpResourcesTool', 'WebSearch'];
|
||||||
const FIXED_PORT = parseInt(process.env.CLAUDE_MEM_WORKER_PORT || '37777', 10);
|
const FIXED_PORT = parseInt(process.env.CLAUDE_MEM_WORKER_PORT || '37777', 10);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Find Claude Code executable path using which (Unix/Mac) or where (Windows)
|
||||||
|
*/
|
||||||
|
function findClaudePath(): string {
|
||||||
|
try {
|
||||||
|
// Try environment variable first
|
||||||
|
if (process.env.CLAUDE_CODE_PATH) {
|
||||||
|
return process.env.CLAUDE_CODE_PATH;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Use which on Unix/Mac, where on Windows
|
||||||
|
const command = process.platform === 'win32' ? 'where claude' : 'which claude';
|
||||||
|
const result = execSync(command, { encoding: 'utf8' }).trim();
|
||||||
|
|
||||||
|
// On Windows, 'where' returns multiple lines if there are multiple matches, take the first
|
||||||
|
const path = result.split('\n')[0].trim();
|
||||||
|
|
||||||
|
if (!path) {
|
||||||
|
throw new Error('Claude executable not found in PATH');
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.info('SYSTEM', `Found Claude executable: ${path}`);
|
||||||
|
return path;
|
||||||
|
} catch (error: any) {
|
||||||
|
logger.failure('SYSTEM', 'Failed to find Claude executable', {}, error);
|
||||||
|
throw new Error('Claude Code executable not found. Please ensure claude is in your PATH or set CLAUDE_CODE_PATH environment variable.');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
interface ObservationMessage {
|
interface ObservationMessage {
|
||||||
type: 'observation';
|
type: 'observation';
|
||||||
tool_name: string;
|
tool_name: string;
|
||||||
@@ -345,13 +375,17 @@ class WorkerService {
|
|||||||
private async runSDKAgent(session: ActiveSession): Promise<void> {
|
private async runSDKAgent(session: ActiveSession): Promise<void> {
|
||||||
logger.info('SDK', 'Agent starting', { sessionId: session.sessionDbId });
|
logger.info('SDK', 'Agent starting', { sessionId: session.sessionDbId });
|
||||||
|
|
||||||
|
const claudePath = findClaudePath();
|
||||||
|
logger.info('SDK', `Using Claude executable: ${claudePath}`, { sessionId: session.sessionDbId });
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const queryResult = query({
|
const queryResult = query({
|
||||||
prompt: this.createMessageGenerator(session),
|
prompt: this.createMessageGenerator(session),
|
||||||
options: {
|
options: {
|
||||||
model: MODEL,
|
model: MODEL,
|
||||||
disallowedTools: DISALLOWED_TOOLS,
|
disallowedTools: DISALLOWED_TOOLS,
|
||||||
abortController: session.abortController
|
abortController: session.abortController,
|
||||||
|
pathToClaudeCodeExecutable: claudePath
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user