| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
|
|
| import ast |
| import logging |
| import time |
| from pathlib import Path |
| from typing import Dict |
|
|
| logger = logging.getLogger("tools.workspace") |
|
|
| |
| _stats_cache = {"data": None, "expires": 0} |
| _STATS_TTL = 30 |
|
|
|
|
| class WorkspaceTool: |
| """Repository mapping and statistics.""" |
|
|
| def __init__(self, repo_path: Path, ng, policy_engine=None): |
| self.repo_path = repo_path |
| self.ng = ng |
| self.policy_engine = policy_engine |
|
|
| def map_repository_structure(self) -> str: |
| graph = {"nodes": [], "edges": []} |
| try: |
| file_count = 0 |
| for file_path in self.repo_path.rglob('*.py'): |
| if 'venv' in str(file_path): |
| continue |
| rel_path = str(file_path.relative_to(self.repo_path)) |
| content = file_path.read_text(errors='ignore') |
| file_count += 1 |
| graph["nodes"].append({"id": rel_path, "type": "file"}) |
| try: |
| tree = ast.parse(content) |
| for node in ast.walk(tree): |
| if isinstance(node, (ast.FunctionDef, ast.ClassDef)): |
| node_id = f"{rel_path}::{node.name}" |
| graph["nodes"].append({"id": node_id, "type": "function"}) |
| except SyntaxError: |
| continue |
| return f"Map Generated: {file_count} files, {len(graph['nodes'])} nodes." |
| except (OSError, PermissionError) as e: |
| logger.error("[workspace] map_repository_structure failed: %s: %s", type(e).__name__, e, exc_info=True) |
| return {"status": "error", "tool": "workspace", "error": str(e), "type": type(e).__name__} |
|
|
| def get_stats(self) -> Dict: |
| now = time.time() |
| if _stats_cache["data"] and now < _stats_cache["expires"]: |
| return _stats_cache["data"] |
|
|
| ng_stats = {} |
| try: |
| ng_stats = self.ng.stats() |
| except (OSError, ValueError, AttributeError) as e: |
| logger.warning("NG stats retrieval failed: %s: %s", type(e).__name__, e) |
|
|
| |
| file_count = 0 |
| for p in self.repo_path.rglob("*"): |
| if p.is_file() and not any(skip in p.parts for skip in ("venv", "__pycache__", ".git")): |
| file_count += 1 |
|
|
| stats = { |
| "total_files": file_count, |
| "conversations": ng_stats.get("message_count", 0), |
| "ng_nodes": ng_stats.get("nodes", 0), |
| "ng_synapses": ng_stats.get("synapses", 0), |
| "ng_firing_rate": ng_stats.get("firing_rate", 0.0), |
| "ng_prediction_accuracy": ng_stats.get("prediction_accuracy", 0.0), |
| } |
| _stats_cache["data"] = stats |
| _stats_cache["expires"] = now + _STATS_TTL |
| return stats |
|
|