"use client"; import { useState, useEffect, useCallback } from "react"; import BackToMC from "@/components/mission-control/BackToMC"; interface Skill { slug: string; name: string; score: number; category?: string; description?: string; triggers?: string; } const AGENTS = ["horus", "amun", "cleo"] as const; const AGENT_LABELS: Record = { horus: "🦅 Horus (Local)", amun: "🤖 Amun", cleo: "👑 Cleo", }; const CATEGORIES = [ { id: "productivity", name: "⚡ Productivity", icon: "⚡" }, { id: "automation", name: "🤖 Automation", icon: "🤖" }, { id: "ai", name: "🧠 AI", icon: "🧠" }, { id: "writing", name: "✍️ Writing", icon: "✍️" }, { id: "research", name: "🔬 Research", icon: "🔬" }, { id: "coding", name: "💻 Coding", icon: "💻" }, { id: "business", name: "💼 Business", icon: "💼" }, ]; const CATEGORY_QUERIES: Record = { productivity: "productivity focus work", automation: "automation workflow", ai: "artificial intelligence machine learning", writing: "writing content copy", research: "research data analysis", coding: "code programming developer", business: "business sales marketing", }; export default function ClawHubMarketplace() { const [skills, setSkills] = useState([]); const [categorySkills, setCategorySkills] = useState>({}); const [search, setSearch] = useState(""); const [loading, setLoading] = useState(false); const [selectedSkill, setSelectedSkill] = useState(null); const [skillDetails, setSkillDetails] = useState<{description?: string; triggers?: string} | null>(null); const [selectedAgents, setSelectedAgents] = useState(["horus"]); const [view, setView] = useState<"popular" | "categories" | "search">("popular"); const [categoryView, setCategoryView] = useState(null); const [action, setAction] = useState<"install" | "delete" | "sync" | "push" | null>(null); const [output, setOutput] = useState(""); const [installedSkills, setInstalledSkills] = useState>({}); const [syncing, setSyncing] = useState(false); const [selectedCategory, setSelectedCategory] = useState(null); const fetchInstalled = useCallback(async () => { try { const res = await fetch("/api/clawhub?action=list"); const data = await res.json(); setInstalledSkills(data.installed || {}); } catch (e) { console.error(e); } }, []); const searchSkills = useCallback(async (query: string) => { setLoading(true); try { const res = await fetch(`/api/clawhub?action=search&q=${encodeURIComponent(query)}`); const data = await res.json(); setSkills(data.skills || []); } catch (e) { console.error(e); } setLoading(false); }, []); const fetchAllCategories = useCallback(async () => { setLoading(true); const results: Record = {}; for (const cat of CATEGORIES) { try { const res = await fetch(`/api/clawhub?action=search&q=${encodeURIComponent(CATEGORY_QUERIES[cat.id])}`); const data = await res.json(); results[cat.id] = (data.skills || []).slice(0, 5); // Top 5 per category } catch (e) { results[cat.id] = []; } } setCategorySkills(results); setLoading(false); }, []); const refreshPopular = useCallback(async () => { setLoading(true); setView("popular"); // Get top skills from all categories combined const allSkills: Skill[] = []; const seen = new Set(); for (const cat of CATEGORIES) { try { const res = await fetch(`/api/clawhub?action=search&q=${encodeURIComponent(CATEGORY_QUERIES[cat.id])}`); const data = await res.json(); for (const skill of data.skills || []) { if (!seen.has(skill.slug)) { seen.add(skill.slug); allSkills.push({ ...skill, category: cat.id }); } } } catch {} } // Sort by score and take top 30 allSkills.sort((a, b) => b.score - a.score); setSkills(allSkills.slice(0, 30)); setLoading(false); }, []); useEffect(() => { if (view === "popular") { refreshPopular(); } else if (view === "categories") { fetchAllCategories(); } fetchInstalled(); }, [view, refreshPopular, fetchAllCategories, fetchInstalled]); const toggleAgent = (agent: string) => { setSelectedAgents((prev) => prev.includes(agent) ? prev.filter((a) => a !== agent) : [...prev, agent] ); }; const selectAll = () => setSelectedAgents([...AGENTS]); const handleInstall = async () => { if (!selectedSkill || selectedAgents.length === 0) return; setAction("install"); setOutput("Installing...\n"); try { const res = await fetch("/api/clawhub", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ action: "install", slug: selectedSkill.slug, agents: selectedAgents, }), }); const data = await res.json(); setOutput(data.output || data.error || "Done"); fetchInstalled(); } catch (e) { setOutput("Error: " + String(e)); } setAction(null); }; const handleDelete = async () => { if (!selectedSkill || selectedAgents.length === 0) return; setAction("delete"); setOutput("Removing...\n"); try { const res = await fetch("/api/clawhub", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ action: "delete", slug: selectedSkill.slug, agents: selectedAgents, }), }); const data = await res.json(); setOutput(data.output || data.error || "Done"); fetchInstalled(); } catch (e) { setOutput("Error: " + String(e)); } setAction(null); }; const handleSync = async () => { setSyncing(true); setAction("sync"); setOutput("Syncing with GitHub...\n"); try { const res = await fetch("/api/clawhub", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ action: "sync" }), }); const data = await res.json(); setOutput(data.output || data.error || "Sync complete"); fetchInstalled(); } catch (e) { setOutput("Error: " + String(e)); } setAction(null); 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 }); 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`; 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`; } setOutput(output); } 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"); try { const res = await fetch("/api/clawhub", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ action: "push" }), }); const data = await res.json(); setOutput(data.output || data.error || "Push complete"); } catch (e) { setOutput("Error: " + String(e)); } setAction(null); }; const isInstalled = (slug: string) => { return AGENTS.some((agent) => installedSkills[agent]?.includes(slug)); }; const getCategoryName = (catId: string) => { return CATEGORIES.find((c) => c.id === catId)?.name || catId; }; return (

🛒 ClawHub Marketplace

Search, install, and manage skills across all agents

{/* Agent Status Bar */}

Agent Skills Status

{AGENTS.map((agent) => (
{AGENT_LABELS[agent]}
{installedSkills[agent]?.length || 0} skills installed
{installedSkills[agent]?.slice(0, 3).join(", ") || "None"} {installedSkills[agent]?.length > 3 && "..."}
))}
{/* View Toggle */}
{/* Search */}
setSearch(e.target.value)} onKeyDown={(e) => { if (e.key === "Enter") { searchSkills(search); setView("search"); } }} placeholder="Search skills..." className="flex-1 bg-slate-800 border border-slate-700 rounded-lg px-4 py-2 text-white placeholder-slate-400 focus:outline-none focus:border-blue-500" />
{/* Categories View */} {view === "categories" && !categoryView && (
{CATEGORIES.map((cat) => ( ))}
)} {view === "categories" && categoryView && (
{CATEGORIES.find(c => c.id === categoryView)?.icon}

{CATEGORIES.find(c => c.id === categoryView)?.name}

)} {/* Popular/Search/Category View */} {(view === "popular" || view === "search" || (view === "categories" && categoryView)) && (
{/* Skills List */}

{view === "popular" ? "🔥 Popular Skills" : view === "categories" ? CATEGORIES.find(c => c.id === categoryView)?.name || "Category" : "Search Results"}

{skills.length} skills found

{loading ? (
Loading...
) : skills.length === 0 ? (
No skills found
) : ( skills.map((skill) => { const installed = isInstalled(skill.slug); return ( ); }) )}
{/* Detail Panel */}

{selectedSkill ? selectedSkill.name : "Select a Skill"}

{selectedSkill && (

@{selectedSkill.slug}

)}
{!selectedSkill ? (
Click a skill to see details
) : (
{/* Agent Selector */}

Install On:

{AGENTS.map((agent) => ( ))}
{/* Action Buttons */}
{/* Output */} {output && (

Output

                        {output}
                      
)}
)}
)}
); }