feat: Add analyze and Make My Version buttons
- Analyze shows skill description and preview - Make My Version creates custom skill without installing from ClawHub
This commit is contained in:
@@ -1,7 +1,8 @@
|
||||
import { NextRequest, NextResponse } from "next/server";
|
||||
import { exec } from "child_process";
|
||||
import { promisify } from "util";
|
||||
import { existsSync } from "fs";
|
||||
import { existsSync, readFileSync } from "fs";
|
||||
import { readFile, writeFile } from "fs/promises";
|
||||
import path from "path";
|
||||
|
||||
const execAsync = promisify(exec);
|
||||
@@ -82,6 +83,85 @@ export async function GET(req: NextRequest) {
|
||||
return NextResponse.json({ info: stdout });
|
||||
}
|
||||
|
||||
if (action === "analyze") {
|
||||
try {
|
||||
// Install to temp for analysis
|
||||
const tempPath = `/tmp/clawhub-analyze-${slug}`;
|
||||
await execAsync(`rm -rf ${tempPath} 2>/dev/null; ${CLAWHUB_BIN} install ${slug} --dir ${tempPath} 2>&1`);
|
||||
|
||||
// Read SKILL.md
|
||||
const skillMdPath = path.join(tempPath, slug, "SKILL.md");
|
||||
let content = "";
|
||||
if (existsSync(skillMdPath)) {
|
||||
content = await readFile(skillMdPath, "utf-8");
|
||||
} else {
|
||||
// Try without slug subfolder
|
||||
const altPath = path.join(tempPath, "SKILL.md");
|
||||
if (existsSync(altPath)) {
|
||||
content = await readFile(altPath, "utf-8");
|
||||
}
|
||||
}
|
||||
|
||||
// Extract description
|
||||
const descMatch = content.match(/description:\s*([^\n]+)/i);
|
||||
const desc = descMatch ? descMatch[1].trim() : "No description available";
|
||||
|
||||
// Extract triggers
|
||||
const triggerMatch = content.match(/triggers?:\s*([^\n]+)/i);
|
||||
const triggers = triggerMatch ? triggerMatch[1].trim() : "General use";
|
||||
|
||||
// Clean up
|
||||
await execAsync(`rm -rf ${tempPath} 2>/dev/null`);
|
||||
|
||||
return NextResponse.json({
|
||||
description: desc,
|
||||
triggers: triggers,
|
||||
raw: content.substring(0, 2000)
|
||||
});
|
||||
} catch (e: any) {
|
||||
return NextResponse.json({ error: e.message, description: "Could not analyze skill" });
|
||||
}
|
||||
}
|
||||
|
||||
if (action === "clone") {
|
||||
try {
|
||||
// Install to temp
|
||||
const tempPath = `/tmp/clawhub-clone-${slug}`;
|
||||
await execAsync(`rm -rf ${tempPath} 2>/dev/null; ${CLAWHUB_BIN} install ${slug} --dir ${tempPath} 2>&1`);
|
||||
|
||||
// Find the skill folder
|
||||
const entries = await readdir(tempPath);
|
||||
const skillFolder = entries.find(e => e.includes(slug.replace(/-/g, '')));
|
||||
const sourcePath = path.join(tempPath, skillFolder || slug);
|
||||
|
||||
// Create custom version
|
||||
const customSlug = `${slug}-custom`;
|
||||
const destPath = path.join(SKILLS_BASE, "horus", customSlug);
|
||||
|
||||
// Copy files
|
||||
await execAsync(`cp -r ${sourcePath} ${destPath} 2>&1`);
|
||||
|
||||
// Modify SKILL.md
|
||||
const skillMdPath = path.join(destPath, "SKILL.md");
|
||||
if (existsSync(skillMdPath)) {
|
||||
let content = await readFile(skillMdPath, "utf-8");
|
||||
content = content
|
||||
.replace(/name:\s*([^\n]+)/i, `name: $1 (Custom)`)
|
||||
.replace(/description:\s*([^\n]+)/i, `description: Custom version for Haitham's workflow`);
|
||||
await writeFile(skillMdPath, content);
|
||||
}
|
||||
|
||||
// Clean up
|
||||
await execAsync(`rm -rf ${tempPath} 2>/dev/null`);
|
||||
|
||||
return NextResponse.json({
|
||||
output: `Created custom skill: ${customSlug}\nPath: ${destPath}\n\nEdit SKILL.md to customize further!`
|
||||
});
|
||||
} catch (e: any) {
|
||||
return NextResponse.json({ error: e.message });
|
||||
}
|
||||
}
|
||||
|
||||
if (action === "sync") {
|
||||
try {
|
||||
const { stdout, stderr } = await execAsync(`cd ${SKILLS_BASE} && git pull origin main 2>&1`);
|
||||
|
||||
Reference in New Issue
Block a user