142 lines
5.7 KiB
PHP
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']]);
|
|
}
|