Protokoll #14506
| ID | 14506 |
|---|---|
| Zeitstempel | 2025-12-25 10:44:33.632369 |
| Client | root |
| IP | Warning: Undefined array key "request_ip" in /var/www/dev.campus.systemische-tools.de/src/View/protokoll/show.php on line 13 Deprecated: htmlspecialchars(): Passing null to parameter #1 ($string) of type string is deprecated in /var/www/dev.campus.systemische-tools.de/src/View/protokoll/show.php on line 13 |
| Modell | claude-sonnet-4-20250514 |
| Status | completed |
| Tokens | 4,993 (Input: 0, Output: 0) |
| Dauer | 112 ms |
| Request-Zeit | Warning: Undefined array key "request_timestamp" in /var/www/dev.campus.systemische-tools.de/src/View/protokoll/show.php on line 18 |
| Response-Zeit | - |
Warning: Undefined array key "error_message" in /var/www/dev.campus.systemische-tools.de/src/View/protokoll/show.php on line 22
Request
{
"event": "PreToolUse",
"tool_name": "Write",
"tool_input": {
"file_path": "\/var\/www\/tools\/ki-protokoll\/claude-hook\/quality\/full_scan.py",
"content": "#!\/usr\/bin\/env python3\n\"\"\"\nFull Codebase Quality Scan.\n\nScannt alle PHP-Dateien gegen Pre- und Post-Hook Regeln.\nErstellt optional Tasks für Violations.\n\nUsage:\n full_scan.py # Scan mit Output\n full_scan.py --json # JSON-Output\n full_scan.py --create-tasks # Tasks für Violations erstellen\n full_scan.py --path \/src # Nur bestimmten Pfad scannen\n\"\"\"\n\nimport argparse\nimport json\nimport os\nimport sys\nfrom pathlib import Path\nfrom typing import Dict, List, Any\n\n# Eigene Module laden\nsys.path.insert(0, str(Path(__file__).parent))\nimport pre_rules\nimport post_rules\n\n# =============================================================================\n# CONFIGURATION\n# =============================================================================\n\nDEFAULT_SCAN_PATH = \"\/var\/www\/dev.campus.systemische-tools.de\/src\"\n\nSKIP_DIRS = [\n \"\/vendor\/\",\n \"\/node_modules\/\",\n \"\/.git\/\",\n \"\/cache\/\",\n \"\/var\/\",\n]\n\n# =============================================================================\n# SCANNER\n# =============================================================================\n\n\ndef find_php_files(base_path: str) -> List[Path]:\n \"\"\"Findet alle PHP-Dateien im Pfad.\"\"\"\n base = Path(base_path)\n if not base.exists():\n return []\n\n files = []\n for php_file in base.rglob(\"*.php\"):\n file_str = str(php_file)\n if not any(skip in file_str for skip in SKIP_DIRS):\n files.append(php_file)\n\n return sorted(files)\n\n\ndef scan_file(file_path: Path) -> Dict[str, Any]:\n \"\"\"Scannt eine einzelne Datei.\"\"\"\n try:\n content = file_path.read_text(encoding=\"utf-8\")\n except (OSError, UnicodeDecodeError) as e:\n return {\n \"file\": str(file_path),\n \"error\": str(e),\n \"blocks\": [],\n \"warnings\": [],\n }\n\n file_str = str(file_path)\n\n # Pre-Rules (Blocks)\n pre_result = pre_rules.check(file_str, content)\n blocks = []\n if not pre_result.get(\"allowed\", True):\n blocks.append(pre_result.get(\"message\", \"Unknown block\"))\n\n # Post-Rules (Warnings)\n post_result = post_rules.check(file_str, content)\n warnings = post_result.get(\"warnings\", [])\n\n return {\n \"file\": file_str,\n \"blocks\": blocks,\n \"warnings\": warnings,\n }\n\n\ndef scan_all(base_path: str) -> Dict[str, Any]:\n \"\"\"Scannt alle PHP-Dateien.\"\"\"\n files = find_php_files(base_path)\n\n results = {\n \"scan_path\": base_path,\n \"total_files\": len(files),\n \"files_with_blocks\": 0,\n \"files_with_warnings\": 0,\n \"total_blocks\": 0,\n \"total_warnings\": 0,\n \"violations\": [],\n }\n\n for file_path in files:\n file_result = scan_file(file_path)\n\n if file_result.get(\"error\"):\n results[\"violations\"].append(file_result)\n continue\n\n has_issues = False\n\n if file_result[\"blocks\"]:\n results[\"files_with_blocks\"] += 1\n results[\"total_blocks\"] += len(file_result[\"blocks\"])\n has_issues = True\n\n if file_result[\"warnings\"]:\n results[\"files_with_warnings\"] += 1\n results[\"total_warnings\"] += len(file_result[\"warnings\"])\n has_issues = True\n\n if has_issues:\n results[\"violations\"].append(file_result)\n\n return results\n\n\n# =============================================================================\n# OUTPUT FORMATTERS\n# =============================================================================\n\n\ndef format_console(results: Dict[str, Any]) -> str:\n \"\"\"Formatiert Ergebnis für Console-Output.\"\"\"\n lines = []\n lines.append(\"=\" * 70)\n lines.append(\"QUALITY SCAN REPORT\")\n lines.append(\"=\" * 70)\n lines.append(f\"Scan Path: {results['scan_path']}\")\n lines.append(f\"Total Files: {results['total_files']}\")\n lines.append(\"\")\n lines.append(f\"Files with BLOCKS: {results['files_with_blocks']}\")\n lines.append(f\"Files with WARNINGS: {results['files_with_warnings']}\")\n lines.append(f\"Total BLOCKS: {results['total_blocks']}\")\n lines.append(f\"Total WARNINGS: {results['total_warnings']}\")\n lines.append(\"\")\n\n if results[\"violations\"]:\n lines.append(\"-\" * 70)\n lines.append(\"VIOLATIONS:\")\n lines.append(\"-\" * 70)\n\n for v in results[\"violations\"]:\n # Kurzer Pfad\n short_path = v[\"file\"].replace(\"\/var\/www\/dev.campus.systemische-tools.de\/\", \"\")\n lines.append(f\"\\n{short_path}\")\n\n if v.get(\"error\"):\n lines.append(f\" ERROR: {v['error']}\")\n\n for block in v.get(\"blocks\", []):\n lines.append(f\" [BLOCK] {block}\")\n\n for warning in v.get(\"warnings\", []):\n lines.append(f\" [WARN] {warning}\")\n\n lines.append(\"\")\n lines.append(\"=\" * 70)\n\n if results[\"total_blocks\"] > 0:\n lines.append(\"STATUS: FAILED (has blocking violations)\")\n elif results[\"total_warnings\"] > 0:\n lines.append(\"STATUS: PASSED with warnings\")\n else:\n lines.append(\"STATUS: PASSED\")\n\n lines.append(\"=\" * 70)\n\n return \"\\n\".join(lines)\n\n\ndef format_json(results: Dict[str, Any]) -> str:\n \"\"\"Formatiert Ergebnis als JSON.\"\"\"\n return json.dumps(results, indent=2, ensure_ascii=False)\n\n\n# =============================================================================\n# TASK CREATION\n# =============================================================================\n\n\ndef create_tasks_for_violations(results: Dict[str, Any]) -> List[Dict[str, Any]]:\n \"\"\"Erstellt Tasks für alle Violations.\"\"\"\n try:\n import task_creator\n except ImportError:\n return [{\"error\": \"task_creator module not found\"}]\n\n created = []\n\n for v in results[\"violations\"]:\n file_path = v[\"file\"]\n\n for block in v.get(\"blocks\", []):\n # Parse Rule-ID aus Message\n rule_id = \"UNKNOWN\"\n if \"[\" in block and \"]\" in block:\n rule_id = block.split(\"[\")[1].split(\"]\")[0]\n\n try:\n task_id = task_creator.create_violation_task(\n file_path, rule_id, block, \"block\"\n )\n created.append({\n \"file\": file_path,\n \"rule\": rule_id,\n \"type\": \"block\",\n \"task_id\": task_id,\n })\n except Exception as e:\n created.append({\n \"file\": file_path,\n \"rule\": rule_id,\n \"type\": \"block\",\n \"error\": str(e),\n })\n\n for warning in v.get(\"warnings\", []):\n # Parse Rule-ID aus Warning\n rule_id = \"UNKNOWN\"\n if warning.startswith(\"W\") and \":\" in warning:\n rule_id = warning.split(\":\")[0]\n\n try:\n task_id = task_creator.create_warning_task(file_path, rule_id, warning)\n created.append({\n \"file\": file_path,\n \"rule\": rule_id,\n \"type\": \"warning\",\n \"task_id\": task_id,\n })\n except Exception as e:\n created.append({\n \"file\": file_path,\n \"rule\": rule_id,\n \"type\": \"warning\",\n \"error\": str(e),\n })\n\n return created\n\n\n# =============================================================================\n# MAIN\n# =============================================================================\n\n\ndef main():\n parser = argparse.ArgumentParser(description=\"Full Codebase Quality Scan\")\n parser.add_argument(\n \"--path\",\n default=DEFAULT_SCAN_PATH,\n help=f\"Path to scan (default: {DEFAULT_SCAN_PATH})\",\n )\n parser.add_argument(\n \"--json\",\n action=\"store_true\",\n help=\"Output as JSON\",\n )\n parser.add_argument(\n \"--create-tasks\",\n action=\"store_true\",\n help=\"Create tasks for violations\",\n )\n parser.add_argument(\n \"--blocks-only\",\n action=\"store_true\",\n help=\"Only report blocking violations\",\n )\n\n args = parser.parse_args()\n\n # Scan durchführen\n results = scan_all(args.path)\n\n # Wenn blocks-only, Warnings entfernen\n if args.blocks_only:\n for v in results[\"violations\"]:\n v[\"warnings\"] = []\n results[\"violations\"] = [\n v for v in results[\"violations\"] if v[\"blocks\"]\n ]\n results[\"total_warnings\"] = 0\n results[\"files_with_warnings\"] = 0\n\n # Tasks erstellen wenn gewünscht\n if args.create_tasks:\n created_tasks = create_tasks_for_violations(results)\n results[\"created_tasks\"] = created_tasks\n\n # Output\n if args.json:\n print(format_json(results))\n else:\n print(format_console(results))\n if args.create_tasks and results.get(\"created_tasks\"):\n print(f\"\\nCreated {len(results['created_tasks'])} tasks for violations.\")\n\n # Exit Code\n if results[\"total_blocks\"] > 0:\n sys.exit(1)\n sys.exit(0)\n\n\nif __name__ == \"__main__\":\n main()\n"
}
}
Response
{
"tool_response": {
"type": "create",
"filePath": "\/var\/www\/tools\/ki-protokoll\/claude-hook\/quality\/full_scan.py",
"content": "#!\/usr\/bin\/env python3\n\"\"\"\nFull Codebase Quality Scan.\n\nScannt alle PHP-Dateien gegen Pre- und Post-Hook Regeln.\nErstellt optional Tasks für Violations.\n\nUsage:\n full_scan.py # Scan mit Output\n full_scan.py --json # JSON-Output\n full_scan.py --create-tasks # Tasks für Violations erstellen\n full_scan.py --path \/src # Nur bestimmten Pfad scannen\n\"\"\"\n\nimport argparse\nimport json\nimport os\nimport sys\nfrom pathlib import Path\nfrom typing import Dict, List, Any\n\n# Eigene Module laden\nsys.path.insert(0, str(Path(__file__).parent))\nimport pre_rules\nimport post_rules\n\n# =============================================================================\n# CONFIGURATION\n# =============================================================================\n\nDEFAULT_SCAN_PATH = \"\/var\/www\/dev.campus.systemische-tools.de\/src\"\n\nSKIP_DIRS = [\n \"\/vendor\/\",\n \"\/node_modules\/\",\n \"\/.git\/\",\n \"\/cache\/\",\n \"\/var\/\",\n]\n\n# =============================================================================\n# SCANNER\n# =============================================================================\n\n\ndef find_php_files(base_path: str) -> List[Path]:\n \"\"\"Findet alle PHP-Dateien im Pfad.\"\"\"\n base = Path(base_path)\n if not base.exists():\n return []\n\n files = []\n for php_file in base.rglob(\"*.php\"):\n file_str = str(php_file)\n if not any(skip in file_str for skip in SKIP_DIRS):\n files.append(php_file)\n\n return sorted(files)\n\n\ndef scan_file(file_path: Path) -> Dict[str, Any]:\n \"\"\"Scannt eine einzelne Datei.\"\"\"\n try:\n content = file_path.read_text(encoding=\"utf-8\")\n except (OSError, UnicodeDecodeError) as e:\n return {\n \"file\": str(file_path),\n \"error\": str(e),\n \"blocks\": [],\n \"warnings\": [],\n }\n\n file_str = str(file_path)\n\n # Pre-Rules (Blocks)\n pre_result = pre_rules.check(file_str, content)\n blocks = []\n if not pre_result.get(\"allowed\", True):\n blocks.append(pre_result.get(\"message\", \"Unknown block\"))\n\n # Post-Rules (Warnings)\n post_result = post_rules.check(file_str, content)\n warnings = post_result.get(\"warnings\", [])\n\n return {\n \"file\": file_str,\n \"blocks\": blocks,\n \"warnings\": warnings,\n }\n\n\ndef scan_all(base_path: str) -> Dict[str, Any]:\n \"\"\"Scannt alle PHP-Dateien.\"\"\"\n files = find_php_files(base_path)\n\n results = {\n \"scan_path\": base_path,\n \"total_files\": len(files),\n \"files_with_blocks\": 0,\n \"files_with_warnings\": 0,\n \"total_blocks\": 0,\n \"total_warnings\": 0,\n \"violations\": [],\n }\n\n for file_path in files:\n file_result = scan_file(file_path)\n\n if file_result.get(\"error\"):\n results[\"violations\"].append(file_result)\n continue\n\n has_issues = False\n\n if file_result[\"blocks\"]:\n results[\"files_with_blocks\"] += 1\n results[\"total_blocks\"] += len(file_result[\"blocks\"])\n has_issues = True\n\n if file_result[\"warnings\"]:\n results[\"files_with_warnings\"] += 1\n results[\"total_warnings\"] += len(file_result[\"warnings\"])\n has_issues = True\n\n if has_issues:\n results[\"violations\"].append(file_result)\n\n return results\n\n\n# =============================================================================\n# OUTPUT FORMATTERS\n# =============================================================================\n\n\ndef format_console(results: Dict[str, Any]) -> str:\n \"\"\"Formatiert Ergebnis für Console-Output.\"\"\"\n lines = []\n lines.append(\"=\" * 70)\n lines.append(\"QUALITY SCAN REPORT\")\n lines.append(\"=\" * 70)\n lines.append(f\"Scan Path: {results['scan_path']}\")\n lines.append(f\"Total Files: {results['total_files']}\")\n lines.append(\"\")\n lines.append(f\"Files with BLOCKS: {results['files_with_blocks']}\")\n lines.append(f\"Files with WARNINGS: {results['files_with_warnings']}\")\n lines.append(f\"Total BLOCKS: {results['total_blocks']}\")\n lines.append(f\"Total WARNINGS: {results['total_warnings']}\")\n lines.append(\"\")\n\n if results[\"violations\"]:\n lines.append(\"-\" * 70)\n lines.append(\"VIOLATIONS:\")\n lines.append(\"-\" * 70)\n\n for v in results[\"violations\"]:\n # Kurzer Pfad\n short_path = v[\"file\"].replace(\"\/var\/www\/dev.campus.systemische-tools.de\/\", \"\")\n lines.append(f\"\\n{short_path}\")\n\n if v.get(\"error\"):\n lines.append(f\" ERROR: {v['error']}\")\n\n for block in v.get(\"blocks\", []):\n lines.append(f\" [BLOCK] {block}\")\n\n for warning in v.get(\"warnings\", []):\n lines.append(f\" [WARN] {warning}\")\n\n lines.append(\"\")\n lines.append(\"=\" * 70)\n\n if results[\"total_blocks\"] > 0:\n lines.append(\"STATUS: FAILED (has blocking violations)\")\n elif results[\"total_warnings\"] > 0:\n lines.append(\"STATUS: PASSED with warnings\")\n else:\n lines.append(\"STATUS: PASSED\")\n\n lines.append(\"=\" * 70)\n\n return \"\\n\".join(lines)\n\n\ndef format_json(results: Dict[str, Any]) -> str:\n \"\"\"Formatiert Ergebnis als JSON.\"\"\"\n return json.dumps(results, indent=2, ensure_ascii=False)\n\n\n# =============================================================================\n# TASK CREATION\n# =============================================================================\n\n\ndef create_tasks_for_violations(results: Dict[str, Any]) -> List[Dict[str, Any]]:\n \"\"\"Erstellt Tasks für alle Violations.\"\"\"\n try:\n import task_creator\n except ImportError:\n return [{\"error\": \"task_creator module not found\"}]\n\n created = []\n\n for v in results[\"violations\"]:\n file_path = v[\"file\"]\n\n for block in v.get(\"blocks\", []):\n # Parse Rule-ID aus Message\n rule_id = \"UNKNOWN\"\n if \"[\" in block and \"]\" in block:\n rule_id = block.split(\"[\")[1].split(\"]\")[0]\n\n try:\n task_id = task_creator.create_violation_task(\n file_path, rule_id, block, \"block\"\n )\n created.append({\n \"file\": file_path,\n \"rule\": rule_id,\n \"type\": \"block\",\n \"task_id\": task_id,\n })\n except Exception as e:\n created.append({\n \"file\": file_path,\n \"rule\": rule_id,\n \"type\": \"block\",\n \"error\": str(e),\n })\n\n for warning in v.get(\"warnings\", []):\n # Parse Rule-ID aus Warning\n rule_id = \"UNKNOWN\"\n if warning.startswith(\"W\") and \":\" in warning:\n rule_id = warning.split(\":\")[0]\n\n try:\n task_id = task_creator.create_warning_task(file_path, rule_id, warning)\n created.append({\n \"file\": file_path,\n \"rule\": rule_id,\n \"type\": \"warning\",\n \"task_id\": task_id,\n })\n except Exception as e:\n created.append({\n \"file\": file_path,\n \"rule\": rule_id,\n \"type\": \"warning\",\n \"error\": str(e),\n })\n\n return created\n\n\n# =============================================================================\n# MAIN\n# =============================================================================\n\n\ndef main():\n parser = argparse.ArgumentParser(description=\"Full Codebase Quality Scan\")\n parser.add_argument(\n \"--path\",\n default=DEFAULT_SCAN_PATH,\n help=f\"Path to scan (default: {DEFAULT_SCAN_PATH})\",\n )\n parser.add_argument(\n \"--json\",\n action=\"store_true\",\n help=\"Output as JSON\",\n )\n parser.add_argument(\n \"--create-tasks\",\n action=\"store_true\",\n help=\"Create tasks for violations\",\n )\n parser.add_argument(\n \"--blocks-only\",\n action=\"store_true\",\n help=\"Only report blocking violations\",\n )\n\n args = parser.parse_args()\n\n # Scan durchführen\n results = scan_all(args.path)\n\n # Wenn blocks-only, Warnings entfernen\n if args.blocks_only:\n for v in results[\"violations\"]:\n v[\"warnings\"] = []\n results[\"violations\"] = [\n v for v in results[\"violations\"] if v[\"blocks\"]\n ]\n results[\"total_warnings\"] = 0\n results[\"files_with_warnings\"] = 0\n\n # Tasks erstellen wenn gewünscht\n if args.create_tasks:\n created_tasks = create_tasks_for_violations(results)\n results[\"created_tasks\"] = created_tasks\n\n # Output\n if args.json:\n print(format_json(results))\n else:\n print(format_console(results))\n if args.create_tasks and results.get(\"created_tasks\"):\n print(f\"\\nCreated {len(results['created_tasks'])} tasks for violations.\")\n\n # Exit Code\n if results[\"total_blocks\"] > 0:\n sys.exit(1)\n sys.exit(0)\n\n\nif __name__ == \"__main__\":\n main()\n",
"structuredPatch": [],
"originalFile": null
}
}