"use client"; import { useState, useEffect, useCallback } from "react"; import BackToMC from "@/components/mission-control/BackToMC"; interface Skill { slug: string; name: string; score: number; description?: string; } const AGENTS = ["horus", "amun", "cleo"] as const; const AGENT_LABELS: Record = { horus: "🦅 Horus (Local)", amun: "🤖 Amun", cleo: "👑 Cleo", }; export default function ClawHubMarketplace() { const [skills, setSkills] = useState([]); const [search, setSearch] = useState(""); const [loading, setLoading] = useState(false); const [selectedSkill, setSelectedSkill] = useState(null); const [selectedAgents, setSelectedAgents] = useState(["horus"]); const [action, setAction] = useState<"install" | "delete" | "sync" | "push" | null>(null); const [output, setOutput] = useState(""); const [installedSkills, setInstalledSkills] = useState>({}); const [syncing, setSyncing] = useState(false); 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 refreshPopular = useCallback(async () => { setLoading(true); try { const res = await fetch("/api/clawhub?action=popular"); const data = await res.json(); setSkills(data.skills || []); } catch (e) { console.error(e); } setLoading(false); }, []); useEffect(() => { refreshPopular(); fetchInstalled(); }, [refreshPopular, 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 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)); }; 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 && "..."}
))}
{/* Search */}
setSearch(e.target.value)} onKeyDown={(e) => e.key === "Enter" && searchSkills(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" />
{/* Skills List */}

Available Skills

{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}
                    
)}
)}
); }