import { useState, useCallback } from "react"; import { FolderSimple, GithubLogo, Globe, Link, } from "../ui/icons"; import { Modal, ActionButton, Input } from "../ui"; import { useAppStore } from "../../state/store"; type TabId = "github" | "local" | "url" | "skills_sh"; const tabs: { id: TabId; label: string; icon: typeof GithubLogo }[] = [ { id: "github", label: "GitHub", icon: GithubLogo }, { id: "local", label: "Local Path", icon: FolderSimple }, { id: "url", label: "HTTP URL", icon: Link }, { id: "skills_sh", label: "skills.sh", icon: Globe }, ]; function isValidGithubSource(value: string): boolean { return /^(https:\/\/github\.com\/[\w.-]+\/[\w.-]+|[\w.-]+\/[\w.-]+)/.test(value.trim()); } function isValidUrl(value: string): boolean { try { const url = new URL(value.trim()); return url.protocol === "https:" || url.protocol === "http:"; } catch { return false; } } export function SkillImportModal({ open, onClose, companyId, onImported, }: { open: boolean; onClose: () => void; companyId: string; onImported: () => void; }) { const addToast = useAppStore((s) => s.addToast); const [activeTab, setActiveTab] = useState("github"); const [source, setSource] = useState(""); const [isImporting, setIsImporting] = useState(false); const resetForm = useCallback(() => { setSource(""); setActiveTab("github"); setIsImporting(false); }, []); const handleClose = useCallback(() => { resetForm(); onClose(); }, [onClose, resetForm]); const handleBrowse = useCallback(async () => { const result = await window.agentCompany.pickDirectory(); if (result.ok && result.data) { setSource(result.data); } }, []); const canImport = (() => { const trimmed = source.trim(); if (!trimmed) return false; switch (activeTab) { case "github": return isValidGithubSource(trimmed); case "url": return isValidUrl(trimmed); case "local": return trimmed.length > 0; case "skills_sh": return trimmed.length > 0; default: return false; } })(); const handleImport = useCallback(async () => { const trimmed = source.trim(); if (!trimmed) return; setIsImporting(true); try { const result = await window.agentCompany.importSkill(companyId, trimmed); if (result.ok) { const count = result.data.length; addToast(`Imported ${count} skill${count !== 1 ? "s" : ""} successfully`); onImported(); handleClose(); } else { addToast(result.error.message, "danger"); } } catch (error) { addToast(error instanceof Error ? error.message : "Import failed", "danger"); } finally { setIsImporting(false); } }, [source, companyId, addToast, onImported, handleClose]); const placeholder: Record = { github: "https://github.com/owner/repo or owner/repo", local: "Enter or browse local path", url: "https://example.com/path/to/skill", skills_sh: "skills.sh install command or URL", }; return (
{/* Tab bar */}
{tabs.map((tab) => { const Icon = tab.icon; const isActive = activeTab === tab.id; return ( ); })}
{/* Tab content */}
{activeTab === "local" ? (
void handleBrowse()} />
) : ( )} {activeTab === "skills_sh" && (

Enter a skills.sh install command (e.g., npx skills.sh install skill-name) or a direct skills.sh URL.

)}
{/* Actions */}
void handleImport()} loading={isImporting} disabled={!canImport} />
); }