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 { unlinkSync, existsSync } from 'fs';
|
||||
import { execSync } from 'child_process';
|
||||
import { query } from '@anthropic-ai/claude-agent-sdk';
|
||||
import type { SDKUserMessage, SDKSystemMessage } from '@anthropic-ai/claude-agent-sdk';
|
||||
import { SessionStore } from '../services/sqlite/SessionStore.js';
|
||||
@@ -24,6 +25,35 @@ import type { SDKSession } from './prompts.js';
|
||||
const MODEL = 'claude-sonnet-4-5';
|
||||
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 {
|
||||
type: 'observation';
|
||||
tool_name: string;
|
||||
@@ -282,14 +312,16 @@ class SDKWorker {
|
||||
* Run SDK agent with streaming input mode
|
||||
*/
|
||||
private async runSDKAgent(): Promise<void> {
|
||||
// Find Claude Code executable
|
||||
const claudePath = findClaudePath();
|
||||
console.error(`[SDK Worker DEBUG] Using Claude executable: ${claudePath}`);
|
||||
|
||||
const queryResult = query({
|
||||
prompt: this.createMessageGenerator(),
|
||||
options: {
|
||||
model: MODEL,
|
||||
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 { logger } from '../utils/logger.js';
|
||||
import { ensureAllDataDirs } from '../shared/paths.js';
|
||||
import { execSync } from 'child_process';
|
||||
|
||||
const MODEL = process.env.CLAUDE_MEM_MODEL || 'claude-sonnet-4-5';
|
||||
const DISALLOWED_TOOLS = ['Glob', 'Grep', 'ListMcpResourcesTool', 'WebSearch'];
|
||||
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 {
|
||||
type: 'observation';
|
||||
tool_name: string;
|
||||
@@ -345,13 +375,17 @@ class WorkerService {
|
||||
private async runSDKAgent(session: ActiveSession): Promise<void> {
|
||||
logger.info('SDK', 'Agent starting', { sessionId: session.sessionDbId });
|
||||
|
||||
const claudePath = findClaudePath();
|
||||
logger.info('SDK', `Using Claude executable: ${claudePath}`, { sessionId: session.sessionDbId });
|
||||
|
||||
try {
|
||||
const queryResult = query({
|
||||
prompt: this.createMessageGenerator(session),
|
||||
options: {
|
||||
model: MODEL,
|
||||
disallowedTools: DISALLOWED_TOOLS,
|
||||
abortController: session.abortController
|
||||
abortController: session.abortController,
|
||||
pathToClaudeCodeExecutable: claudePath
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user