Protokoll #15739

ID15739
Zeitstempel2025-12-25 16:56:31.197909
Clientroot
IP145.224.72.140
Modellclaude-sonnet-4-20250514
Statuscompleted
Tokens2,331 (Input: 1,163, Output: 1,168)
Dauer111 ms
Request-Zeit2025-12-25 16:56:31.197909
Response-Zeit2025-12-25 16:56:31.308840

Request

{
    "event": "PreToolUse",
    "tool_name": "Write",
    "tool_input": {
        "file_path": "\/var\/www\/tools\/ki-protokoll\/claude-hook\/quality\/rules_security.py",
        "content": "#!\/usr\/bin\/env python3\n\"\"\"\nSecurity & Architecture Rules (W2, W3, W7).\n\nRegeln für MVC-Architektur, Type-Safety und Dependency Injection.\n\"\"\"\n\nimport re\nfrom typing import List\nfrom .rule_base import Rule\n\n\n# =============================================================================\n# W2: MVC + CRUD - Architectural Boundaries\n# =============================================================================\n\nclass W2_1_BusinessKeywordsInController(Rule):\n    \"\"\"W2.1: Business-Keywords in Controller.\"\"\"\n\n    def should_skip(self, file_path: str) -> bool:\n        if \"\/Controller\/\" not in file_path:\n            return True\n        return super().should_skip(file_path)\n\n    def check(self, file_path: str, content: str) -> List[str]:\n        keywords = [\n            (r\"\\bcalculate\\w*\\s*\\(\", \"calculate\"),\n            (r\"\\bcompute\\w*\\s*\\(\", \"compute\"),\n            (r\"\\bvalidate\\w*\\s*\\(\", \"validate\"),\n            (r\"\\bprocess\\w*\\s*\\(\", \"process\"),\n            (r\"\\btransform\\w*\\s*\\(\", \"transform\"),\n            (r\"\\bconvert\\w*\\s*\\(\", \"convert\"),\n        ]\n\n        found = []\n        for pattern, name in keywords:\n            if re.search(pattern, content, re.IGNORECASE):\n                found.append(name)\n\n        if found:\n            return [f\"W2.1: Business keywords in Controller: {', '.join(found)}. Consider moving to Domain\/UseCase.\"]\n\n        return []\n\n\nclass W2_2_PrivateMethodsInController(Rule):\n    \"\"\"W2.2: Viele private Methoden in Controller (max 5).\"\"\"\n\n    def should_skip(self, file_path: str) -> bool:\n        if \"\/Controller\/\" not in file_path:\n            return True\n        return super().should_skip(file_path)\n\n    def check(self, file_path: str, content: str) -> List[str]:\n        private_methods = re.findall(r\"private\\s+function\\s+\\w+\", content)\n        count = len(private_methods)\n\n        if count > 5:\n            return [f\"W2.2: Controller has {count} private methods (max 5). Extract to Service.\"]\n\n        return []\n\n\n# =============================================================================\n# W3: PSR + Types - Type Safety\n# =============================================================================\n\nclass W3_1_PotentialUntypedParams(Rule):\n    \"\"\"W3.1: Potentiell untypisierte Parameter.\"\"\"\n\n    def check(self, file_path: str, content: str) -> List[str]:\n        # Heuristik: Suche nach $param direkt nach ( oder ,\n        potential = re.findall(r\"function\\s+\\w+\\s*\\([^)]*[(,]\\s*\\$\", content)\n\n        if potential:\n            return [\"W3.1: Potential untyped parameters detected. Run PHPStan for verification.\"]\n\n        return []\n\n\nclass W3_3_MixedType(Rule):\n    \"\"\"W3.3: mixed Type verwendet.\"\"\"\n\n    def check(self, file_path: str, content: str) -> List[str]:\n        if re.search(r\":\\s*mixed\\b\", content):\n            return [\"W3.3: 'mixed' type used. Consider more specific type.\"]\n\n        return []\n\n\n# =============================================================================\n# W7: DI + AUTOWIRING - Dependency Injection\n# =============================================================================\n\nclass W7_1_UseCaseInterfaceDependency(Rule):\n    \"\"\"W7.1: UseCase mit Interface-Dependency - Hinweis zur Registrierung.\"\"\"\n\n    def should_skip(self, file_path: str) -> bool:\n        if \"\/UseCases\/\" not in file_path:\n            return True\n        return super().should_skip(file_path)\n\n    def check(self, file_path: str, content: str) -> List[str]:\n        constructor_match = re.search(r\"function\\s+__construct\\s*\\(([^)]*)\\)\", content, re.DOTALL)\n        if not constructor_match:\n            return []\n\n        params = constructor_match.group(1)\n        interface_deps = re.findall(r\"(\\w+Interface)\\s+\\$\", params)\n\n        if interface_deps:\n            return [f\"W7.1: Hint - UseCase uses interfaces: {', '.join(interface_deps)}. Ensure registered in services.php.\"]\n\n        return []\n\n\n# =============================================================================\n# RULE COLLECTION\n# =============================================================================\n\nRULES = [\n    W2_1_BusinessKeywordsInController(),\n    W2_2_PrivateMethodsInController(),\n    W3_1_PotentialUntypedParams(),\n    W3_3_MixedType(),\n    W7_1_UseCaseInterfaceDependency(),\n]\n"
    }
}

