fix: terminal termination & simplified detection (v2.4.1)

Critical Fixes:
- Fixed PowerShell terminal closing when using `irm | iex` installation
  * Changed `exit 1` to `return` in install.ps1 (line 229)
  * Terminal now stays open on errors, showing full error messages
  * Affects: Windows PowerShell 5.1+, PowerShell 7+

- Fixed installation download path
  * Changed `/ccs.ps1` to `/lib/ccs.ps1` in install.ps1 (line 223)
  * Resolves standalone installation failures from GitHub

- Simplified Claude CLI detection logic across all platforms
  * Removed complex validation that failed with npm-installed Claude
  * Now trusts system PATH (standard case for users)
  * Falls back to CCS_CLAUDE_PATH for custom installations
  * Fixes: `where.exe claude` shows installed but CCS reports "not found"

Improvements:
- Simplified error messages (removed lengthy search location details)
- Reduced codebase by 332 lines (454 deleted, 122 added)
- npm package size reduced: 17.2 KB → 15.9 KB (7.6% smaller)

Cross-Platform Parity:
- bash (lib/ccs): Simplified detection, removed validate_claude_cli
- PowerShell (lib/ccs.ps1): Simplified detection, removed Test-ClaudeCli
- Node.js (bin/*.js): Simplified detection, removed validateClaudeCli
- All versions now use identical trust-the-PATH approach

Files Modified:
- installers/install.ps1: exit→return, download path fix
- lib/ccs.ps1: simplified detection (165 lines removed)
- lib/ccs: simplified detection (172 lines removed)
- bin/claude-detector.js: simplified detection (86 lines removed)
- bin/ccs.js: removed validation calls (31 lines removed)
- .github/workflows/publish-npm.yml: fixed package name
- CHANGELOG.md: comprehensive v2.4.1 release notes
- VERSION, package.json: bumped to 2.4.1

Testing: bash validated, npm syntax checked, manual Windows testing recommended
This commit is contained in:
kaitranntt
2025-11-04 21:54:05 -05:00
parent f066faca43
commit 80a5200cae
11 changed files with 126 additions and 458 deletions
+27 -145
View File
@@ -2,7 +2,7 @@
set -euo pipefail
# Version (updated by scripts/bump-version.sh)
CCS_VERSION="2.4.0"
CCS_VERSION="2.4.1"
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
# --- Color/Format Functions ---
@@ -32,147 +32,44 @@ setup_colors
# --- Claude CLI Detection Logic ---
detect_claude_cli() {
local claude_path=""
# Priority 1: CCS_CLAUDE_PATH environment variable
# Priority 1: CCS_CLAUDE_PATH environment variable (if user wants custom path)
if [[ -n "${CCS_CLAUDE_PATH:-}" ]]; then
if [[ -f "$CCS_CLAUDE_PATH" ]] && [[ -x "$CCS_CLAUDE_PATH" ]]; then
# Basic validation: file exists
if [[ -f "$CCS_CLAUDE_PATH" ]]; then
echo "$CCS_CLAUDE_PATH"
return 0
fi
# Invalid CCS_CLAUDE_PATH - continue to fallbacks
# Warning will be shown later in validation phase
# Invalid CCS_CLAUDE_PATH - show warning and fall back to PATH
echo "[!] Warning: CCS_CLAUDE_PATH is set but file not found: $CCS_CLAUDE_PATH" >&2
echo " Falling back to system PATH lookup..." >&2
fi
# Priority 2: Check if claude in PATH
claude_path=$(command -v claude 2>/dev/null || true)
if [[ -n "$claude_path" ]]; then
echo "$claude_path"
return 0
fi
# Priority 3: Check common installation locations
local common_locations=()
# Platform-specific common locations
if [[ "$OSTYPE" == darwin* ]]; then
# macOS
common_locations=(
"/usr/local/bin/claude"
"$HOME/.local/bin/claude"
"/opt/homebrew/bin/claude"
)
else
# Linux
common_locations=(
"/usr/local/bin/claude"
"$HOME/.local/bin/claude"
"/usr/bin/claude"
)
fi
# Check each common location
for location in "${common_locations[@]}"; do
if [[ -f "$location" ]] && [[ -x "$location" ]]; then
echo "$location"
return 0
fi
done
# Not found
echo ""
return 1
}
# Global variable for validation error message
VALIDATION_ERROR=""
validate_claude_cli() {
local path="$1"
VALIDATION_ERROR=""
# Check 1: Empty path
if [[ -z "$path" ]]; then
VALIDATION_ERROR="No path provided"
return 1
fi
# Check 2: File exists
if [[ ! -e "$path" ]]; then
VALIDATION_ERROR="File not found: $path"
return 1
fi
# Check 3: Is regular file (not directory)
if [[ -d "$path" ]]; then
VALIDATION_ERROR="Path is a directory: $path"
return 1
fi
# Check 4: Is executable
if [[ ! -x "$path" ]]; then
VALIDATION_ERROR="File is not executable: $path
Try: chmod +x $path"
return 1
fi
# Check 5: Path safety (prevent injection)
# Allow: alphanumeric, /, \, :, space, -, _, ., ~
if [[ "$path" =~ [^\;a-zA-Z0-9/\\:\ \._~-] ]]; then
VALIDATION_ERROR="Path contains unsafe characters: $path
Allowed: alphanumeric, path separators, spaces, hyphens, underscores, dots"
return 1
fi
# All checks passed
# Priority 2: Use 'claude' from PATH (trust the system)
# This is the standard case - if user installed Claude CLI, it's in their PATH
echo "claude"
return 0
}
show_claude_not_found_error() {
local env_var_status="${CCS_CLAUDE_PATH:-(not set)}"
msg_error "Claude CLI not found in PATH
msg_error "Claude CLI not found
Searched:
- CCS_CLAUDE_PATH: $env_var_status
- System PATH: not found
- Common locations: not found
CCS requires Claude CLI to be installed and available in your PATH.
Solutions:
1. Add Claude CLI to PATH:
# Find where Claude is installed
sudo find / -name claude 2>/dev/null
# Then add to PATH (replace /path/to with actual path)
export PATH=\"/path/to/claude/bin:\$PATH\"
echo 'export PATH=\"/path/to/claude/bin:\$PATH\"' >> ~/.bashrc
source ~/.bashrc
2. Or set custom path:
export CCS_CLAUDE_PATH=\"/full/path/to/claude\"
echo 'export CCS_CLAUDE_PATH=\"/full/path/to/claude\"' >> ~/.bashrc
source ~/.bashrc
Example (D drive on Windows/WSL):
export CCS_CLAUDE_PATH=\"/mnt/d/Tools/Claude/claude.exe\"
3. Or install Claude CLI:
1. Install Claude CLI:
https://docs.claude.com/en/docs/claude-code/installation
Verify installation:
ccs --version
2. Verify installation:
command -v claude
Debugging:
# Check if claude command exists
command -v claude
3. If installed but not in PATH, add it:
# Find Claude installation
which claude
# Check CCS_CLAUDE_PATH
echo \$CCS_CLAUDE_PATH"
# Or set custom path
export CCS_CLAUDE_PATH='/path/to/claude'
Restart your terminal after installation."
}
CONFIG_FILE="${CCS_CONFIG:-$HOME/.ccs/config.json}"
@@ -387,20 +284,12 @@ fi
# Special case: help command (check BEFORE profile detection)
if [[ $# -gt 0 ]] && [[ "${1}" == "--help" || "${1}" == "-h" || "${1}" == "help" ]]; then
shift # Remove the help argument
# Detect and validate Claude CLI for help command
CLAUDE_CLI=$(detect_claude_cli)
if [[ -z "$CLAUDE_CLI" ]]; then
if ! exec "$CLAUDE_CLI" --help "$@"; then
show_claude_not_found_error
exit 1
fi
if ! validate_claude_cli "$CLAUDE_CLI"; then
msg_error "$VALIDATION_ERROR"
exit 1
fi
exec "$CLAUDE_CLI" --help "$@"
fi
# Special case: install command (check BEFORE profile detection)
@@ -517,16 +406,9 @@ fi
# Detect Claude CLI executable
CLAUDE_CLI=$(detect_claude_cli)
if [[ -z "$CLAUDE_CLI" ]]; then
# Execute Claude with the profile settings
# If claude is not found, exec will fail and show an error
if ! exec "$CLAUDE_CLI" --settings "$SETTINGS_PATH" "$@"; then
show_claude_not_found_error
exit 1
fi
# Validate detected path
if ! validate_claude_cli "$CLAUDE_CLI"; then
msg_error "$VALIDATION_ERROR"
exit 1
fi
# Execute with validated path
exec "$CLAUDE_CLI" --settings "$SETTINGS_PATH" "$@"
+25 -140
View File
@@ -30,136 +30,49 @@ function Find-ClaudeCli {
[OutputType([string])]
param()
# Priority 1: CCS_CLAUDE_PATH environment variable
# Priority 1: CCS_CLAUDE_PATH environment variable (if user wants custom path)
$CcsClaudePath = $env:CCS_CLAUDE_PATH
if ($CcsClaudePath) {
if ((Test-Path $CcsClaudePath -PathType Leaf) -and
(Get-Command $CcsClaudePath -ErrorAction SilentlyContinue)) {
# Basic validation: file exists
if (Test-Path $CcsClaudePath -PathType Leaf) {
return $CcsClaudePath
}
# Invalid CCS_CLAUDE_PATH - continue to fallbacks
# Warning will be shown later in validation phase
# Invalid CCS_CLAUDE_PATH - show warning and fall back to PATH
Write-Host "[!] Warning: CCS_CLAUDE_PATH is set but file not found: $CcsClaudePath" -ForegroundColor Yellow
Write-Host " Falling back to system PATH lookup..." -ForegroundColor Yellow
}
# Priority 2: Check if claude in PATH
$ClaudeInPath = Get-Command claude -ErrorAction SilentlyContinue
if ($ClaudeInPath) {
return $ClaudeInPath.Source
}
# Priority 3: Check common installation locations
$CommonLocations = @(
"$env:LOCALAPPDATA\Claude\claude.exe",
"$env:PROGRAMFILES\Claude\claude.exe",
"C:\Program Files\Claude\claude.exe",
"D:\Program Files\Claude\claude.exe",
"$env:USERPROFILE\.local\bin\claude.exe"
)
foreach ($Location in $CommonLocations) {
$ExpandedPath = [System.Environment]::ExpandEnvironmentVariables($Location)
if ((Test-Path $ExpandedPath -PathType Leaf) -and
(Get-Command $ExpandedPath -ErrorAction SilentlyContinue)) {
return $ExpandedPath
}
}
# Not found
return ""
}
function Test-ClaudeCli {
[OutputType([bool])]
param(
[Parameter(Mandatory=$true)]
[AllowEmptyString()]
[string]$Path
)
# Check 1: Empty path
if ([string]::IsNullOrWhiteSpace($Path)) {
throw "No path provided"
}
# Check 2: File exists
if (-not (Test-Path $Path)) {
throw "File not found: $Path"
}
# Check 3: Is regular file (not directory)
if (Test-Path $Path -PathType Container) {
throw "Path is a directory: $Path"
}
# Check 4: Is executable (Get-Command can load it)
try {
$null = Get-Command $Path -ErrorAction Stop
} catch {
throw "File is not executable: $Path`n`nCheck file permissions and file type"
}
# Check 5: Path safety (prevent injection)
# Allow: alphanumeric, \, /, :, space, -, _, ., ~
if ($Path -match '[;\|&<>``\$\*\?\[\]''\"()]') {
throw "Path contains unsafe characters: $Path`n`nAllowed: alphanumeric, path separators, spaces, hyphens, underscores, dots"
}
# All checks passed
return $true
# Priority 2: Use 'claude' from PATH (trust the system)
# This is the standard case - if user installed Claude CLI, it's in their PATH
return "claude"
}
function Show-ClaudeNotFoundError {
$EnvVarStatus = if ($env:CCS_CLAUDE_PATH) { $env:CCS_CLAUDE_PATH } else { "(not set)" }
Write-ErrorMsg @"
Claude CLI not found
Claude CLI not found in PATH
Searched:
- CCS_CLAUDE_PATH: $EnvVarStatus
- System PATH: not found
- Common locations: not found
CCS requires Claude CLI to be installed and available in your PATH.
Solutions:
1. Add Claude CLI to PATH:
# Find where Claude is installed
Get-ChildItem -Path C:\,D:\ -Filter claude.exe -Recurse -ErrorAction SilentlyContinue | Select-Object FullName
# Then add to PATH (replace with actual path)
`$env:Path += ';D:\path\to\claude\directory'
[Environment]::SetEnvironmentVariable('Path', `$env:Path, 'User')
# Restart terminal for changes to take effect
2. Or set custom path:
`$env:CCS_CLAUDE_PATH = 'D:\full\path\to\claude.exe'
[Environment]::SetEnvironmentVariable('CCS_CLAUDE_PATH', 'D:\full\path\to\claude.exe', 'User')
Example (D drive installation):
`$env:CCS_CLAUDE_PATH = 'D:\Tools\Claude\claude.exe'
[Environment]::SetEnvironmentVariable('CCS_CLAUDE_PATH', 'D:\Tools\Claude\claude.exe', 'User')
# Restart terminal for changes to take effect
3. Or install Claude CLI:
1. Install Claude CLI:
https://docs.claude.com/en/docs/claude-code/installation
Verify installation:
ccs --version
2. Verify installation:
Get-Command claude
Debugging:
# Check if claude command exists
Get-Command claude -ErrorAction SilentlyContinue
3. If installed but not in PATH, add it:
# Find Claude installation
where.exe claude
# Check CCS_CLAUDE_PATH
`$env:CCS_CLAUDE_PATH
# Or set custom path
`$env:CCS_CLAUDE_PATH = 'C:\path\to\claude.exe'
Restart your terminal after installation.
"@
}
# Version (updated by scripts/bump-version.sh)
$CcsVersion = "2.4.0"
$CcsVersion = "2.4.1"
$ScriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path
# Installation function for commands and skills
@@ -382,21 +295,8 @@ if ($FirstArg -eq "version" -or $FirstArg -eq "--version" -or $FirstArg -eq "-v"
# Special case: help command (check BEFORE profile detection)
if ($FirstArg -eq "--help" -or $FirstArg -eq "-h" -or $FirstArg -eq "help") {
# Detect and validate Claude CLI for help command
$ClaudeCli = Find-ClaudeCli
if ([string]::IsNullOrEmpty($ClaudeCli)) {
Show-ClaudeNotFoundError
exit 1
}
try {
$null = Test-ClaudeCli -Path $ClaudeCli
} catch {
Write-ErrorMsg $_.Exception.Message
exit 1
}
try {
if ($RemainingArgs) {
& $ClaudeCli --help @RemainingArgs
@@ -405,8 +305,7 @@ if ($FirstArg -eq "--help" -or $FirstArg -eq "-h" -or $FirstArg -eq "help") {
}
exit $LASTEXITCODE
} catch {
Write-Host "Error: Failed to execute claude --help" -ForegroundColor Red
Write-Host $_.Exception.Message
Show-ClaudeNotFoundError
exit 1
}
}
@@ -580,20 +479,7 @@ Solutions:
# Detect Claude CLI executable
$ClaudeCli = Find-ClaudeCli
if ([string]::IsNullOrEmpty($ClaudeCli)) {
Show-ClaudeNotFoundError
exit 1
}
# Validate detected path
try {
$null = Test-ClaudeCli -Path $ClaudeCli
} catch {
Write-ErrorMsg $_.Exception.Message
exit 1
}
# Execute with validated path
# Execute Claude with the profile settings
try {
if ($RemainingArgs) {
& $ClaudeCli --settings $SettingsPath @RemainingArgs
@@ -602,7 +488,6 @@ try {
}
exit $LASTEXITCODE
} catch {
Write-Host "Error: Failed to execute claude" -ForegroundColor Red
Write-Host $_.Exception.Message
Show-ClaudeNotFoundError
exit 1
}