Files
agent-aide/aide-program/aide/env/modules/node_deps.py

142 lines
4.2 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"""Node.js 项目依赖检测模块。"""
from __future__ import annotations
import subprocess
from pathlib import Path
from typing import Any
from aide.env.modules.base import BaseModule, CheckResult, ModuleInfo
class NodeDepsModule(BaseModule):
"""Node.js 项目依赖检测模块类型B需要配置
支持多种包管理器npm, pnpm, yarn, bun
自动根据锁文件检测包管理器类型
"""
# 锁文件到包管理器的映射
LOCK_FILES = {
"pnpm-lock.yaml": "pnpm",
"yarn.lock": "yarn",
"bun.lockb": "bun",
"package-lock.json": "npm",
}
# 包管理器安装命令
INSTALL_COMMANDS = {
"npm": ["npm", "install"],
"pnpm": ["pnpm", "install"],
"yarn": ["yarn", "install"],
"bun": ["bun", "install"],
}
@property
def info(self) -> ModuleInfo:
return ModuleInfo(
name="node_deps",
description="Node.js 项目依赖",
capabilities=["check", "ensure"],
requires_config=True,
config_keys=["path"],
)
def check(self, config: dict[str, Any], root: Path) -> CheckResult:
"""检测 Node.js 项目依赖。"""
project_path = root / config["path"]
# 检测 package.json 是否存在
package_json = project_path / "package.json"
if not package_json.exists():
return CheckResult(
success=False,
message=f"package.json 不存在: {config['path']}",
can_ensure=False,
)
# 检测 node_modules 是否存在
node_modules = project_path / "node_modules"
if not node_modules.exists():
manager = self._detect_manager(project_path, config)
return CheckResult(
success=False,
message=f"node_modules 不存在",
can_ensure=True,
)
# 检测包管理器
manager = self._detect_manager(project_path, config)
return CheckResult(
success=True,
version=config["path"],
message=manager,
)
def ensure(self, config: dict[str, Any], root: Path) -> CheckResult:
"""安装 Node.js 项目依赖。"""
project_path = root / config["path"]
manager = self._detect_manager(project_path, config)
# 检测包管理器是否已安装
if not self._is_manager_installed(manager):
return CheckResult(
success=False,
message=f"{manager} 未安装",
)
# 运行安装命令
install_cmd = self.INSTALL_COMMANDS.get(manager, ["npm", "install"])
try:
subprocess.run(
install_cmd,
cwd=project_path,
check=True,
capture_output=True,
)
return CheckResult(
success=True,
version=config["path"],
message=f"已安装 ({manager})",
)
except subprocess.CalledProcessError as exc:
error_msg = exc.stderr.decode() if exc.stderr else str(exc)
return CheckResult(
success=False,
message=f"安装失败: {error_msg[:100]}",
)
def _detect_manager(self, project_path: Path, config: dict[str, Any]) -> str:
"""检测包管理器类型。
优先使用配置指定的 manager否则根据锁文件自动检测。
"""
# 优先使用配置指定的 manager
if "manager" in config:
return config["manager"]
# 根据锁文件检测
for lock_file, manager in self.LOCK_FILES.items():
if (project_path / lock_file).exists():
return manager
# 默认使用 npm
return "npm"
def _is_manager_installed(self, manager: str) -> bool:
"""检测包管理器是否已安装。"""
try:
subprocess.run(
[manager, "--version"],
capture_output=True,
timeout=10,
)
return True
except (FileNotFoundError, subprocess.TimeoutExpired):
return False
module = NodeDepsModule()