diff --git a/CHANGELOG.md b/CHANGELOG.md index ed2608e7..c8719745 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,19 @@ All notable changes to CCS will be documented here. Format based on [Keep a Changelog](https://keepachangelog.com/). +## [2.4.9] - 2025-11-05 + +### Fixed +- **Deprecation Warning**: Fixed Node.js DEP0190 warning by using string concatenation when shell is needed (instead of args array with shell: true) +- Conditional shell usage: only for .cmd/.bat/.ps1 files on Windows +- Proper argument escaping for security + +### Technical Details +- **Files Modified**: `bin/ccs.js` (execClaude function, escapeShellArg helper) +- **Change**: When shell needed, pass single string instead of args array to avoid deprecation +- **Security**: Arguments properly escaped with double quotes +- **Performance**: No shell overhead on Unix or for .exe files on Windows + ## [2.4.8] - 2025-11-05 ### Fixed diff --git a/VERSION b/VERSION index f041bc6d..3f5987a5 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -2.4.8 +2.4.9 diff --git a/bin/ccs.js b/bin/ccs.js index 19238b5e..156cd6f8 100755 --- a/bin/ccs.js +++ b/bin/ccs.js @@ -11,14 +11,34 @@ const { getSettingsPath, getConfigPath } = require('./config-manager'); // Version (sync with package.json) const CCS_VERSION = require('../package.json').version; +// Helper: Escape arguments for shell execution +function escapeShellArg(arg) { + // Windows: escape double quotes and wrap in double quotes + return '"' + String(arg).replace(/"/g, '""') + '"'; +} + // Execute Claude CLI with unified spawn logic function execClaude(claudeCli, args) { - // Use shell only on Windows for .cmd/.bat compatibility - const child = spawn(claudeCli, args, { - stdio: 'inherit', - windowsHide: true, - shell: process.platform === 'win32' - }); + const isWindows = process.platform === 'win32'; + const needsShell = isWindows && /\.(cmd|bat|ps1)$/i.test(claudeCli); + + let child; + if (needsShell) { + // When shell needed: concatenate into string to avoid DEP0190 warning + const cmdString = [claudeCli, ...args].map(escapeShellArg).join(' '); + child = spawn(cmdString, { + stdio: 'inherit', + windowsHide: true, + shell: true + }); + } else { + // When no shell needed: use array form (faster, no shell overhead) + child = spawn(claudeCli, args, { + stdio: 'inherit', + windowsHide: true + }); + } + child.on('exit', (code, signal) => { if (signal) process.kill(process.pid, signal); else process.exit(code || 0); diff --git a/installers/install.ps1 b/installers/install.ps1 index 52d21a19..916f70a4 100644 --- a/installers/install.ps1 +++ b/installers/install.ps1 @@ -30,7 +30,7 @@ $InstallMethod = if ($ScriptDir -and ((Test-Path "$ScriptDir\lib\ccs.ps1") -or ( # IMPORTANT: Update this version when releasing new versions! # This hardcoded version is used for standalone installations (irm | iex) # For git installations, VERSION file is read if available -$CcsVersion = "2.4.8" +$CcsVersion = "2.4.9" # Try to read VERSION file for git installations if ($ScriptDir) { diff --git a/installers/install.sh b/installers/install.sh index 1249b63a..b94a0b9e 100755 --- a/installers/install.sh +++ b/installers/install.sh @@ -31,7 +31,7 @@ fi # IMPORTANT: Update this version when releasing new versions! # This hardcoded version is used for standalone installations (curl | bash) # For git installations, VERSION file is read if available -CCS_VERSION="2.4.8" +CCS_VERSION="2.4.9" # Try to read VERSION file for git installations if [[ -f "$SCRIPT_DIR/VERSION" ]]; then diff --git a/lib/ccs b/lib/ccs index 265b73db..a114acb6 100755 --- a/lib/ccs +++ b/lib/ccs @@ -2,7 +2,7 @@ set -euo pipefail # Version (updated by scripts/bump-version.sh) -CCS_VERSION="2.4.8" +CCS_VERSION="2.4.9" SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" readonly CONFIG_FILE="${CCS_CONFIG:-$HOME/.ccs/config.json}" diff --git a/lib/ccs.ps1 b/lib/ccs.ps1 index 0a222a82..4d09117b 100644 --- a/lib/ccs.ps1 +++ b/lib/ccs.ps1 @@ -134,7 +134,7 @@ function Show-Help { } # Version (updated by scripts/bump-version.sh) -$CcsVersion = "2.4.8" +$CcsVersion = "2.4.9" $ScriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path $ConfigFile = if ($env:CCS_CONFIG) { $env:CCS_CONFIG } else { "$env:USERPROFILE\.ccs\config.json" } diff --git a/package.json b/package.json index 38cd42ca..12ea6a69 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@kaitranntt/ccs", - "version": "2.4.8", + "version": "2.4.9", "description": "Claude Code Switch - Instant profile switching between Claude Sonnet 4.5 and GLM 4.6", "keywords": [ "cli",