Protokoll #28435

ID28435
Zeitstempel2025-12-28 13:27:02.899258
Clientroot
IP145.224.72.140
Modellclaude-sonnet-4-20250514
Statuscompleted
Tokens2,061 (Input: 1,028, Output: 1,033)
Dauer101 ms
Request-Zeit2025-12-28 13:27:02.899258
Response-Zeit2025-12-28 13:27:03.000092

Request

{
    "event": "PreToolUse",
    "tool_name": "Write",
    "tool_input": {
        "file_path": "\/var\/www\/mcp-servers\/mcp_contracts\/validators\/scope_resolver.py",
        "content": "\"\"\"Scope Resolver - Pfad-Aufloesung und Glob-Pattern-Matching.\"\"\"\n\nimport os\nimport glob as globlib\nfrom pathlib import Path\nfrom typing import Optional\n\n\nclass ScopeResolver:\n    \"\"\"Loest Pfade und Glob-Patterns auf.\"\"\"\n\n    def __init__(self, base_path: str = \"\/var\/www\/dev.campus.systemische-tools.de\"):\n        self.base_path = base_path\n\n    def resolve_paths(\n        self,\n        scope: dict,\n        target_path: Optional[str] = None,\n        legacy_applicability: Optional[dict] = None,\n    ) -> list[str]:\n        \"\"\"\n        Ermittelt zu pruefende Pfade aus Scope.\n\n        Args:\n            scope: Contract scope dict mit paths\/includes\/excludes\n            target_path: Optional spezifischer Pfad\n            legacy_applicability: Legacy applicability dict\n\n        Returns:\n            Liste der aufgeloesten Pfade (dedupliziert)\n        \"\"\"\n        if target_path:\n            return [target_path]\n\n        paths_list = self._get_paths_list(scope, legacy_applicability)\n        excludes = scope.get(\"excludes\", [])\n\n        check_paths = []\n        for pattern in paths_list:\n            matched = self._expand_glob(pattern)\n            for path in matched:\n                if not self._is_excluded(path, excludes):\n                    check_paths.append(path)\n\n        return list(set(check_paths))\n\n    def _get_paths_list(\n        self, scope: dict, legacy_applicability: Optional[dict] = None\n    ) -> list[str]:\n        \"\"\"Extrahiert Pfade aus verschiedenen Contract-Formaten.\"\"\"\n        # Neues Standard-Format\n        paths_list = scope.get(\"paths\", [])\n\n        # Legacy-Formate als Fallback\n        if not paths_list:\n            paths_list = scope.get(\"includes\", [])\n        if not paths_list:\n            paths_list = scope.get(\"applies_to_paths\", [])\n        if not paths_list and legacy_applicability:\n            paths_list = legacy_applicability.get(\"scope\", [])\n            if isinstance(paths_list, str):\n                paths_list = [paths_list]\n\n        return paths_list\n\n    def _expand_glob(self, pattern: str) -> list[str]:\n        \"\"\"Expandiert Glob-Pattern zu konkreten Pfaden.\"\"\"\n        full_pattern = os.path.join(self.base_path, pattern.lstrip(\"\/\"))\n        matched = globlib.glob(full_pattern, recursive=True)\n\n        if matched:\n            return matched\n\n        # Fallback: Basisverzeichnis wenn kein Match\n        pattern_path = pattern.replace(\"**\", \"\").replace(\"*\", \"\").rstrip(\"\/\")\n        full_path = os.path.join(self.base_path, pattern_path.lstrip(\"\/\"))\n        if os.path.exists(full_path):\n            return [full_path]\n\n        return []\n\n    def _is_excluded(self, path: str, excludes: list[str]) -> bool:\n        \"\"\"Prueft ob Pfad durch Exclude-Pattern ausgeschlossen wird.\"\"\"\n        for excl in excludes:\n            excl_pattern = os.path.join(self.base_path, excl.lstrip(\"\/\"))\n            if globlib.fnmatch.fnmatch(path, excl_pattern):\n                return True\n        return False\n\n    def file_matches_pattern(self, file_path: str, pattern: str) -> bool:\n        \"\"\"Prueft ob Datei zum Glob-Pattern passt.\"\"\"\n        rel_path = file_path.replace(self.base_path, \"\").lstrip(\"\/\")\n\n        if \"**\" in pattern:\n            parts = pattern.split(\"**\")\n            if len(parts) == 2:\n                prefix = parts[0].rstrip(\"\/\")\n                suffix = parts[1].lstrip(\"\/\")\n                if prefix and not rel_path.startswith(prefix.lstrip(\"\/\")):\n                    return False\n                if suffix and not globlib.fnmatch.fnmatch(rel_path, f\"*{suffix}\"):\n                    return False\n                return True\n        elif \"*\" in pattern:\n            return globlib.fnmatch.fnmatch(rel_path, pattern)\n        else:\n            return pattern in rel_path\n\n        return True\n"
    }
}

