fix: resolve nvm when not in path

This commit is contained in:
Boris Arzentar 2025-12-02 10:43:57 +01:00
parent 5ee5ae294a
commit 5fe6a17cfd
No known key found for this signature in database
GPG key ID: D5CC274C784807B7
3 changed files with 101 additions and 41 deletions

View file

@ -11,6 +11,24 @@ from cognee.shared.logging_utils import get_logger
logger = get_logger() logger = get_logger()
def get_nvm_dir() -> Path:
"""
Get the nvm directory path following standard nvm installation logic.
Uses XDG_CONFIG_HOME if set, otherwise falls back to ~/.nvm.
"""
xdg_config_home = os.environ.get("XDG_CONFIG_HOME")
if xdg_config_home:
return Path(xdg_config_home) / "nvm"
return Path.home() / ".nvm"
def get_nvm_sh_path() -> Path:
"""
Get the path to nvm.sh following standard nvm installation logic.
"""
return get_nvm_dir() / "nvm.sh"
def check_nvm_installed() -> bool: def check_nvm_installed() -> bool:
""" """
Check if nvm (Node Version Manager) is installed. Check if nvm (Node Version Manager) is installed.
@ -29,14 +47,29 @@ def check_nvm_installed() -> bool:
) )
else: else:
# On Unix-like systems, nvm is a shell function, so we need to source it # On Unix-like systems, nvm is a shell function, so we need to source it
# First check if nvm.sh exists
nvm_path = get_nvm_sh_path()
if not nvm_path.exists():
logger.debug(f"nvm.sh not found at {nvm_path}")
return False
# Try to source nvm and check version, capturing errors
result = subprocess.run( result = subprocess.run(
["bash", "-c", "source ~/.nvm/nvm.sh 2>/dev/null && nvm --version"], ["bash", "-c", f"source {nvm_path} && nvm --version"],
capture_output=True, capture_output=True,
text=True, text=True,
timeout=10, timeout=10,
) )
if result.returncode != 0:
# Log the error to help diagnose configuration issues
if result.stderr:
logger.debug(f"nvm check failed: {result.stderr.strip()}")
return False
return result.returncode == 0 return result.returncode == 0
except Exception: except Exception as e:
logger.debug(f"Exception checking nvm: {str(e)}")
return False return False
@ -79,11 +112,13 @@ def install_nvm() -> bool:
if result.returncode == 0: if result.returncode == 0:
logger.info("✓ nvm installed successfully") logger.info("✓ nvm installed successfully")
# Source nvm in current shell session # Source nvm in current shell session
nvm_dir = Path.home() / ".nvm" nvm_dir = get_nvm_dir()
if nvm_dir.exists(): if nvm_dir.exists():
return True return True
else: else:
logger.warning("nvm installation completed but .nvm directory not found") logger.warning(
f"nvm installation completed but nvm directory not found at {nvm_dir}"
)
return False return False
else: else:
logger.error(f"nvm installation failed: {result.stderr}") logger.error(f"nvm installation failed: {result.stderr}")
@ -117,7 +152,12 @@ def install_node_with_nvm() -> bool:
try: try:
# Source nvm and install latest Node.js # Source nvm and install latest Node.js
nvm_source_cmd = "source ~/.nvm/nvm.sh" nvm_path = get_nvm_sh_path()
if not nvm_path.exists():
logger.error(f"nvm.sh not found at {nvm_path}. nvm may not be properly installed.")
return False
nvm_source_cmd = f"source {nvm_path}"
install_cmd = f"{nvm_source_cmd} && nvm install node" install_cmd = f"{nvm_source_cmd} && nvm install node"
result = subprocess.run( result = subprocess.run(
@ -141,7 +181,7 @@ def install_node_with_nvm() -> bool:
# Add nvm to PATH for current session # Add nvm to PATH for current session
# This ensures node/npm are available in subsequent commands # This ensures node/npm are available in subsequent commands
nvm_dir = Path.home() / ".nvm" nvm_dir = get_nvm_dir()
if nvm_dir.exists(): if nvm_dir.exists():
# Update PATH for current process # Update PATH for current process
nvm_bin = nvm_dir / "versions" / "node" nvm_bin = nvm_dir / "versions" / "node"
@ -178,14 +218,16 @@ def check_node_npm() -> tuple[bool, str]: # (is_available, error_message)
result = subprocess.run(["node", "--version"], capture_output=True, text=True, timeout=10) result = subprocess.run(["node", "--version"], capture_output=True, text=True, timeout=10)
if result.returncode != 0: if result.returncode != 0:
# If direct command fails, try with nvm sourced (in case nvm is installed but not in PATH) # If direct command fails, try with nvm sourced (in case nvm is installed but not in PATH)
nvm_path = Path.home() / ".nvm" / "nvm.sh" nvm_path = get_nvm_sh_path()
if nvm_path.exists(): if nvm_path.exists():
result = subprocess.run( result = subprocess.run(
["bash", "-c", "source ~/.nvm/nvm.sh 2>/dev/null && node --version"], ["bash", "-c", f"source {nvm_path} && node --version"],
capture_output=True, capture_output=True,
text=True, text=True,
timeout=10, timeout=10,
) )
if result.returncode != 0 and result.stderr:
logger.debug(f"Failed to source nvm or run node: {result.stderr.strip()}")
if result.returncode != 0: if result.returncode != 0:
# Node.js is not installed, try to install it # Node.js is not installed, try to install it
logger.info("Node.js is not installed. Attempting to install automatically...") logger.info("Node.js is not installed. Attempting to install automatically...")
@ -208,22 +250,27 @@ def check_node_npm() -> tuple[bool, str]: # (is_available, error_message)
# Verify installation after automatic setup # Verify installation after automatic setup
# Try with nvm sourced first # Try with nvm sourced first
nvm_path = Path.home() / ".nvm" / "nvm.sh" nvm_path = get_nvm_sh_path()
if nvm_path.exists(): if nvm_path.exists():
result = subprocess.run( result = subprocess.run(
["bash", "-c", "source ~/.nvm/nvm.sh 2>/dev/null && node --version"], ["bash", "-c", f"source {nvm_path} && node --version"],
capture_output=True, capture_output=True,
text=True, text=True,
timeout=10, timeout=10,
) )
if result.returncode != 0 and result.stderr:
logger.debug(
f"Failed to verify node after installation: {result.stderr.strip()}"
)
else: else:
result = subprocess.run( result = subprocess.run(
["node", "--version"], capture_output=True, text=True, timeout=10 ["node", "--version"], capture_output=True, text=True, timeout=10
) )
if result.returncode != 0: if result.returncode != 0:
nvm_path = get_nvm_sh_path()
return ( return (
False, False,
"Node.js installation completed but node command is not available. Please restart your terminal or source ~/.nvm/nvm.sh", f"Node.js installation completed but node command is not available. Please restart your terminal or source {nvm_path}",
) )
node_version = result.stdout.strip() node_version = result.stdout.strip()
@ -243,12 +290,16 @@ def check_node_npm() -> tuple[bool, str]: # (is_available, error_message)
) )
if result.returncode != 0: if result.returncode != 0:
# Try with nvm sourced # Try with nvm sourced
result = subprocess.run( nvm_path = get_nvm_sh_path()
["bash", "-c", "source ~/.nvm/nvm.sh 2>/dev/null && npm --version"], if nvm_path.exists():
capture_output=True, result = subprocess.run(
text=True, ["bash", "-c", f"source {nvm_path} && npm --version"],
timeout=10, capture_output=True,
) text=True,
timeout=10,
)
if result.returncode != 0 and result.stderr:
logger.debug(f"Failed to source nvm or run npm: {result.stderr.strip()}")
if result.returncode != 0: if result.returncode != 0:
return False, "npm is not installed or not in PATH" return False, "npm is not installed or not in PATH"
@ -288,17 +339,21 @@ def check_node_npm() -> tuple[bool, str]: # (is_available, error_message)
if result.returncode == 0: if result.returncode == 0:
node_version = result.stdout.strip() node_version = result.stdout.strip()
# Check npm # Check npm
result = subprocess.run( nvm_path = get_nvm_sh_path()
["bash", "-c", "source ~/.nvm/nvm.sh 2>/dev/null && npm --version"], if nvm_path.exists():
capture_output=True, result = subprocess.run(
text=True, ["bash", "-c", f"source {nvm_path} && npm --version"],
timeout=10, capture_output=True,
) text=True,
if result.returncode == 0: timeout=10,
npm_version = result.stdout.strip() )
return True, f"Node.js {node_version}, npm {npm_version}" if result.returncode == 0:
except Exception: npm_version = result.stdout.strip()
pass return True, f"Node.js {node_version}, npm {npm_version}"
elif result.stderr:
logger.debug(f"Failed to source nvm or run npm: {result.stderr.strip()}")
except Exception as e:
logger.debug(f"Exception retrying node/npm check: {str(e)}")
return False, "Node.js/npm not found. Please install Node.js from https://nodejs.org/" return False, "Node.js/npm not found. Please install Node.js from https://nodejs.org/"
except Exception as e: except Exception as e:

