From d1552487d87492522e0b371313db86d2be39a720 Mon Sep 17 00:00:00 2001 From: Erik M Jacobs Date: Sun, 18 Jan 2026 20:32:16 -0500 Subject: [PATCH] fix: Windows support for Claude CLI path resolution - Add Windows-specific paths to search for Claude CLI executable - Use 'where' command instead of 'which' on Windows - Return full path from commandExists() to fix node-pty spawn issues - Add CLAUDE_COMMAND environment variable override - Use USERPROFILE for home directory on Windows node-pty on Windows requires the full path to executables, not just the command name. This change ensures the full path is resolved and used when spawning the Claude process. Co-Authored-By: Claude Opus 4.5 --- src/claude-bridge.js | 41 +++++++++++++++++++++++++++++++++++------ 1 file changed, 35 insertions(+), 6 deletions(-) diff --git a/src/claude-bridge.js b/src/claude-bridge.js index c7b4fee..268a956 100644 --- a/src/claude-bridge.js +++ b/src/claude-bridge.js @@ -9,22 +9,47 @@ class ClaudeBridge { } findClaudeCommand() { - const possibleCommands = [ + // Allow override via environment variable + if (process.env.CLAUDE_COMMAND) { + console.log(`Using CLAUDE_COMMAND from environment: ${process.env.CLAUDE_COMMAND}`); + return process.env.CLAUDE_COMMAND; + } + + const isWindows = process.platform === 'win32'; + const homeDir = process.env.HOME || process.env.USERPROFILE || '/'; + + const possibleCommands = isWindows ? [ + 'claude', + 'claude.exe', + 'claude-code', + 'claude-code.exe', + path.join(homeDir, '.local', 'bin', 'claude.exe'), + path.join(homeDir, '.claude', 'local', 'claude.exe'), + path.join(homeDir, 'AppData', 'Local', 'Programs', 'claude', 'claude.exe'), + path.join(homeDir, 'AppData', 'Roaming', 'npm', 'claude.cmd'), + ] : [ '/home/ec2-user/.claude/local/claude', 'claude', 'claude-code', - path.join(process.env.HOME || '/', '.claude', 'local', 'claude'), - path.join(process.env.HOME || '/', '.local', 'bin', 'claude'), + path.join(homeDir, '.claude', 'local', 'claude'), + path.join(homeDir, '.local', 'bin', 'claude'), '/usr/local/bin/claude', '/usr/bin/claude' ]; for (const cmd of possibleCommands) { try { - if (fs.existsSync(cmd) || this.commandExists(cmd)) { + if (fs.existsSync(cmd)) { console.log(`Found Claude command at: ${cmd}`); return cmd; } + const resolvedPath = this.commandExists(cmd); + if (resolvedPath) { + // Use the full path if available (string), otherwise use the command name + const finalCmd = typeof resolvedPath === 'string' ? resolvedPath : cmd; + console.log(`Found Claude command at: ${finalCmd}`); + return finalCmd; + } } catch (error) { continue; } @@ -35,9 +60,13 @@ class ClaudeBridge { } commandExists(command) { + const isWindows = process.platform === 'win32'; + const whichCmd = isWindows ? 'where' : 'which'; try { - require('child_process').execFileSync('which', [command], { stdio: 'ignore' }); - return true; + const result = require('child_process').execFileSync(whichCmd, [command], { encoding: 'utf8' }); + // Return the first line (full path) on Windows, or the path on Unix + const fullPath = result.split(/\r?\n/)[0].trim(); + return fullPath || true; } catch (error) { return false; }