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:
2026-03-24 18:43:42 +01:00
parent 5ece3001a3
commit 2ee9b22cec
2 changed files with 148 additions and 9 deletions
+67 -8
View File
@@ -8,6 +8,8 @@ interface Skill {
name: string;
score: number;
category?: string;
description?: string;
triggers?: string;
}
const AGENTS = ["horus", "amun", "cleo"] as const;
@@ -43,6 +45,7 @@ export default function ClawHubMarketplace() {
const [search, setSearch] = useState("");
const [loading, setLoading] = useState(false);
const [selectedSkill, setSelectedSkill] = useState<Skill | null>(null);
const [skillDetails, setSkillDetails] = useState<{description?: string; triggers?: string} | null>(null);
const [selectedAgents, setSelectedAgents] = useState<string[]>(["horus"]);
const [view, setView] = useState<"popular" | "categories" | "search">("popular");
const [action, setAction] = useState<"install" | "delete" | "sync" | "push" | null>(null);
@@ -200,6 +203,46 @@ export default function ClawHubMarketplace() {
setSyncing(false);
};
const handleAnalyze = async () => {
if (!selectedSkill) return;
setAction("analyze");
setOutput("Analyzing skill...\n");
try {
const res = await fetch(`/api/clawhub?action=analyze&slug=${encodeURIComponent(selectedSkill.slug)}`);
const data = await res.json();
setSkillDetails({
description: data.description,
triggers: data.triggers
});
setOutput(`📋 ${selectedSkill.name}\n\n` +
`Description: ${data.description || "N/A"}\n\n` +
`Triggers: ${data.triggers || "N/A"}\n\n` +
(data.raw ? `📄 SKILL.md Preview:\n${data.raw.substring(0, 500)}...` : ""));
} catch (e) {
setOutput("Error: " + String(e));
}
setAction(null);
};
const handleClone = async () => {
if (!selectedSkill) return;
setAction("clone");
setOutput("Creating custom version...\n");
try {
const res = await fetch("/api/clawhub", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ action: "clone", slug: selectedSkill.slug }),
});
const data = await res.json();
setOutput(data.output || data.error || "Clone complete!");
fetchInstalled();
} catch (e) {
setOutput("Error: " + String(e));
}
setAction(null);
};
const handlePush = async () => {
setAction("push");
setOutput("Pushing to GitHub...\n");
@@ -454,19 +497,35 @@ export default function ClawHubMarketplace() {
{/* Action Buttons */}
<div className="flex flex-col gap-2 mb-4">
<button
onClick={handleInstall}
disabled={action !== null || selectedAgents.length === 0}
className="bg-green-600 hover:bg-green-700 disabled:bg-green-800 disabled:cursor-not-allowed px-4 py-2 rounded-lg font-medium transition flex items-center justify-center gap-2"
onClick={handleAnalyze}
disabled={action !== null}
className="bg-blue-600 hover:bg-blue-700 disabled:bg-blue-800 px-4 py-2 rounded-lg font-medium transition flex items-center justify-center gap-2"
>
{action === "install" ? "⏳ Installing..." : `✅ Install on ${selectedAgents.length} agent(s)`}
{action === "analyze" ? "⏳ Analyzing..." : "🔍 Analyze Skill"}
</button>
<button
onClick={handleDelete}
disabled={action !== null || selectedAgents.length === 0 || !isInstalled(selectedSkill.slug)}
className="bg-red-600 hover:bg-red-700 disabled:bg-red-800 disabled:cursor-not-allowed px-4 py-2 rounded-lg font-medium transition flex items-center justify-center gap-2"
onClick={handleClone}
disabled={action !== null}
className="bg-purple-600 hover:bg-purple-700 disabled:bg-purple-800 px-4 py-2 rounded-lg font-medium transition flex items-center justify-center gap-2"
>
{action === "delete" ? "⏳ Removing..." : `🗑️ Remove from ${selectedAgents.length} agent(s)`}
{action === "clone" ? "⏳ Creating..." : "🧬 Make My Version"}
</button>
<div className="border-t border-slate-600 pt-2 mt-2">
<button
onClick={handleInstall}
disabled={action !== null || selectedAgents.length === 0}
className="w-full bg-green-600 hover:bg-green-700 disabled:bg-green-800 disabled:cursor-not-allowed px-4 py-2 rounded-lg font-medium transition flex items-center justify-center gap-2"
>
{action === "install" ? "⏳ Installing..." : `✅ Install on ${selectedAgents.length} agent(s)`}
</button>
<button
onClick={handleDelete}
disabled={action !== null || selectedAgents.length === 0 || !isInstalled(selectedSkill.slug)}
className="w-full bg-red-600 hover:bg-red-700 disabled:bg-red-800 disabled:cursor-not-allowed px-4 py-2 rounded-lg font-medium transition flex items-center justify-center gap-2 mt-2"
>
{action === "delete" ? "⏳ Removing..." : `🗑️ Remove from ${selectedAgents.length} agent(s)`}
</button>
</div>
</div>
{/* Output */}