feat: Enhanced analyze - shows overview, scripts, sections, better project matching

This commit is contained in:
2026-03-24 21:59:53 +01:00
parent 48a452b994
commit fc6ddbd1b2
4 changed files with 113 additions and 19 deletions
+1 -1
View File
@@ -19,7 +19,7 @@
},
"agentic-workflow-automation": {
"version": "0.1.0",
"installedAt": 1774375021538
"installedAt": 1774385419847
}
}
}
+66 -12
View File
@@ -132,6 +132,7 @@ export async function POST(req: NextRequest) {
try {
await execAsync(`rm -rf ${tempPath} 2>/dev/null; ${CLAWHUB_BIN} install ${slug} --dir ${tempPath} 2>&1`);
// Find SKILL.md
const skillMdPath = path.join(tempPath, slug, "SKILL.md");
let content = "";
if (existsSync(skillMdPath)) {
@@ -141,43 +142,96 @@ export async function POST(req: NextRequest) {
if (existsSync(altPath)) content = await readFile(altPath, "utf-8");
}
// Extract description from frontmatter
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";
// Extract overview section (everything after first ---)
const overviewMatch = content.match(/---\n([\s\S]+?)(?=\n##|\n#|$)/i);
let overview = "";
if (overviewMatch) {
overview = overviewMatch[1].trim();
// Clean up frontmatter keys
overview = overview.replace(/^[a-z]+:/gim, "").trim();
}
// Extract all ## sections
const sections: Record<string, string> = {};
const sectionMatches = content.matchAll(/##\s+(.+?)\n([\s\S]*?)(?=##\s+|$)/gi);
for (const match of sectionMatches) {
const title = match[1].trim();
const body = match[2].trim();
if (title.toLowerCase() !== "overview" && body) {
sections[title] = body.substring(0, 500);
}
}
// Get scripts info
const scriptsDir = path.join(tempPath, slug, "scripts");
let scripts: string[] = [];
if (existsSync(scriptsDir)) {
try {
const files = await readdir(scriptsDir);
scripts = files.filter(f => !f.startsWith("."));
} catch {}
}
await execAsync(`rm -rf ${tempPath} 2>/dev/null`);
// Project matching
// Project matching - more thorough analysis
const projectsDir = "/root/.openclaw/workspace/projects";
const projectMatches: string[] = [];
const projectMatches: Array<{name: string; relevance: string; why: string}> = [];
try {
const entries = await readdir(projectsDir, { withFileTypes: true });
for (const entry of entries) {
if (entry.isFile() && (entry.name.endsWith(".md") || entry.name.endsWith(".json"))) {
if (entry.isFile() && entry.name.endsWith(".md")) {
const projectPath = path.join(projectsDir, entry.name);
const projectContent = await readFile(projectPath, "utf-8");
const projectName = entry.name.replace(/\.(md|json)$/, "");
const projectName = entry.name.replace(/\.md$/, "");
const skillKeywords = (desc + " " + triggers).toLowerCase();
// Check purpose/goals
const purposeMatch = projectContent.match(/purpose:?\s*([^\n]+)/i);
const purpose = purposeMatch ? purposeMatch[1].trim() : "";
// Find keyword matches with skill content
const skillContent = (desc + " " + triggers + " " + overview).toLowerCase();
const projectKeywords = projectContent.toLowerCase();
const overlaps: string[] = [];
const skillWords = skillKeywords.split(/\s+/).filter((w: string) => w.length > 4);
for (const word of skillWords) {
if (projectKeywords.includes(word)) overlaps.push(word);
// Look for specific relevance
const relevantKeywords: string[] = [];
const keywordsToCheck = ["automation", "workflow", "ai", "agent", "service", "client", "sales", "marketing", "content", "data", "email", "task", "report", "integration", "api", "web", "voice", "chat"];
for (const kw of keywordsToCheck) {
if (skillContent.includes(kw) && projectKeywords.includes(kw)) {
relevantKeywords.push(kw);
}
}
if (overlaps.length >= 2) {
projectMatches.push(`${projectName}: ${overlaps.slice(0, 3).join(", ")}`);
if (relevantKeywords.length >= 2 || (purpose && relevantKeywords.length >= 1)) {
const why = relevantKeywords.slice(0, 4).join(", ");
projectMatches.push({
name: projectName,
relevance: `${relevantKeywords.length} keyword matches`,
why: `Useful for: ${why}`
});
}
}
}
} catch {}
return NextResponse.json({ description: desc, triggers: triggers, raw: content.substring(0, 2000), projectMatches });
return NextResponse.json({
description: desc,
triggers: triggers,
overview: overview.substring(0, 1000),
sections,
scripts,
projectMatches
});
} catch (e: any) {
return NextResponse.json({ error: e.message, description: "Could not analyze skill" });
}
+34 -6
View File
@@ -215,17 +215,45 @@ export default function ClawHubMarketplace() {
description: data.description,
triggers: data.triggers
});
let output = `📋 ${selectedSkill.name}\n\n`;
output += `Description: ${data.description || "N/A"}\n\n`;
output += `Triggers: ${data.triggers || "N/A"}\n\n`;
let output = `📋 ${selectedSkill.name}\n`;
output += `${"─".repeat(40)}\n\n`;
output += `💬 ${data.description || "N/A"}\n\n`;
output += `🎯 Triggers: ${data.triggers || "N/A"}\n\n`;
if (data.overview) {
output += `📝 Overview:\n${data.overview.substring(0, 500)}${data.overview.length > 500 ? "..." : ""}\n\n`;
}
if (data.scripts && data.scripts.length > 0) {
output += `🛠️ Scripts: ${data.scripts.join(", ")}\n\n`;
}
if (data.sections) {
const relevantSections = Object.entries(data.sections).filter(([k]) =>
!["overview", "triggers", "description", "guardrails"].includes(k.toLowerCase())
);
if (relevantSections.length > 0) {
output += `📚 Sections:\n`;
relevantSections.forEach(([title, body]) => {
output += `${title}\n`;
});
output += `\n`;
}
}
if (data.projectMatches && data.projectMatches.length > 0) {
output += `🎯 Project Matches:\n`;
data.projectMatches.forEach((m: string) => {
output += `${m}\n`;
output += `${"─".repeat(40)}\n`;
data.projectMatches.forEach((m: {name: string; relevance: string; why: string}) => {
output += `\n 📦 ${m.name.toUpperCase()}\n`;
output += ` ${m.why}\n`;
});
output += `\n`;
} else {
output += `❌ No direct project matches found\n`;
}
output += (data.raw ? `📄 SKILL.md Preview:\n${data.raw.substring(0, 500)}...` : "");
setOutput(output);
} catch (e) {
setOutput("Error: " + String(e));
+12
View File
@@ -1,4 +1,16 @@
[
{
"id": "eod-1774382402686",
"date": "2026-03-24",
"completed": [
"See Mission Control for details",
"🛡️ SECURITY: 10 advisories found today! Check MC."
],
"progress": {},
"council": {},
"tomorrow": [],
"created_at": "2026-03-24T20:00:02.686Z"
},
{
"id": "eod-1774296002482",
"date": "2026-03-23",