From 3c534f48cb60448875c02bc0a8444277ca7c89eb Mon Sep 17 00:00:00 2001 From: ruan-cat <1219043956@qq.com> Date: Wed, 28 Jan 2026 02:45:22 +0800 Subject: [PATCH] fix(websearch): add shell option for Windows spawnSync compatibility On Windows, globally installed CLI tools via npm/pnpm are .cmd/.bat batch files, not real .exe executables. Node.js spawnSync() without the shell option cannot execute these files and returns ENOENT error. Changes: - Extract isWindows as a global constant at file top - Add shell: isWindows to all CLI execution spawnSync calls - Remove duplicate isWindows declaration in isCliAvailable() Fixes #378 Co-authored-by: Cursor --- lib/hooks/websearch-transformer.cjs | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/lib/hooks/websearch-transformer.cjs b/lib/hooks/websearch-transformer.cjs index 7a2af2a6..2df55450 100644 --- a/lib/hooks/websearch-transformer.cjs +++ b/lib/hooks/websearch-transformer.cjs @@ -26,6 +26,18 @@ const { spawnSync } = require('child_process'); +// ============================================================================ +// PLATFORM DETECTION +// ============================================================================ + +/** + * Windows platform flag - used for shell option in spawnSync calls. + * On Windows, globally installed CLI tools via npm/pnpm are .cmd/.bat files, + * which require shell: true to execute properly. + * @see https://github.com/kaitranntt/ccs/issues/378 + */ +const isWindows = process.platform === 'win32'; + // ============================================================================ // CONFIGURATION - Edit these for prompt engineering // ============================================================================ @@ -154,7 +166,6 @@ process.stdin.on('error', () => { */ function isCliAvailable(cmd) { try { - const isWindows = process.platform === 'win32'; const whichCmd = isWindows ? 'where.exe' : 'which'; const result = spawnSync(whichCmd, [cmd], { @@ -292,6 +303,7 @@ function tryGeminiSearch(query, timeoutSec = DEFAULT_TIMEOUT_SEC) { timeout: timeoutMs, maxBuffer: 1024 * 1024 * 2, stdio: ['pipe', 'pipe', 'pipe'], + shell: isWindows, } ); @@ -358,6 +370,7 @@ function tryOpenCodeSearch(query, timeoutSec = DEFAULT_TIMEOUT_SEC) { timeout: timeoutMs, maxBuffer: 1024 * 1024 * 2, stdio: ['pipe', 'pipe', 'pipe'], + shell: isWindows, } ); @@ -417,6 +430,7 @@ function tryGrokSearch(query, timeoutSec = DEFAULT_TIMEOUT_SEC) { timeout: timeoutMs, maxBuffer: 1024 * 1024 * 2, stdio: ['pipe', 'pipe', 'pipe'], + shell: isWindows, }); if (spawnResult.error) {