Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 29 additions & 13 deletions WINDOWS.md
Original file line number Diff line number Diff line change
Expand Up @@ -79,34 +79,50 @@ Codebuff checks GitHub for the latest release on first run. This fails when:

---

### Shell Detection & PowerShell Support

Codebuff now automatically detects your shell (PowerShell, cmd.exe, bash, etc.) and adapts its behavior accordingly.

**PowerShell users benefit from:**
- Many Unix-like commands work natively (`mkdir`, `rm`, `cp`, `mv`, `ls`, `cat`)
- Better compatibility with cross-platform commands
- Codebuff generates shell-appropriate commands based on detection

**To check your detected shell:**
Look at the "Shell:" line in the system info at the start of each conversation.

**Recommendation:** Use PowerShell instead of cmd.exe for the best Windows experience.

---

### Issue: Git Commands Fail on Windows

**Symptom**:
Git operations (commit, rebase, complex commands) fail with syntax errors or unexpected behavior.

**Cause**:
Codebuff uses Windows `cmd.exe` for command execution, which:
- Does not support bash syntax (HEREDOC, process substitution)
- Has limited quote escaping compared to bash
- Cannot execute complex git commands that work in Git Bash
**Cause** (now largely fixed):
Older versions of Codebuff used HEREDOC syntax for git commits, which doesn't work on Windows. This has been fixed - Codebuff now uses cross-platform compatible syntax.

**Solutions**:
**If you still experience issues:**

1. **Ensure you have the latest Codebuff version**:
```powershell
npm update -g codebuff
```

1. **Install Git for Windows** (if not already installed):
2. **Install Git for Windows** (if not already installed):
- Download from https://git-scm.com/download/win
- Ensures git commands are available in PATH

2. **Use Git Bash terminal** instead of PowerShell:
- Git Bash provides better compatibility with bash-style commands
- Launch Git Bash and run `codebuff` from there
3. **Use PowerShell** instead of cmd.exe:
- PowerShell has better command compatibility
- Codebuff detects PowerShell and adjusts accordingly

3. **Or use WSL (Windows Subsystem for Linux)**:
4. **Or use WSL (Windows Subsystem for Linux)**:
- Provides full Linux environment with native bash
- Install: `wsl --install` in PowerShell (Admin)
- Run codebuff inside WSL for best compatibility

**Note**: Even when running in Git Bash, Codebuff spawns commands using `cmd.exe`. Using WSL provides the most reliable experience for git operations.