Response

{
    "tool_response": {
        "type": "create",
        "filePath": "\/var\/www\/tools\/ki-protokoll\/claude-hook\/quality\/rules_security.py",
        "content": "#!\/usr\/bin\/env python3\n\"\"\"\nSecurity & Architecture Rules (W2, W3, W7).\n\nRegeln für MVC-Architektur, Type-Safety und Dependency Injection.\n\"\"\"\n\nimport re\nfrom typing import List\nfrom .rule_base import Rule\n\n\n# =============================================================================\n# W2: MVC + CRUD - Architectural Boundaries\n# =============================================================================\n\nclass W2_1_BusinessKeywordsInController(Rule):\n    \"\"\"W2.1: Business-Keywords in Controller.\"\"\"\n\n    def should_skip(self, file_path: str) -> bool:\n        if \"\/Controller\/\" not in file_path:\n            return True\n        return super().should_skip(file_path)\n\n    def check(self, file_path: str, content: str) -> List[str]:\n        keywords = [\n            (r\"\\bcalculate\\w*\\s*\\(\", \"calculate\"),\n            (r\"\\bcompute\\w*\\s*\\(\", \"compute\"),\n            (r\"\\bvalidate\\w*\\s*\\(\", \"validate\"),\n            (r\"\\bprocess\\w*\\s*\\(\", \"process\"),\n            (r\"\\btransform\\w*\\s*\\(\", \"transform\"),\n            (r\"\\bconvert\\w*\\s*\\(\", \"convert\"),\n        ]\n\n        found = []\n        for pattern, name in keywords:\n            if re.search(pattern, content, re.IGNORECASE):\n                found.append(name)\n\n        if found:\n            return [f\"W2.1: Business keywords in Controller: {', '.join(found)}. Consider moving to Domain\/UseCase.\"]\n\n        return []\n\n\nclass W2_2_PrivateMethodsInController(Rule):\n    \"\"\"W2.2: Viele private Methoden in Controller (max 5).\"\"\"\n\n    def should_skip(self, file_path: str) -> bool:\n        if \"\/Controller\/\" not in file_path:\n            return True\n        return super().should_skip(file_path)\n\n    def check(self, file_path: str, content: str) -> List[str]:\n        private_methods = re.findall(r\"private\\s+function\\s+\\w+\", content)\n        count = len(private_methods)\n\n        if count > 5:\n            return [f\"W2.2: Controller has {count} private methods (max 5). Extract to Service.\"]\n\n        return []\n\n\n# =============================================================================\n# W3: PSR + Types - Type Safety\n# =============================================================================\n\nclass W3_1_PotentialUntypedParams(Rule):\n    \"\"\"W3.1: Potentiell untypisierte Parameter.\"\"\"\n\n    def check(self, file_path: str, content: str) -> List[str]:\n        # Heuristik: Suche nach $param direkt nach ( oder ,\n        potential = re.findall(r\"function\\s+\\w+\\s*\\([^)]*[(,]\\s*\\$\", content)\n\n        if potential:\n            return [\"W3.1: Potential untyped parameters detected. Run PHPStan for verification.\"]\n\n        return []\n\n\nclass W3_3_MixedType(Rule):\n    \"\"\"W3.3: mixed Type verwendet.\"\"\"\n\n    def check(self, file_path: str, content: str) -> List[str]:\n        if re.search(r\":\\s*mixed\\b\", content):\n            return [\"W3.3: 'mixed' type used. Consider more specific type.\"]\n\n        return []\n\n\n# =============================================================================\n# W7: DI + AUTOWIRING - Dependency Injection\n# =============================================================================\n\nclass W7_1_UseCaseInterfaceDependency(Rule):\n    \"\"\"W7.1: UseCase mit Interface-Dependency - Hinweis zur Registrierung.\"\"\"\n\n    def should_skip(self, file_path: str) -> bool:\n        if \"\/UseCases\/\" not in file_path:\n            return True\n        return super().should_skip(file_path)\n\n    def check(self, file_path: str, content: str) -> List[str]:\n        constructor_match = re.search(r\"function\\s+__construct\\s*\\(([^)]*)\\)\", content, re.DOTALL)\n        if not constructor_match:\n            return []\n\n        params = constructor_match.group(1)\n        interface_deps = re.findall(r\"(\\w+Interface)\\s+\\$\", params)\n\n        if interface_deps:\n            return [f\"W7.1: Hint - UseCase uses interfaces: {', '.join(interface_deps)}. Ensure registered in services.php.\"]\n\n        return []\n\n\n# =============================================================================\n# RULE COLLECTION\n# =============================================================================\n\nRULES = [\n    W2_1_BusinessKeywordsInController(),\n    W2_2_PrivateMethodsInController(),\n    W3_1_PotentialUntypedParams(),\n    W3_3_MixedType(),\n    W7_1_UseCaseInterfaceDependency(),\n]\n",
        "structuredPatch": [],
        "originalFile": null
    }
}
← Vorheriger Zur Liste Nächster →