fix: use shell=True on Windows for subprocess calls (npm/claude are .cmd)
Without shell=True, subprocess.run(["npm", ...]) fails on Windows because npm and claude are .cmd batch files, not .exe. Added run_cmd() wrapper that sets shell=True only on Windows, keeping Linux/macOS behavior unchanged. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -69,6 +69,13 @@ def eprint(*args, **kwargs):
|
||||
print(*args, file=sys.stderr, **kwargs)
|
||||
|
||||
|
||||
def run_cmd(cmd, **kwargs):
|
||||
"""run_cmd wrapper: uses shell=True on Windows for .cmd/.bat commands (npm, claude, etc.)."""
|
||||
if IS_WINDOWS:
|
||||
kwargs.setdefault("shell", True)
|
||||
return subprocess.run(cmd, **kwargs)
|
||||
|
||||
|
||||
# ============================================================
|
||||
# Node.js check and auto-install
|
||||
# ============================================================
|
||||
@@ -79,7 +86,7 @@ MIN_NODE_VERSION = (24, 13, 0)
|
||||
def get_node_version():
|
||||
"""Get installed Node.js version as tuple, or None."""
|
||||
try:
|
||||
result = subprocess.run(
|
||||
result = run_cmd(
|
||||
["node", "--version"],
|
||||
capture_output=True, text=True, timeout=10,
|
||||
)
|
||||
@@ -103,7 +110,7 @@ def install_node():
|
||||
if IS_MACOS:
|
||||
print(f" Installing Node.js via Homebrew...")
|
||||
try:
|
||||
result = subprocess.run(
|
||||
result = run_cmd(
|
||||
["brew", "install", "node"],
|
||||
timeout=120, capture_output=True, text=True,
|
||||
)
|
||||
@@ -125,7 +132,7 @@ def install_node():
|
||||
if os.path.isfile(old_list):
|
||||
os.remove(old_list)
|
||||
|
||||
result = subprocess.run(
|
||||
result = run_cmd(
|
||||
["bash", "-c", "curl -fsSL https://deb.nodesource.com/setup_24.x | bash - && apt-get install -y nodejs"],
|
||||
timeout=180, capture_output=True, text=True,
|
||||
)
|
||||
@@ -140,7 +147,7 @@ def install_node():
|
||||
# Try dnf/yum fallback for RHEL/Fedora
|
||||
for pkg_mgr in ["dnf", "yum"]:
|
||||
if shutil.which(pkg_mgr):
|
||||
result = subprocess.run(
|
||||
result = run_cmd(
|
||||
["bash", "-c", f"curl -fsSL https://rpm.nodesource.com/setup_24.x | bash - && {pkg_mgr} install -y nodejs"],
|
||||
timeout=180, capture_output=True, text=True,
|
||||
)
|
||||
@@ -213,7 +220,7 @@ def ensure_claude_code(target_version=None):
|
||||
pkg = "@anthropic-ai/claude-code" + (f"@{target_version}" if target_version else "")
|
||||
|
||||
try:
|
||||
result = subprocess.run(
|
||||
result = run_cmd(
|
||||
["npm", "install", "-g", pkg],
|
||||
capture_output=True, text=True, timeout=300,
|
||||
)
|
||||
@@ -291,7 +298,7 @@ def get_installed_version():
|
||||
|
||||
# 2. claude --version
|
||||
try:
|
||||
result = subprocess.run(
|
||||
result = run_cmd(
|
||||
["claude", "--version"],
|
||||
capture_output=True, text=True, timeout=10,
|
||||
)
|
||||
@@ -362,13 +369,13 @@ def git_pull():
|
||||
"""Pull latest changes from remote (shallow fetch for minimal download)."""
|
||||
try:
|
||||
# Shallow fetch + reset — downloads only latest commit, not full history
|
||||
result = subprocess.run(
|
||||
result = run_cmd(
|
||||
["git", "fetch", "--depth", "1", "origin", "master"],
|
||||
cwd=REPO_ROOT, capture_output=True, text=True, timeout=60,
|
||||
)
|
||||
if result.returncode != 0:
|
||||
# Fallback to regular pull
|
||||
result = subprocess.run(
|
||||
result = run_cmd(
|
||||
["git", "pull", "--quiet"],
|
||||
cwd=REPO_ROOT, capture_output=True, text=True, timeout=60,
|
||||
)
|
||||
@@ -377,7 +384,7 @@ def git_pull():
|
||||
return True
|
||||
|
||||
# Reset to fetched state
|
||||
subprocess.run(
|
||||
run_cmd(
|
||||
["git", "reset", "--hard", "origin/master"],
|
||||
cwd=REPO_ROOT, capture_output=True, text=True, timeout=10,
|
||||
)
|
||||
@@ -414,7 +421,7 @@ def _setup_sparse_checkout():
|
||||
return
|
||||
|
||||
# Enable sparse checkout
|
||||
subprocess.run(
|
||||
run_cmd(
|
||||
["git", "config", "core.sparseCheckout", "true"],
|
||||
cwd=REPO_ROOT, capture_output=True,
|
||||
)
|
||||
@@ -432,7 +439,7 @@ def _setup_sparse_checkout():
|
||||
f.write("\n".join(patterns) + "\n")
|
||||
|
||||
# Apply sparse checkout
|
||||
subprocess.run(
|
||||
run_cmd(
|
||||
["git", "checkout", "HEAD", "--", "."],
|
||||
cwd=REPO_ROOT, capture_output=True, timeout=30,
|
||||
)
|
||||
@@ -461,7 +468,7 @@ def install_cli_js(version, cli_js_path):
|
||||
os.chmod(cli_js_path, 0o755)
|
||||
|
||||
# Syntax check
|
||||
result = subprocess.run(
|
||||
result = run_cmd(
|
||||
["node", "--check", cli_js_path],
|
||||
capture_output=True, text=True, timeout=30,
|
||||
)
|
||||
@@ -748,7 +755,7 @@ def _set_user_env_windows(config):
|
||||
|
||||
for key, val in env_vars.items():
|
||||
try:
|
||||
subprocess.run(["setx", key, val], capture_output=True, check=True)
|
||||
run_cmd(["setx", key, val], capture_output=True, check=True)
|
||||
os.environ[key] = val
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
Reference in New Issue
Block a user