Response

{
    "tool_response": {
        "type": "create",
        "filePath": "\/var\/www\/mcp-servers\/mcp_contracts\/validators\/scope_resolver.py",
        "content": "\"\"\"Scope Resolver - Pfad-Aufloesung und Glob-Pattern-Matching.\"\"\"\n\nimport os\nimport glob as globlib\nfrom pathlib import Path\nfrom typing import Optional\n\n\nclass ScopeResolver:\n    \"\"\"Loest Pfade und Glob-Patterns auf.\"\"\"\n\n    def __init__(self, base_path: str = \"\/var\/www\/dev.campus.systemische-tools.de\"):\n        self.base_path = base_path\n\n    def resolve_paths(\n        self,\n        scope: dict,\n        target_path: Optional[str] = None,\n        legacy_applicability: Optional[dict] = None,\n    ) -> list[str]:\n        \"\"\"\n        Ermittelt zu pruefende Pfade aus Scope.\n\n        Args:\n            scope: Contract scope dict mit paths\/includes\/excludes\n            target_path: Optional spezifischer Pfad\n            legacy_applicability: Legacy applicability dict\n\n        Returns:\n            Liste der aufgeloesten Pfade (dedupliziert)\n        \"\"\"\n        if target_path:\n            return [target_path]\n\n        paths_list = self._get_paths_list(scope, legacy_applicability)\n        excludes = scope.get(\"excludes\", [])\n\n        check_paths = []\n        for pattern in paths_list:\n            matched = self._expand_glob(pattern)\n            for path in matched:\n                if not self._is_excluded(path, excludes):\n                    check_paths.append(path)\n\n        return list(set(check_paths))\n\n    def _get_paths_list(\n        self, scope: dict, legacy_applicability: Optional[dict] = None\n    ) -> list[str]:\n        \"\"\"Extrahiert Pfade aus verschiedenen Contract-Formaten.\"\"\"\n        # Neues Standard-Format\n        paths_list = scope.get(\"paths\", [])\n\n        # Legacy-Formate als Fallback\n        if not paths_list:\n            paths_list = scope.get(\"includes\", [])\n        if not paths_list:\n            paths_list = scope.get(\"applies_to_paths\", [])\n        if not paths_list and legacy_applicability:\n            paths_list = legacy_applicability.get(\"scope\", [])\n            if isinstance(paths_list, str):\n                paths_list = [paths_list]\n\n        return paths_list\n\n    def _expand_glob(self, pattern: str) -> list[str]:\n        \"\"\"Expandiert Glob-Pattern zu konkreten Pfaden.\"\"\"\n        full_pattern = os.path.join(self.base_path, pattern.lstrip(\"\/\"))\n        matched = globlib.glob(full_pattern, recursive=True)\n\n        if matched:\n            return matched\n\n        # Fallback: Basisverzeichnis wenn kein Match\n        pattern_path = pattern.replace(\"**\", \"\").replace(\"*\", \"\").rstrip(\"\/\")\n        full_path = os.path.join(self.base_path, pattern_path.lstrip(\"\/\"))\n        if os.path.exists(full_path):\n            return [full_path]\n\n        return []\n\n    def _is_excluded(self, path: str, excludes: list[str]) -> bool:\n        \"\"\"Prueft ob Pfad durch Exclude-Pattern ausgeschlossen wird.\"\"\"\n        for excl in excludes:\n            excl_pattern = os.path.join(self.base_path, excl.lstrip(\"\/\"))\n            if globlib.fnmatch.fnmatch(path, excl_pattern):\n                return True\n        return False\n\n    def file_matches_pattern(self, file_path: str, pattern: str) -> bool:\n        \"\"\"Prueft ob Datei zum Glob-Pattern passt.\"\"\"\n        rel_path = file_path.replace(self.base_path, \"\").lstrip(\"\/\")\n\n        if \"**\" in pattern:\n            parts = pattern.split(\"**\")\n            if len(parts) == 2:\n                prefix = parts[0].rstrip(\"\/\")\n                suffix = parts[1].lstrip(\"\/\")\n                if prefix and not rel_path.startswith(prefix.lstrip(\"\/\")):\n                    return False\n                if suffix and not globlib.fnmatch.fnmatch(rel_path, f\"*{suffix}\"):\n                    return False\n                return True\n        elif \"*\" in pattern:\n            return globlib.fnmatch.fnmatch(rel_path, pattern)\n        else:\n            return pattern in rel_path\n\n        return True\n",
        "structuredPatch": [],
        "originalFile": null
    }
}
← Vorheriger Zur Liste Nächster →