"use strict";Object.defineProperty(exports, "__esModule", { value: true });exports.getShellConfig = getShellConfig;exports.getShellEnv = getShellEnv;exports.killProcessTree = killProcessTree;exports.sanitizeBinaryOutput = sanitizeBinaryOutput;var _nodeFs = require("node:fs"); var _nodePath = require("node:path"); var _child_process = require("child_process"); var _config = require("../config.js"); var _settingsManager = require("../core/settings-manager.js"); let cachedShellConfig = null; /** * Find bash executable on PATH (cross-platform) */ function findBashOnPath() { if (process.platform === "win32") { // Windows: Use 'where' and verify file exists (where can return non-existent paths) try { const result = (0, _child_process.spawnSync)("where", ["bash.exe"], { encoding: "utf-8", timeout: 5000 }); if (result.status === 0 && result.stdout) { const firstMatch = result.stdout.trim().split(/\r?\n/)[0]; if (firstMatch && (0, _nodeFs.existsSync)(firstMatch)) { return firstMatch; } } } catch { // Ignore errors }return null; } // Unix: Use 'which' and trust its output (handles Termux and special filesystems) try { const result = (0, _child_process.spawnSync)("which", ["bash"], { encoding: "utf-8", timeout: 5000 }); if (result.status === 0 && result.stdout) { const firstMatch = result.stdout.trim().split(/\r?\n/)[0]; if (firstMatch) { return firstMatch; } } } catch { // Ignore errors }return null; } /** * Get shell configuration based on platform. * Resolution order: * 1. User-specified shellPath in settings.json * 2. On Windows: Git Bash in known locations, then bash on PATH * 3. On Unix: /bin/bash, then bash on PATH, then fallback to sh */ function getShellConfig() { if (cachedShellConfig) { return cachedShellConfig; } const settings = _settingsManager.SettingsManager.create(); const customShellPath = settings.getShellPath(); // 1. Check user-specified shell path if (customShellPath) { if ((0, _nodeFs.existsSync)(customShellPath)) { cachedShellConfig = { shell: customShellPath, args: ["-c"] }; return cachedShellConfig; } throw new Error(`Custom shell path not found: ${customShellPath}\nPlease update shellPath in ${(0, _config.getSettingsPath)()}`); } if (process.platform === "win32") { // 2. Try Git Bash in known locations const paths = []; const programFiles = process.env.ProgramFiles; if (programFiles) { paths.push(`${programFiles}\\Git\\bin\\bash.exe`); } const programFilesX86 = process.env["ProgramFiles(x86)"]; if (programFilesX86) { paths.push(`${programFilesX86}\\Git\\bin\\bash.exe`); } for (const path of paths) { if ((0, _nodeFs.existsSync)(path)) { cachedShellConfig = { shell: path, args: ["-c"] }; return cachedShellConfig; } } // 3. Fallback: search bash.exe on PATH (Cygwin, MSYS2, WSL, etc.) const bashOnPath = findBashOnPath(); if (bashOnPath) { cachedShellConfig = { shell: bashOnPath, args: ["-c"] }; return cachedShellConfig; } throw new Error(`No bash shell found. Options:\n` + ` 1. Install Git for Windows: https://git-scm.com/download/win\n` + ` 2. Add your bash to PATH (Cygwin, MSYS2, etc.)\n` + ` 3. Set shellPath in ${(0, _config.getSettingsPath)()}\n\n` + `Searched Git Bash in:\n${paths.map((p) => ` ${p}`).join("\n")}`); } // Unix: try /bin/bash, then bash on PATH, then fallback to sh if ((0, _nodeFs.existsSync)("/bin/bash")) { cachedShellConfig = { shell: "/bin/bash", args: ["-c"] }; return cachedShellConfig; } const bashOnPath = findBashOnPath(); if (bashOnPath) { cachedShellConfig = { shell: bashOnPath, args: ["-c"] }; return cachedShellConfig; } cachedShellConfig = { shell: "sh", args: ["-c"] }; return cachedShellConfig; } function getShellEnv() { const binDir = (0, _config.getBinDir)(); const pathKey = Object.keys(process.env).find((key) => key.toLowerCase() === "path") ?? "PATH"; const currentPath = process.env[pathKey] ?? ""; const pathEntries = currentPath.split(_nodePath.delimiter).filter(Boolean); const hasBinDir = pathEntries.includes(binDir); const updatedPath = hasBinDir ? currentPath : [binDir, currentPath].filter(Boolean).join(_nodePath.delimiter); return { ...process.env, [pathKey]: updatedPath }; } /** * Sanitize binary output for display/storage. * Removes characters that crash string-width or cause display issues: * - Control characters (except tab, newline, carriage return) * - Lone surrogates * - Unicode Format characters (crash string-width due to a bug) * - Characters with undefined code points */ function sanitizeBinaryOutput(str) { // Use Array.from to properly iterate over code points (not code units) // This handles surrogate pairs correctly and catches edge cases where // codePointAt() might return undefined return Array.from(str). filter((char) => { // Filter out characters that cause string-width to crash // This includes: // - Unicode format characters // - Lone surrogates (already filtered by Array.from) // - Control chars except \t \n \r // - Characters with undefined code points const code = char.codePointAt(0); // Skip if code point is undefined (edge case with invalid strings) if (code === undefined) return false; // Allow tab, newline, carriage return if (code === 0x09 || code === 0x0a || code === 0x0d) return true; // Filter out control characters (0x00-0x1F, except 0x09, 0x0a, 0x0x0d) if (code <= 0x1f) return false; // Filter out Unicode format characters if (code >= 0xfff9 && code <= 0xfffb) return false; return true; }). join(""); } /** * Kill a process and all its children (cross-platform) */ function killProcessTree(pid) { if (process.platform === "win32") { // Use taskkill on Windows to kill process tree try { (0, _child_process.spawn)("taskkill", ["/F", "/T", "/PID", String(pid)], { stdio: "ignore", detached: true }); } catch { // Ignore errors if taskkill fails }} else { // Use SIGKILL on Unix/Linux/Mac try { process.kill(-pid, "SIGKILL"); } catch { // Fallback to killing just the child if process group kill fails try { process.kill(pid, "SIGKILL"); } catch { // Process already dead }} } } /* v9-666d1723c069afff */