View file

@ -4,6 +4,7 @@ from pathlib import Path
from typing import List from typing import List
from cognee.shared.logging_utils import get_logger from cognee.shared.logging_utils import get_logger
from .node_setup import get_nvm_sh_path
logger = get_logger() logger = get_logger()
@ -33,13 +34,17 @@ def run_npm_command(cmd: List[str], cwd: Path, timeout: int = 300) -> subprocess
timeout=timeout, timeout=timeout,
) )
# If it fails and nvm might be installed, try with nvm sourced # If it fails and nvm might be installed, try with nvm sourced
if result.returncode != 0 and (Path.home() / ".nvm" / "nvm.sh").exists(): if result.returncode != 0:
nvm_cmd = f"source ~/.nvm/nvm.sh 2>/dev/null && {' '.join(cmd)}" nvm_path = get_nvm_sh_path()
result = subprocess.run( if nvm_path.exists():
["bash", "-c", nvm_cmd], nvm_cmd = f"source {nvm_path} && {' '.join(cmd)}"
cwd=cwd, result = subprocess.run(
capture_output=True, ["bash", "-c", nvm_cmd],
text=True, cwd=cwd,
timeout=timeout, capture_output=True,
) text=True,
timeout=timeout,
)
if result.returncode != 0 and result.stderr:
logger.debug(f"npm command failed with nvm: {result.stderr.strip()}")
return result return result

