$dir, 'name' => $m[1] ?? $dir, 'size' => strlen($content), 'has_code' => strpos($content, '```python') !== false ]; } // Also scan other dirs foreach (glob("/opt/deer-flow/skills/*/SKILL.md") as $f) { $dir = basename(dirname($f)); if (in_array($dir, ['weval','public'])) continue; $content = file_get_contents($f); preg_match('/^# (.+)/m', $content, $m); $skills[] = ['id' => $dir, 'name' => $m[1] ?? $dir, 'size' => strlen($content), 'source' => 'core']; } // Public skills foreach (glob("/opt/deer-flow/skills/public/*/SKILL.md") as $f) { $dir = basename(dirname($f)); $content = file_get_contents($f); preg_match('/^# (.+)/m', $content, $m); $skills[] = ['id' => $dir, 'name' => $m[1] ?? $dir, 'size' => strlen($content), 'source' => 'public']; } echo json_encode(['ok' => true, 'count' => count($skills), 'skills' => $skills]); break; case 'search': $q = strtolower($_GET['q'] ?? ''); if (!$q) { echo json_encode(['error' => 'missing q']); break; } $results = []; foreach (glob("/opt/deer-flow/skills/{weval,public,aegis,aios,skillsmith}/*/SKILL.md", GLOB_BRACE) as $f) { $content = file_get_contents($f); if (stripos($content, $q) !== false) { $dir = basename(dirname($f)); preg_match('/^# (.+)/m', $content, $m); $results[] = ['id' => $dir, 'name' => $m[1] ?? $dir, 'match' => substr($content, max(0, stripos($content, $q)-50), 150)]; } } echo json_encode(['ok' => true, 'query' => $q, 'results' => $results]); break; case 'get': $id = preg_replace('/[^a-z0-9_-]/', '', $_GET['id'] ?? ''); $found = false; foreach (["/opt/deer-flow/skills/weval/$id/SKILL.md", "/opt/deer-flow/skills/public/$id/SKILL.md", "/opt/deer-flow/skills/$id/SKILL.md"] as $path) { if (file_exists($path)) { echo json_encode(['ok' => true, 'id' => $id, 'content' => file_get_contents($path)]); $found = true; break; } } if (!$found) echo json_encode(['error' => 'not found', 'id' => $id]); break; case 'create': $name = trim($_POST['name'] ?? ''); $desc = trim($_POST['description'] ?? ''); $triggers = trim($_POST['triggers'] ?? ''); $code = trim($_POST['code'] ?? ''); if (!$name) { echo json_encode(['error' => 'missing name']); break; } $id = preg_replace('/[^a-z0-9-]/', '-', strtolower($name)); $id = preg_replace('/-+/', '-', trim($id, '-')); $dir = "$SKILLS_DIR/$id"; if (is_dir($dir)) { echo json_encode(['error' => 'skill already exists', 'id' => $id]); break; } @mkdir($dir, 0755, true); $md = "# $name\n\n## Description\n$desc\n"; if ($triggers) { $md .= "\n## Triggers\n"; foreach (explode("\n", $triggers) as $t) { $t = trim($t); if ($t) $md .= "- \"$t\"\n"; } } if ($code) { $md .= "\n## Execution\n```python\n$code\n```\n"; } $md .= "\n## Created\n- Date: " . date('Y-m-d H:i') . "\n- Source: WEVAL Skill Factory\n"; file_put_contents("$dir/SKILL.md", $md); // Also create executable if code provided if ($code) { file_put_contents("$dir/run.py", "#!/usr/bin/env python3\n$code\n\nif __name__=='__main__':\n import sys,json\n print(json.dumps(execute(*sys.argv[1:])))\n"); chmod("$dir/run.py", 0755); } echo json_encode(['ok' => true, 'id' => $id, 'path' => "$dir/SKILL.md", 'has_code' => !empty($code)]); break; case 'delete': $id = preg_replace('/[^a-z0-9_-]/', '', $_POST['id'] ?? ''); $dir = "$SKILLS_DIR/$id"; if (is_dir($dir)) { array_map('unlink', glob("$dir/*")); rmdir($dir); echo json_encode(['ok' => true, 'deleted' => $id]); } else { echo json_encode(['error' => 'not found']); } break; case 'stats': $total = 0; $with_code = 0; $categories = []; foreach (glob("/opt/deer-flow/skills/{weval,public,aegis,aios,skillsmith}/*/SKILL.md", GLOB_BRACE) as $f) { $total++; $c = file_get_contents($f); if (strpos($c, '```python') !== false) $with_code++; $parent = basename(dirname(dirname($f))); $categories[$parent] = ($categories[$parent] ?? 0) + 1; } echo json_encode(['ok' => true, 'total' => $total, 'with_code' => $with_code, 'categories' => $categories]); break; default: echo json_encode(['error' => 'unknown action', 'actions' => ['list','search','get','create','delete','stats']]); }