Protokoll #1757

ID1757
Zeitstempel2025-12-20 19:57:25.915554
Clientroot
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
Modellclaude-sonnet-4-20250514
Statuscompleted
Tokens3,965 (Input: 0, Output: 0)
Dauer89 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": "Edit",
    "tool_input": {
        "file_path": "\/var\/www\/dev.campus.systemische-tools.de\/src\/Controller\/ContentController.php",
        "old_string": "        $scriptPath = $this->pipelinePath . '\/web_generate.py';\n\n        $cmdArgs = array_map('escapeshellarg', $args);\n        $safeCommand = escapeshellarg($command);\n        $safeEntityId = escapeshellarg((string) $entityId);\n        $cmd = \"{$this->pythonPath} {$scriptPath} {$safeCommand} {$safeEntityId} \" . implode(' ', $cmdArgs) . ' 2>&1';\n\n        $output = shell_exec($cmd);\n\n        if ($output === null) {\n            return ['error' => 'Script konnte nicht ausgeführt werden'];\n        }",
        "new_string": "        $scriptPath = $this->pipelinePath . '\/web_generate.py';\n\n        \/\/ Build command array for proc_open (safer than shell_exec)\n        $cmdArray = [\n            $this->pythonPath,\n            $scriptPath,\n            $command,\n            (string) $entityId,\n            ...$args,\n        ];\n\n        $descriptors = [\n            0 => ['pipe', 'r'],\n            1 => ['pipe', 'w'],\n            2 => ['pipe', 'w'],\n        ];\n\n        $process = proc_open($cmdArray, $descriptors, $pipes);\n\n        if (!is_resource($process)) {\n            return ['error' => 'Script konnte nicht gestartet werden'];\n        }\n\n        fclose($pipes[0]);\n        $stdout = stream_get_contents($pipes[1]);\n        $stderr = stream_get_contents($pipes[2]);\n        fclose($pipes[1]);\n        fclose($pipes[2]);\n        $exitCode = proc_close($process);\n\n        $output = $stdout . $stderr;\n\n        if ($exitCode !== 0 && $output === '') {\n            return ['error' => 'Script fehlgeschlagen (Exit: ' . $exitCode . ')'];\n        }"
    }
}

Response

