Files
html/api/skill-factory.php
2026-04-12 22:57:03 +02:00

142 lines
5.7 KiB
PHP

<?php
/**
* WEVAL Skill Factory — Create, list, search skills for DeerFlow
* POST: action=create&name=X&description=Y&triggers=Z&code=W
* GET: action=list|search|get&q=X
*/
header('Content-Type: application/json');
header('Access-Control-Allow-Origin: *');
$SKILLS_DIR = '/opt/deer-flow/skills/weval';
if (!is_dir($SKILLS_DIR)) @mkdir($SKILLS_DIR, 0755, true);
$action = $_GET['action'] ?? $_POST['action'] ?? 'list';
switch ($action) {
case 'list':
$skills = [];
foreach (glob("$SKILLS_DIR/*/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),
'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']]);
}