View file

@ -15,7 +15,7 @@ import shutil
from cognee.shared.logging_utils import get_logger from cognee.shared.logging_utils import get_logger
from cognee.version import get_cognee_version from cognee.version import get_cognee_version
from .node_setup import check_node_npm from .node_setup import check_node_npm, get_nvm_dir, get_nvm_sh_path
from .npm_utils import run_npm_command from .npm_utils import run_npm_command
logger = get_logger() logger = get_logger()
@ -586,10 +586,10 @@ def start_ui(
env["PORT"] = str(port) env["PORT"] = str(port)
# If nvm is installed, ensure it's available in the environment # If nvm is installed, ensure it's available in the environment
nvm_path = Path.home() / ".nvm" / "nvm.sh" nvm_path = get_nvm_sh_path()
if platform.system() != "Windows" and nvm_path.exists(): if platform.system() != "Windows" and nvm_path.exists():
# Add nvm to PATH for the subprocess # Add nvm to PATH for the subprocess
nvm_dir = Path.home() / ".nvm" nvm_dir = get_nvm_dir()
# Find the latest Node.js version installed via nvm # Find the latest Node.js version installed via nvm
nvm_versions = nvm_dir / "versions" / "node" nvm_versions = nvm_dir / "versions" / "node"
if nvm_versions.exists(): if nvm_versions.exists():
@ -621,7 +621,7 @@ def start_ui(
if nvm_path.exists(): if nvm_path.exists():
# Use bash to source nvm and run npm # Use bash to source nvm and run npm
process = subprocess.Popen( process = subprocess.Popen(
["bash", "-c", "source ~/.nvm/nvm.sh 2>/dev/null && npm run dev"], ["bash", "-c", f"source {nvm_path} && npm run dev"],
cwd=frontend_path, cwd=frontend_path,
env=env, env=env,
stdout=subprocess.PIPE, stdout=subprocess.PIPE,