fix: parse Windows .cmd wrapper to extract real CLI script path
v0.10.7 skipped .cmd wrappers entirely, but the SDK's internal fallback can't find the CLI either. Now we read the .cmd file, extract the actual .js path (e.g. node_modules/@anthropic-ai/ claude-code/cli.js), resolve %~dp0 to the wrapper's directory, and pass the resolved script path to the SDK. Regex patterns are scoped to paths containing "claude" to avoid matching unrelated .js files in the wrapper. Bump version to 0.10.8. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
1 parent
c0e96bd1aa
commit
01e7e0c1e3
3 files changed
+46
-6
No files matched your search
Generated
+2
-2
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "codepilot",
|
||||
"version": "0.10.7",
|
||||
"version": "0.10.8",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "codepilot",
|
||||
"version": "0.10.7",
|
||||
"version": "0.10.8",
|
||||
"dependencies": {
|
||||
"@anthropic-ai/claude-agent-sdk": "^0.2.33",
|
||||
"@hugeicons/core-free-icons": "^3.1.1",
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "codepilot",
|
||||
"version": "0.10.7",
|
||||
"version": "0.10.8",
|
||||
"private": true,
|
||||
"author": {
|
||||
"name": "op7418",
|
||||
|
||||
@@ -49,6 +49,41 @@ function sanitizeEnv(env: Record<string, string>): Record<string, string> {
|
||||
return clean;
|
||||
}
|
||||
|
||||
/**
|
||||
* On Windows, npm installs CLI tools as .cmd wrappers that can't be
|
||||
* spawned without shell:true. Parse the wrapper to extract the real
|
||||
* .js script path so we can pass it to the SDK directly.
|
||||
*/
|
||||
function resolveScriptFromCmd(cmdPath: string): string | undefined {
|
||||
try {
|
||||
const content = fs.readFileSync(cmdPath, 'utf-8');
|
||||
const cmdDir = path.dirname(cmdPath);
|
||||
|
||||
// npm .cmd wrappers typically contain a line like:
|
||||
// "%~dp0\node_modules\@anthropic-ai\claude-code\cli.js" %*
|
||||
// Match paths containing claude-code or claude-agent and ending in .js
|
||||
const patterns = [
|
||||
// Quoted: "%~dp0\...\cli.js"
|
||||
/"%~dp0\\([^"]*claude[^"]*\.js)"/i,
|
||||
// Unquoted: %~dp0\...\cli.js
|
||||
/%~dp0\\(\S*claude\S*\.js)/i,
|
||||
// Quoted with %dp0%: "%dp0%\...\cli.js"
|
||||
/"%dp0%\\([^"]*claude[^"]*\.js)"/i,
|
||||
];
|
||||
|
||||
for (const re of patterns) {
|
||||
const m = content.match(re);
|
||||
if (m) {
|
||||
const resolved = path.normalize(path.join(cmdDir, m[1]));
|
||||
if (fs.existsSync(resolved)) return resolved;
|
||||
}
|
||||
}
|
||||
} catch {
|
||||
// ignore read errors
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
let cachedClaudePath: string | null | undefined;
|
||||
|
||||
function findClaudePath(): string | undefined {
|
||||
@@ -296,13 +331,18 @@ export function streamClaude(options: ClaudeStreamOptions): ReadableStream<strin
|
||||
|
||||
// Find claude binary for packaged app where PATH is limited.
|
||||
// On Windows, npm installs Claude CLI as a .cmd wrapper which cannot
|
||||
// be spawned directly without shell:true — skip it and let the SDK
|
||||
// resolve the executable internally.
|
||||
// be spawned directly without shell:true. Parse the wrapper to
|
||||
// extract the real .js script path and pass that to the SDK instead.
|
||||
const claudePath = findClaudePath();
|
||||
if (claudePath) {
|
||||
const ext = path.extname(claudePath).toLowerCase();
|
||||
if (ext === '.cmd' || ext === '.bat') {
|
||||
console.warn('[claude-client] Ignoring .cmd/.bat wrapper, falling back to SDK resolution:', claudePath);
|
||||
const scriptPath = resolveScriptFromCmd(claudePath);
|
||||
if (scriptPath) {
|
||||
queryOptions.pathToClaudeCodeExecutable = scriptPath;
|
||||
} else {
|
||||
console.warn('[claude-client] Could not resolve .js path from .cmd wrapper, falling back to SDK resolution:', claudePath);
|
||||
}
|
||||
} else {
|
||||
queryOptions.pathToClaudeCodeExecutable = claudePath;
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user