**Reference**: Issue [#274](https://github.com/CodebuffAI/codebuff/issues/274)

---
Expand Down
135 changes: 26 additions & 109 deletions cli/src/utils/detect-shell.ts
Original file line number Diff line number Diff line change
@@ -1,115 +1,32 @@
import { execSync } from 'child_process'
/**
* CLI-specific shell detection wrapper.
* Re-exports from common/src/util/detect-shell.ts with CLI environment integration.
*/
import {
detectShell as detectShellFromCommon,
clearShellCache,
getShellArgs,
SHELL_COMMAND_ARGS,
} from '@codebuff/common/util/detect-shell'

import type { CliEnv } from '../types/env'
import { getCliEnv } from './env'

type KnownShell =
| 'bash'
| 'zsh'
| 'fish'
| 'cmd.exe'
| 'powershell'
| 'unknown'

type ShellName = KnownShell | string

let cachedShell: ShellName | null = null

const SHELL_ALIASES: Record<string, KnownShell> = {
bash: 'bash',
zsh: 'zsh',
fish: 'fish',
cmd: 'cmd.exe',
'cmd.exe': 'cmd.exe',
pwsh: 'powershell',
powershell: 'powershell',
'powershell.exe': 'powershell',
}

import type {
KnownShell,
ShellName,
ShellDetectionEnv,
} from '@codebuff/common/util/detect-shell'

// Re-export types and utilities from common
export type { KnownShell, ShellName, ShellDetectionEnv }
export { clearShellCache, getShellArgs, SHELL_COMMAND_ARGS }

/**
* Detects the user's shell using CLI environment variables.
* This is a convenience wrapper around the common detectShell function
* that automatically uses the CLI environment.
*/
export function detectShell(env: CliEnv = getCliEnv()): ShellName {
if (cachedShell) {
return cachedShell
}

const detected =
detectFromEnvironment(env) ?? detectViaParentProcessInspection() ?? 'unknown'
cachedShell = detected
return detected
}

function detectFromEnvironment(env: CliEnv): ShellName | null {
const candidates: Array<string | undefined> = []

if (process.platform === 'win32') {
candidates.push(env.COMSPEC, env.SHELL)
} else {
candidates.push(env.SHELL)
}

for (const candidate of candidates) {
const normalized = normalizeCandidate(candidate)
if (normalized) {
return normalized
}
}

return null
}

function detectViaParentProcessInspection(): ShellName | null {
try {
if (process.platform === 'win32') {
const parentProcess = execSync(
'wmic process get ParentProcessId,CommandLine',
{ stdio: 'pipe' },
)
.toString()
.toLowerCase()

if (parentProcess.includes('powershell')) return 'powershell'
if (parentProcess.includes('cmd.exe')) return 'cmd.exe'
} else {
const parentProcess = execSync(`ps -p ${process.ppid} -o comm=`, {
stdio: 'pipe',
})
.toString()
.trim()
const normalized = normalizeCandidate(parentProcess)
if (normalized) return normalized
}
} catch {
// Ignore inspection errors
}

return null
}

function normalizeCandidate(value?: string | null): ShellName | null {
if (!value) {
return null
}

const trimmed = value.trim()
if (!trimmed) {
return null
}

const lower = trimmed.toLowerCase()
const parts = lower.split(/[/\\]/)
const last = parts.pop() ?? lower
const base = last.endsWith('.exe') ? last.slice(0, -4) : last

if (SHELL_ALIASES[base]) {
return SHELL_ALIASES[base]
}

if (SHELL_ALIASES[last]) {
return SHELL_ALIASES[last]
}

if (base.endsWith('sh')) {
return base
}

return null
return detectShellFromCommon(env)
}
23 changes: 9 additions & 14 deletions common/src/tools/params/tool/run-terminal-command.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,28 +62,23 @@ When the user requests a new git commit, please follow these steps closely:
Generated with Codebuff 🤖
Co-Authored-By: Codebuff <noreply@codebuff.com>
\`\`\`
To maintain proper formatting, use cross-platform compatible commit messages:

**For Unix/bash shells:**
\`\`\`
git commit -m "$(cat <<'EOF'
Your commit message here.

🤖 Generated with Codebuff
Co-Authored-By: Codebuff <noreply@codebuff.com>
EOF
)"
\`\`\`

**For Windows Command Prompt:**
**For bash/PowerShell:** Use multi-line \`-m\` format:
\`\`\`
git commit -m "Your commit message here.

🤖 Generated with Codebuff
Co-Authored-By: Codebuff <noreply@codebuff.com>"
\`\`\`

Always detect the platform and use the appropriate syntax. HEREDOC syntax (\`<<'EOF'\`) only works in bash/Unix shells and will fail on Windows Command Prompt.
**For cmd.exe (Windows Command Prompt):** Use the file-based approach to avoid escaping issues:
1. Use \`write_file\` to create \`.codebuff-commit-msg.txt\` with the full commit message
2. Run \`git commit -F .codebuff-commit-msg.txt\`
3. Run \`del .codebuff-commit-msg.txt\` to clean up

This file-based approach completely avoids cmd.exe's complex escaping rules for quotes, newlines, and special characters.

**Important:** Do NOT use HEREDOC syntax (\`<<'EOF'\`) - it only works in bash and will fail on Windows.

**Important details**

Expand Down
Loading