From 57cd5a9aa68323d91b5ebe7003327df7bfd53eb7 Mon Sep 17 00:00:00 2001 From: DawidGrzejek Date: Tue, 16 Dec 2025 12:34:32 +0100 Subject: [PATCH] fix: add Windows support for Claude CLI detection and execution - Skip bash/zsh shell detection on Windows platform - Use PowerShell for base64 decoding on Windows - Set appropriate shell (powershell.exe vs bash) based on platform - Conditional PATH environment variable configuration - Bump version to 1.0.1 and rename package to claude-commit --- package-lock.json | 8 ++-- src/extension.ts | 116 ++++++++++++++++++++++++++-------------------- 2 files changed, 69 insertions(+), 55 deletions(-) diff --git a/package-lock.json b/package-lock.json index e280186..b500372 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { - "name": "claude-code-ai-commit-message-button", - "version": "1.0.0", + "name": "claude-commit", + "version": "1.0.1", "lockfileVersion": 3, "requires": true, "packages": { "": { - "name": "claude-code-ai-commit-message-button", - "version": "1.0.0", + "name": "claude-commit", + "version": "1.0.1", "license": "MIT", "devDependencies": { "@types/mocha": "^10.0.10", diff --git a/src/extension.ts b/src/extension.ts index 3bf6eab..06b1fe9 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -90,57 +90,61 @@ class ClaudeCLIExecutor { } } - // Try using bash shell - if (this.debugMode) { - outputChannel.appendLine('\n[BASH SHELL] Trying bash -l -c "which claude"...'); - } - try { - const bashCmd = '/bin/bash -l -c "which claude"'; - if (this.debugMode) { - outputChannel.appendLine(`[BASH SHELL] Command: ${bashCmd}`); - } - - const { stdout, stderr } = await execAsync(bashCmd); - if (this.debugMode) { - outputChannel.appendLine(`[BASH SHELL] stdout: ${stdout}`); - outputChannel.appendLine(`[BASH SHELL] stderr: ${stderr || 'none'}`); - } - - this.claudePath = stdout.trim(); + // Try using bash shell (skip on Windows) + if (process.platform !== 'win32') { if (this.debugMode) { - outputChannel.appendLine(`[BASH SHELL] ✓ Found at: ${this.claudePath}`); + outputChannel.appendLine('\n[BASH SHELL] Trying bash -l -c "which claude"...'); } - return this.claudePath; - } catch (error: any) { - if (this.debugMode) { - outputChannel.appendLine(`[BASH SHELL] Failed: ${error.message}`); + try { + const bashCmd = '/bin/bash -l -c "which claude"'; + if (this.debugMode) { + outputChannel.appendLine(`[BASH SHELL] Command: ${bashCmd}`); + } + + const { stdout, stderr } = await execAsync(bashCmd); + if (this.debugMode) { + outputChannel.appendLine(`[BASH SHELL] stdout: ${stdout}`); + outputChannel.appendLine(`[BASH SHELL] stderr: ${stderr || 'none'}`); + } + + this.claudePath = stdout.trim(); + if (this.debugMode) { + outputChannel.appendLine(`[BASH SHELL] ✓ Found at: ${this.claudePath}`); + } + return this.claudePath; + } catch (error: any) { + if (this.debugMode) { + outputChannel.appendLine(`[BASH SHELL] Failed: ${error.message}`); + } } } - // Try zsh shell - if (this.debugMode) { - outputChannel.appendLine('\n[ZSH SHELL] Trying zsh -l -c "which claude"...'); - } - try { - const zshCmd = '/bin/zsh -l -c "which claude"'; + // Try zsh shell (skip on Windows) + if (process.platform !== 'win32') { if (this.debugMode) { - outputChannel.appendLine(`[ZSH SHELL] Command: ${zshCmd}`); + outputChannel.appendLine('\n[ZSH SHELL] Trying zsh -l -c "which claude"...'); } - - const { stdout, stderr } = await execAsync(zshCmd); - if (this.debugMode) { - outputChannel.appendLine(`[ZSH SHELL] stdout: ${stdout}`); - outputChannel.appendLine(`[ZSH SHELL] stderr: ${stderr || 'none'}`); - } - - this.claudePath = stdout.trim(); - if (this.debugMode) { - outputChannel.appendLine(`[ZSH SHELL] ✓ Found at: ${this.claudePath}`); - } - return this.claudePath; - } catch (error: any) { - if (this.debugMode) { - outputChannel.appendLine(`[ZSH SHELL] Failed: ${error.message}`); + try { + const zshCmd = '/bin/zsh -l -c "which claude"'; + if (this.debugMode) { + outputChannel.appendLine(`[ZSH SHELL] Command: ${zshCmd}`); + } + + const { stdout, stderr } = await execAsync(zshCmd); + if (this.debugMode) { + outputChannel.appendLine(`[ZSH SHELL] stdout: ${stdout}`); + outputChannel.appendLine(`[ZSH SHELL] stderr: ${stderr || 'none'}`); + } + + this.claudePath = stdout.trim(); + if (this.debugMode) { + outputChannel.appendLine(`[ZSH SHELL] ✓ Found at: ${this.claudePath}`); + } + return this.claudePath; + } catch (error: any) { + if (this.debugMode) { + outputChannel.appendLine(`[ZSH SHELL] Failed: ${error.message}`); + } } } @@ -279,12 +283,22 @@ class ClaudeCLIExecutor { outputChannel.appendLine(`[EXECUTE] Using path: ${this.claudePath}`); } + // Detect platform + const isWindows = process.platform === 'win32'; + // Use base64 encoding to completely avoid shell escaping issues const base64Prompt = Buffer.from(prompt, 'utf8').toString('base64'); - + // Build command that decodes base64 and pipes to claude - let command = `echo "${base64Prompt}" | base64 -d | ${this.claudePath}`; - + let command; + if (isWindows) { + // PowerShell command for Windows + command = `[System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String('${base64Prompt}')) | ${this.claudePath}`; + } else { + // Bash command for Linux/macOS + command = `echo "${base64Prompt}" | base64 -d | ${this.claudePath}`; + } + // Add all flags command += ' --print'; // Use explicit --print flag command += ' --model sonnet'; // Hardcoded model @@ -304,11 +318,11 @@ class ClaudeCLIExecutor { const execOptions = { timeout: 60000, // 60 seconds timeout - shell: '/bin/bash', + shell: isWindows ? 'powershell.exe' : '/bin/bash', maxBuffer: 1024 * 1024 * 10, // 10MB buffer for large outputs - env: { - ...process.env, - PATH: `/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:${process.env.PATH}:${process.env.HOME}/.nvm/versions/node/*/bin` + env: { + ...process.env, + PATH: isWindows ? process.env.PATH : `/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:${process.env.PATH}:${process.env.HOME}/.nvm/versions/node/*/bin` } };