import { useState, useEffect, useRef } from "react"; import { t } from "../../services/core/i18n"; import { fileServerService } from "../../services/integrations/fileServer"; import { LOCAL_HOST_URL, DEFAULT_FILE_SERVER_PORT } from "@shared/constants"; interface SkillsSyncProps { isOpen: boolean; onClose: () => void; } function SkillsSync({ isOpen, onClose }: SkillsSyncProps) { const [baseUrl, setBaseUrl] = useState( `${LOCAL_HOST_URL}:${DEFAULT_FILE_SERVER_PORT}`, ); const [connected, setConnected] = useState(false); const [checking, setChecking] = useState(false); const [uploading, setUploading] = useState(false); const [message, setMessage] = useState(""); const [logs, setLogs] = useState([]); const fileInputRef = useRef(null); useEffect(() => { if (isOpen) { loadConfig(); } }, [isOpen]); const loadConfig = async () => { await fileServerService.loadConfig(); const config = fileServerService.getConfig(); setBaseUrl(config.baseUrl); checkConnection(); }; const saveConfig = async () => { fileServerService.setConfig({ baseUrl }); await fileServerService.saveConfig(); setMessage(t("Claw.SkillsSync.configSaved")); setTimeout(() => setMessage(""), 2000); }; const checkConnection = async () => { setChecking(true); const isConnected = await fileServerService.checkConnection(); setConnected(isConnected); setChecking(false); }; const handleUpload = async () => { const file = fileInputRef.current?.files?.[0]; if (!file) { setMessage(t("Claw.SkillsSync.selectZipFile")); return; } if (!file.name.endsWith(".zip")) { setMessage(t("Claw.SkillsSync.onlyZipSupported")); return; } setUploading(true); setMessage(""); setLogs([]); try { // Generate unique IDs const userId = "local-user"; const cId = crypto.randomUUID(); addLog(t("Claw.SkillsSync.creatingWorkspaceAndSyncing")); addLog(`User ID: ${userId}`); addLog(`Session ID: ${cId}`); addLog(`File: ${file.name}`); const result = await fileServerService.createWorkspace(userId, cId, file); addLog(`✓ ${t("Claw.SkillsSync.workspaceCreatedSuccess")}`); addLog(`Message: ${result.message}`); setMessage(t("Claw.SkillsSync.syncSuccess")); } catch (error) { addLog(`✗ ${t("Claw.SkillsSync.errorPrefix", { 0: String(error) })}`); setMessage(t("Claw.SkillsSync.errorPrefix", { 0: String(error) })); } finally { setUploading(false); } }; const addLog = (text: string) => { const timestamp = new Date().toLocaleTimeString(); setLogs((prev) => [...prev, `[${timestamp}] ${text}`]); }; const handleFileChange = (e: React.ChangeEvent) => { const file = e.target.files?.[0]; if (file) { setMessage( t("Claw.SkillsSync.fileSelected", { 0: file.name, 1: (file.size / 1024).toFixed(1), }), ); } }; if (!isOpen) return null; return (
e.stopPropagation()} >

{t("Claw.SkillsSync.title")}

{t("Claw.SkillsSync.fileServiceConnection")}

setBaseUrl(e.target.value)} placeholder={`${LOCAL_HOST_URL}:${DEFAULT_FILE_SERVER_PORT}`} />

{t("Claw.SkillsSync.uploadSkillPackage")}

{logs.length > 0 && (

{t("Claw.SkillsSync.logs")}

{logs.map((log, i) => (
{log}
))}
)} {message && (
{message}
)}
); } export default SkillsSync;