{
    "tool_response": {
        "filePath": "\/var\/www\/dev.campus.systemische-tools.de\/src\/Controller\/ContentController.php",
        "oldString": "        $scriptPath = $this->pipelinePath . '\/web_generate.py';\n\n        $cmdArgs = array_map('escapeshellarg', $args);\n        $safeCommand = escapeshellarg($command);\n        $safeEntityId = escapeshellarg((string) $entityId);\n        $cmd = \"{$this->pythonPath} {$scriptPath} {$safeCommand} {$safeEntityId} \" . implode(' ', $cmdArgs) . ' 2>&1';\n\n        $output = shell_exec($cmd);\n\n        if ($output === null) {\n            return ['error' => 'Script konnte nicht ausgeführt werden'];\n        }",
        "newString": "        $scriptPath = $this->pipelinePath . '\/web_generate.py';\n\n        \/\/ Build command array for proc_open (safer than shell_exec)\n        $cmdArray = [\n            $this->pythonPath,\n            $scriptPath,\n            $command,\n            (string) $entityId,\n            ...$args,\n        ];\n\n        $descriptors = [\n            0 => ['pipe', 'r'],\n            1 => ['pipe', 'w'],\n            2 => ['pipe', 'w'],\n        ];\n\n        $process = proc_open($cmdArray, $descriptors, $pipes);\n\n        if (!is_resource($process)) {\n            return ['error' => 'Script konnte nicht gestartet werden'];\n        }\n\n        fclose($pipes[0]);\n        $stdout = stream_get_contents($pipes[1]);\n        $stderr = stream_get_contents($pipes[2]);\n        fclose($pipes[1]);\n        fclose($pipes[2]);\n        $exitCode = proc_close($process);\n\n        $output = $stdout . $stderr;\n\n        if ($exitCode !== 0 && $output === '') {\n            return ['error' => 'Script fehlgeschlagen (Exit: ' . $exitCode . ')'];\n        }",
        "originalFile": "<?php\n\nnamespace Controller;\n\nuse Framework\\Controller;\nuse Infrastructure\\Persistence\\ContentRepository;\n\nclass ContentController extends Controller\n{\n    private ContentRepository $repository;\n    private string $pipelinePath = '\/opt\/scripts\/pipeline';\n    private string $pythonPath;\n\n    public function __construct()\n    {\n        $this->repository = new ContentRepository();\n        $this->pythonPath = $this->pipelinePath . '\/venv\/bin\/python';\n    }\n\n    \/**\n     * GET \/content\n     * List all content orders\n     *\/\n    public function index(): void\n    {\n        $filters = [];\n        if (isset($_GET['status']) && $_GET['status'] !== '') {\n            $filters['status'] = $_GET['status'];\n        }\n\n        $orders = $this->repository->findAllOrders($filters);\n        $stats = $this->repository->getStatistics();\n\n        $this->view('content.index', [\n            'title' => 'Content Studio',\n            'orders' => $orders,\n            'stats' => $stats,\n            'currentStatus' => $_GET['status'] ?? '',\n        ]);\n    }\n\n    \/**\n     * GET \/content\/new\n     * Show create form\n     *\/\n    public function contentNew(): void\n    {\n        $this->view('content.new', [\n            'title' => 'Neuer Content-Auftrag',\n            'profiles' => $this->repository->findAllProfiles(),\n            'contracts' => $this->repository->findAllContracts(),\n            'structures' => $this->repository->findAllStructures(),\n        ]);\n    }\n\n    \/**\n     * POST \/content\n     * Store new order\n     *\/\n    public function store(): void\n    {\n        $this->requireCsrf();\n\n        $title = trim($_POST['title'] ?? '');\n        $briefing = trim($_POST['briefing'] ?? '');\n\n        if ($title === '' || $briefing === '') {\n            $_SESSION['error'] = 'Titel und Briefing sind erforderlich.';\n            header('Location: \/content\/new');\n            exit;\n        }\n\n        \/\/ Auto-apply first active contract if none selected\n        $contractId = $_POST['contract_id'] ?? null;\n        if ($contractId === null || $contractId === '') {\n            $contracts = $this->repository->findAllContracts();\n            if ($contracts !== []) {\n                $contractId = $contracts[0]['id'];\n            }\n        }\n\n        $orderId = $this->repository->createOrder([\n            'title' => $title,\n            'briefing' => $briefing,\n            'author_profile_id' => $_POST['author_profile_id'] ?? null,\n            'contract_id' => $contractId,\n            'structure_id' => $_POST['structure_id'] ?? null,\n        ]);\n\n        header('Location: \/content\/' . $orderId);\n        exit;\n    }\n\n    \/**\n     * GET \/content\/{id}\n     * Show order details\n     *\/\n    public function show(int $id): void\n    {\n        $order = $this->repository->findOrder($id);\n\n        if ($order === null) {\n            http_response_code(404);\n            echo '404 - Auftrag nicht gefunden';\n\n            return;\n        }\n\n        $versions = $this->repository->findVersionsByOrder($id);\n        $latestVersion = $versions[0] ?? null;\n        $critiques = $latestVersion ? $this->repository->findCritiquesByVersion($latestVersion['id']) : [];\n        $sources = $this->repository->findSourcesByOrder($id);\n\n        $this->view('content.show', [\n            'title' => $order['title'],\n            'order' => $order,\n            'versions' => $versions,\n            'latestVersion' => $latestVersion,\n            'critiques' => $critiques,\n            'sources' => $sources,\n        ]);\n    }\n\n    \/**\n     * GET \/content\/{id}\/edit\n     * Show edit form\n     *\/\n    public function edit(int $id): void\n    {\n        $order = $this->repository->findOrder($id);\n\n        if ($order === null) {\n            http_response_code(404);\n            echo '404 - Auftrag nicht gefunden';\n\n            return;\n        }\n\n        $this->view('content.edit', [\n            'title' => 'Auftrag bearbeiten',\n            'order' => $order,\n            'profiles' => $this->repository->findAllProfiles(),\n            'contracts' => $this->repository->findAllContracts(),\n            'structures' => $this->repository->findAllStructures(),\n        ]);\n    }\n\n    \/**\n     * POST \/content\/{id}\/generate\n     * Generate content (HTMX)\n     *\/\n    public function generate(int $id): void\n    {\n        $this->requireCsrf();\n\n        $model = $_POST['model'] ?? 'claude-opus-4-5-20251101';\n        $collection = $_POST['collection'] ?? 'documents';\n        $limit = (int) ($_POST['context_limit'] ?? 5);\n\n        $result = $this->callPython('generate', $id, [$model, $collection, $limit]);\n\n        if (isset($result['error'])) {\n            echo '<div class=\"alert error\">Fehler: ' . htmlspecialchars($result['error']) . '<\/div>';\n\n            return;\n        }\n\n        \/\/ Return updated content section\n        $this->renderVersionPartial($result);\n    }\n\n    \/**\n     * POST \/content\/{id}\/critique\n     * Run critique round (HTMX)\n     *\/\n    public function critique(int $id): void\n    {\n        $this->requireCsrf();\n\n        \/\/ Get latest version\n        $version = $this->repository->findLatestVersion($id);\n\n        if ($version === null) {\n            echo '<div class=\"alert error\">Keine Version vorhanden.<\/div>';\n\n            return;\n        }\n\n        $model = $_POST['model'] ?? 'claude-opus-4-5-20251101';\n        $result = $this->callPython('critique', $version['id'], [$model]);\n\n        if (isset($result['error'])) {\n            echo '<div class=\"alert error\">Fehler: ' . htmlspecialchars($result['error']) . '<\/div>';\n\n            return;\n        }\n\n        \/\/ Return critique results\n        $this->renderCritiquePartial($result);\n    }\n\n    \/**\n     * POST \/content\/{id}\/revise\n     * Create revision (HTMX)\n     *\/\n    public function revise(int $id): void\n    {\n        $this->requireCsrf();\n\n        $version = $this->repository->findLatestVersion($id);\n\n        if ($version === null) {\n            echo '<div class=\"alert error\">Keine Version vorhanden.<\/div>';\n\n            return;\n        }\n\n        $model = $_POST['model'] ?? 'claude-opus-4-5-20251101';\n        $result = $this->callPython('revise', $version['id'], [$model]);\n\n        if (isset($result['error'])) {\n            echo '<div class=\"alert error\">Fehler: ' . htmlspecialchars($result['error']) . '<\/div>';\n\n            return;\n        }\n\n        $this->renderVersionPartial($result);\n    }\n\n    \/**\n     * POST \/content\/{id}\/approve\n     * Approve content\n     *\/\n    public function approve(int $id): void\n    {\n        $this->requireCsrf();\n\n        $this->repository->updateOrderStatus($id, 'approve');\n        echo '<div class=\"alert success\">Content genehmigt!<\/div>';\n        echo '<script>setTimeout(() => window.location.reload(), 1000);<\/script>';\n    }\n\n    \/**\n     * POST \/content\/{id}\/decline\n     * Decline content\n     *\/\n    public function decline(int $id): void\n    {\n        $this->requireCsrf();\n\n        $this->repository->updateOrderStatus($id, 'draft');\n        echo '<div class=\"alert warning\">Content abgelehnt. Zurück zu Entwurf.<\/div>';\n        echo '<script>setTimeout(() => window.location.reload(), 1000);<\/script>';\n    }\n\n    \/**\n     * Allowed Python commands (whitelist).\n     *\/\n    private const ALLOWED_COMMANDS = ['generate', 'critique', 'revise'];\n\n    \/**\n     * Call Python script\n     *\/\n    private function callPython(string $command, int $entityId, array $args = []): array\n    {\n        \/\/ Validate command against whitelist\n        if (!in_array($command, self::ALLOWED_COMMANDS, true)) {\n            return ['error' => 'Ungültiger Command: ' . $command];\n        }\n\n        $scriptPath = $this->pipelinePath . '\/web_generate.py';\n\n        $cmdArgs = array_map('escapeshellarg', $args);\n        $safeCommand = escapeshellarg($command);\n        $safeEntityId = escapeshellarg((string) $entityId);\n        $cmd = \"{$this->pythonPath} {$scriptPath} {$safeCommand} {$safeEntityId} \" . implode(' ', $cmdArgs) . ' 2>&1';\n\n        $output = shell_exec($cmd);\n\n        if ($output === null) {\n            return ['error' => 'Script konnte nicht ausgeführt werden'];\n        }\n\n        if (preg_match('\/\\{[\\s\\S]*\\}\/', $output, $matches)) {\n            $result = json_decode($matches[0], true);\n            if (json_last_error() === JSON_ERROR_NONE) {\n                return $result;\n            }\n        }\n\n        return ['error' => 'Ungültige Antwort: ' . substr($output, 0, 500)];\n    }\n\n    \/**\n     * Render version partial\n     *\/\n    private function renderVersionPartial(array $result): void\n    {\n        $content = $result['content'] ?? '';\n        $sources = $result['sources'] ?? [];\n\n        echo '<div class=\"version-content\">';\n        echo '<div class=\"version-header\">';\n        echo '<span class=\"version-number\">Version ' . ($result['version_number'] ?? '?') . '<\/span>';\n        echo '<span class=\"badge success\">Generiert<\/span>';\n        echo '<\/div>';\n        echo '<div class=\"content-text\">' . nl2br(htmlspecialchars($content)) . '<\/div>';\n\n        if (count($sources) > 0) {\n            echo '<div class=\"sources\">';\n            echo '<strong>Quellen:<\/strong><ul>';\n            foreach ($sources as $src) {\n                $score = round(($src['score'] ?? 0) * 100);\n                echo '<li>' . htmlspecialchars($src['source'] ?? '') . ' (' . $score . '%)<\/li>';\n            }\n            echo '<\/ul><\/div>';\n        }\n\n        echo '<\/div>';\n    }\n\n    \/**\n     * Render critique partial\n     *\/\n    private function renderCritiquePartial(array $result): void\n    {\n        $critiques = $result['critiques'] ?? [];\n        $allPassed = $result['all_passed'] ?? false;\n\n        echo '<div class=\"critique-results\">';\n        echo '<div class=\"critique-header\">';\n        echo '<span>Kritik-Runde ' . ($result['round'] ?? '?') . '<\/span>';\n        echo $allPassed\n            ? '<span class=\"badge success\">Bestanden<\/span>'\n            : '<span class=\"badge warning\">Revision nötig<\/span>';\n        echo '<\/div>';\n\n        foreach ($critiques as $critiqu... [TRUNCATED-aaba0b977b0b0f46]",
        "structuredPatch": [
            {
                "oldStart": 270,
                "oldLines": 17,
                "newStart": 270,
                "newLines": 40,
                "lines": [
                    " ",
                    "         $scriptPath = $this->pipelinePath . '\/web_generate.py';",
                    " ",
                    "-        $cmdArgs = array_map('escapeshellarg', $args);",
                    "-        $safeCommand = escapeshellarg($command);",
                    "-        $safeEntityId = escapeshellarg((string) $entityId);",
                    "-        $cmd = \"{$this->pythonPath} {$scriptPath} {$safeCommand} {$safeEntityId} \" . implode(' ', $cmdArgs) . ' 2>&1';",
                    "+        \/\/ Build command array for proc_open (safer than shell_exec)",
                    "+        $cmdArray = [",
                    "+            $this->pythonPath,",
                    "+            $scriptPath,",
                    "+            $command,",
                    "+            (string) $entityId,",
                    "+            ...$args,",
                    "+        ];",
                    " ",
                    "-        $output = shell_exec($cmd);",
                    "+        $descriptors = [",
                    "+            0 => ['pipe', 'r'],",
                    "+            1 => ['pipe', 'w'],",
                    "+            2 => ['pipe', 'w'],",
                    "+        ];",
                    " ",
                    "-        if ($output === null) {",
                    "-            return ['error' => 'Script konnte nicht ausgeführt werden'];",
                    "+        $process = proc_open($cmdArray, $descriptors, $pipes);",
                    "+",
                    "+        if (!is_resource($process)) {",
                    "+            return ['error' => 'Script konnte nicht gestartet werden'];",
                    "         }",
                    " ",
                    "+        fclose($pipes[0]);",
                    "+        $stdout = stream_get_contents($pipes[1]);",
                    "+        $stderr = stream_get_contents($pipes[2]);",
                    "+        fclose($pipes[1]);",
                    "+        fclose($pipes[2]);",
                    "+        $exitCode = proc_close($process);",
                    "+",
                    "+        $output = $stdout . $stderr;",
                    "+",
                    "+        if ($exitCode !== 0 && $output === '') {",
                    "+            return ['error' => 'Script fehlgeschlagen (Exit: ' . $exitCode . ')'];",
                    "+        }",
                    "+",
                    "         if (preg_match('\/\\{[\\s\\S]*\\}\/', $output, $matches)) {",
                    "             $result = json_decode($matches[0], true);",
                    "             if (json_last_error() === JSON_ERROR_NONE) {"
                ]
            }
        ],
        "userModified": false,
        "replaceAll": false
    }
}
← Vorheriger Zur Liste Nächster →