Spaces:
Paused
Paused
| # File 9: tools/code_tools.py | |
| with open(f"{base_dir}/tools/code_tools.py", "w") as f: | |
| f.write('''"""Code Development and Analysis Tools""" | |
| import os | |
| import re | |
| import json | |
| import subprocess | |
| import tempfile | |
| from typing import Dict, List, Optional | |
| from config import Config | |
| from utils import Logger, truncate | |
| class CodeTools: | |
| """Code linting, formatting, git operations, and project analysis""" | |
| def __init__(self): | |
| self.logger = Logger() | |
| def code_lint(self, path: str = ".", language: str = "python", | |
| fix: bool = False, rules: List[str] = None) -> Dict: | |
| """Lint code for errors and style issues""" | |
| try: | |
| full_path = os.path.join(Config.SANDBOX_PATH, path) | |
| if language == "python": | |
| tools_to_try = [ | |
| ("flake8", f"flake8 {'--fix' if fix else ''} {full_path}"), | |
| ("pylint", f"pylint {full_path}"), | |
| ] | |
| for tool_name, cmd in tools_to_try: | |
| result = subprocess.run( | |
| cmd, shell=True, capture_output=True, text=True, timeout=30 | |
| ) | |
| if result.returncode in [0, 1]: | |
| issues = [] | |
| for line in (result.stdout + result.stderr).split("\n"): | |
| if line.strip(): | |
| issues.append(line.strip()) | |
| return { | |
| "success": True, | |
| "tool": tool_name, | |
| "language": language, | |
| "issues": issues[:50], | |
| "total_issues": len(issues), | |
| "fixed": fix, | |
| "path": path | |
| } | |
| if os.path.isfile(full_path): | |
| with open(full_path, "r") as f: | |
| code = f.read() | |
| compile(code, full_path, "exec") | |
| return { | |
| "success": True, | |
| "tool": "builtin", | |
| "language": language, | |
| "issues": [], | |
| "total_issues": 0, | |
| "message": "Syntax OK" | |
| } | |
| elif language == "javascript": | |
| for tool, cmd in [("eslint", f"eslint {full_path}"), | |
| ("jshint", f"jshint {full_path}")]: | |
| result = subprocess.run( | |
| cmd, shell=True, capture_output=True, text=True, timeout=30 | |
| ) | |
| if result.returncode in [0, 1, 2]: | |
| return { | |
| "success": True, | |
| "tool": tool, | |
| "language": language, | |
| "output": (result.stdout + result.stderr)[:2000], | |
| "path": path | |
| } | |
| return { | |
| "success": True, | |
| "language": language, | |
| "message": "No linter available, basic syntax check passed", | |
| "path": path | |
| } | |
| except Exception as e: | |
| return {"success": False, "error": str(e)} | |
| def code_format(self, path: str = ".", language: str = "python", | |
| check_only: bool = False) -> Dict: | |
| """Format code automatically""" | |
| try: | |
| full_path = os.path.join(Config.SANDBOX_PATH, path) | |
| formatters = { | |
| "python": ("black", f"black {'--check' if check_only else ''} {full_path}"), | |
| "javascript": ("prettier", f"prettier {'--check' if check_only else '--write'} {full_path}"), | |
| "html": ("prettier", f"prettier --parser html {'--check' if check_only else '--write'} {full_path}"), | |
| "css": ("prettier", f"prettier --parser css {'--check' if check_only else '--write'} {full_path}"), | |
| } | |
| if language in formatters: | |
| tool, cmd = formatters[language] | |
| result = subprocess.run( | |
| cmd, shell=True, capture_output=True, text=True, timeout=30 | |
| ) | |
| return { | |
| "success": result.returncode in [0, 1], | |
| "tool": tool, | |
| "language": language, | |
| "formatted": not check_only and result.returncode == 0, | |
| "needs_formatting": result.returncode == 1, | |
| "output": (result.stdout + result.stderr)[:2000], | |
| "path": path | |
| } | |
| return {"success": False, "error": f"No formatter for {language}"} | |
| except Exception as e: | |
| return {"success": False, "error": str(e)} | |
| def git_command(self, action: str = "status", args: str = "", | |
| repo_path: str = ".") -> Dict: | |
| """Execute git commands""" | |
| try: | |
| full_repo = os.path.join(Config.SANDBOX_PATH, repo_path) | |
| os.makedirs(full_repo, exist_ok=True) | |
| if action == "init": | |
| cmd = f"git init {args}" | |
| elif action == "clone": | |
| cmd = f"git clone {args}" | |
| elif action == "commit": | |
| cmd = f'git commit {args}' | |
| else: | |
| cmd = f"git {action} {args}" | |
| result = subprocess.run( | |
| cmd, | |
| shell=True, | |
| capture_output=True, | |
| text=True, | |
| timeout=60, | |
| cwd=full_repo | |
| ) | |
| self.logger.log("git_command", {"action": action, "args": args, "repo": repo_path}) | |
| return { | |
| "success": result.returncode == 0, | |
| "action": action, | |
| "command": cmd, | |
| "stdout": result.stdout[:3000], | |
| "stderr": result.stderr[:1000], | |
| "repo": repo_path | |
| } | |
| except Exception as e: | |
| return {"success": False, "error": str(e)} | |
| def dependency_check(self, path: str = ".", manifest: str = "auto") -> Dict: | |
| """Check for outdated or vulnerable dependencies""" | |
| try: | |
| full_path = os.path.join(Config.SANDBOX_PATH, path) | |
| if manifest == "auto": | |
| for candidate in ["requirements.txt", "package.json", "pyproject.toml", "Pipfile"]: | |
| if os.path.exists(os.path.join(full_path, candidate)): | |
| manifest = candidate | |
| break | |
| if manifest == "requirements.txt": | |
| req_file = os.path.join(full_path, "requirements.txt") | |
| result = subprocess.run( | |
| f"pip list --outdated --format=json", | |
| shell=True, capture_output=True, text=True, timeout=30 | |
| ) | |
| outdated = [] | |
| try: | |
| packages = json.loads(result.stdout) | |
| with open(req_file, "r") as f: | |
| required = [line.split("==")[0].strip().lower() for line in f if line.strip() and not line.startswith("#")] | |
| for pkg in packages: | |
| if pkg["name"].lower() in required: | |
| outdated.append(pkg) | |
| except: | |
| pass | |
| return { | |
| "success": True, | |
| "manifest": manifest, | |
| "outdated": outdated, | |
| "total_outdated": len(outdated), | |
| "path": path | |
| } | |
| elif manifest == "package.json": | |
| pkg_file = os.path.join(full_path, "package.json") | |
| result = subprocess.run( | |
| "npm outdated --json", | |
| shell=True, capture_output=True, text=True, timeout=30, | |
| cwd=full_path | |
| ) | |
| outdated = {} | |
| try: | |
| outdated = json.loads(result.stdout) if result.stdout.strip() else {} | |
| except: | |
| pass | |
| return { | |
| "success": True, | |
| "manifest": manifest, | |
| "outdated": outdated, | |
| "total_outdated": len(outdated), | |
| "path": path | |
| } | |
| return { | |
| "success": True, | |
| "manifest": manifest, | |
| "message": "No manifest found or unsupported format", | |
| "path": path | |
| } | |
| except Exception as e: | |
| return {"success": False, "error": str(e)} | |
| def project_structure(self, path: str = ".", max_depth: int = 4, | |
| exclude: List[str] = None) -> Dict: | |
| """Analyze project structure""" | |
| try: | |
| full_path = os.path.join(Config.SANDBOX_PATH, path) | |
| if not exclude: | |
| exclude = ["node_modules", ".git", "__pycache__", ".venv", "venv", ".env", ".trash"] | |
| structure = [] | |
| file_count = 0 | |
| dir_count = 0 | |
| total_lines = 0 | |
| languages = {} | |
| for root, dirs, files in os.walk(full_path): | |
| depth = root[len(full_path):].count(os.sep) | |
| if depth > max_depth: | |
| del dirs[:] | |
| continue | |
| dirs[:] = [d for d in dirs if d not in exclude and not d.startswith(".")] | |
| rel_root = os.path.relpath(root, full_path) | |
| if rel_root == ".": | |
| rel_root = "" | |
| indent = " " * depth | |
| structure.append(f"{indent}[DIR] {os.path.basename(root) or path}") | |
| for file in sorted(files): | |
| if any(file.endswith(ext) for ext in [".pyc", ".pyo", ".class"]): | |
| continue | |
| file_path = os.path.join(root, file) | |
| file_indent = " " * (depth + 1) | |
| try: | |
| with open(file_path, "r", encoding="utf-8", errors="ignore") as f: | |
| lines = len(f.readlines()) | |
| total_lines += lines | |
| except: | |
| lines = 0 | |
| ext = os.path.splitext(file)[1] | |
| if ext: | |
| languages[ext] = languages.get(ext, 0) + 1 | |
| structure.append(f"{file_indent}{file} ({lines} lines)") | |
| file_count += 1 | |
| dir_count += 1 | |
| top_langs = sorted(languages.items(), key=lambda x: x[1], reverse=True)[:10] | |
| self.logger.log("project_structure", {"path": path, "files": file_count, "dirs": dir_count}) | |
| return { | |
| "success": True, | |
| "path": path, | |
| "structure": "\n".join(structure), | |
| "files": file_count, | |
| "directories": dir_count, | |
| "total_lines": total_lines, | |
| "top_languages": top_langs, | |
| "depth": max_depth | |
| } | |
| except Exception as e: | |
| return {"success": False, "error": str(e)} | |
| def code_search(self, path: str = ".", query: str = "", | |
| language: str = "", max_results: int = 50) -> Dict: | |
| """Search codebase with regex""" | |
| try: | |
| full_path = os.path.join(Config.SANDBOX_PATH, path) | |
| results = [] | |
| pattern = re.compile(query, re.IGNORECASE) | |
| for root, dirs, files in os.walk(full_path): | |
| dirs[:] = [d for d in dirs if not d.startswith(".") and d not in | |
| ["node_modules", "__pycache__", ".venv", "venv"]] | |
| for file in files: | |
| if language: | |
| ext_map = { | |
| "python": ".py", "javascript": ".js", "typescript": ".ts", | |
| "html": ".html", "css": ".css", "java": ".java", | |
| "cpp": ".cpp", "c": ".c", "go": ".go", "rust": ".rs" | |
| } | |
| if not file.endswith(ext_map.get(language, language)): | |
| continue | |
| file_path = os.path.join(root, file) | |
| rel_path = os.path.relpath(file_path, full_path) | |
| try: | |
| with open(file_path, "r", encoding="utf-8", errors="ignore") as f: | |
| lines = f.readlines() | |
| for i, line in enumerate(lines, 1): | |
| if pattern.search(line): | |
| results.append({ | |
| "file": rel_path, | |
| "line": i, | |
| "text": line.strip()[:150], | |
| "context": "".join(lines[max(0,i-2):min(len(lines),i+1)]).strip()[:300] | |
| }) | |
| if len(results) >= max_results: | |
| break | |
| except: | |
| continue | |
| if len(results) >= max_results: | |
| break | |
| return { | |
| "success": True, | |
| "query": query, | |
| "language": language, | |
| "results": results, | |
| "total": len(results), | |
| "path": path | |
| } | |
| except Exception as e: | |
| return {"success": False, "error": str(e)} | |
| ''') | |
| print("tools/code_tools.py done") |