From 50ecb0e46b42d037144d713f2ca122ecc07a2636 Mon Sep 17 00:00:00 2001 From: kaitranntt Date: Wed, 5 Nov 2025 17:38:29 -0500 Subject: [PATCH] fix: resolve DEP0190 warning with proper shell argument handling Use string concatenation (not args array) when shell is needed to avoid Node.js DEP0190 deprecation warning. Restores previous working approach with conditional shell usage based on file extension. Key changes: - Added escapeShellArg() helper for proper argument escaping - Conditional shell: only for .cmd/.bat/.ps1 files on Windows - When shell needed: concatenate args into single escaped string - When no shell: use array form (faster, no overhead) Benefits: - No deprecation warning - Proper security (escaped arguments) - Better performance (no shell on Unix or for .exe files) - Matches previous stable implementation Version: 2.4.9 --- CHANGELOG.md | 13 +++++++++++++ VERSION | 2 +- bin/ccs.js | 32 ++++++++++++++++++++++++++------ installers/install.ps1 | 2 +- installers/install.sh | 2 +- lib/ccs | 2 +- lib/ccs.ps1 | 2 +- package.json | 2 +- 8 files changed, 45 insertions(+), 12 deletions(-) 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",