import { useState, type ReactNode } from 'react'; import { useTranslation } from 'react-i18next'; import { Activity, BarChart3, BookOpen, Clock, Download, ExternalLink, GitBranch, Loader2, RefreshCw, ServerCrash, ShieldAlert, Terminal, Trash2, type LucideIcon, } from 'lucide-react'; import { usePlugins } from '../../../contexts/PluginsContext'; import type { Plugin } from '../../../contexts/PluginsContext'; import PluginIcon from './PluginIcon'; const STARTER_PLUGIN_URL = 'https://github.com/cloudcli-ai/cloudcli-plugin-starter'; const TERMINAL_PLUGIN_URL = 'https://github.com/cloudcli-ai/cloudcli-plugin-terminal'; const SCHEDULED_PROMPT_PLUGIN_URL = 'https://github.com/grostim/cloudcli-cron'; const CLAUDE_WATCH_PLUGIN_URL = 'https://github.com/satsuki19980613/cloudcli-claude-watch'; type PluginRecommendation = { id: string; translationKey: string; repoUrl: string; installedNames: string[]; icon: LucideIcon; source: 'official' | 'unofficial'; }; const OFFICIAL_PLUGIN_RECOMMENDATIONS: PluginRecommendation[] = [ { id: 'project-stats', translationKey: 'starterPlugin', repoUrl: STARTER_PLUGIN_URL, installedNames: ['project-stats'], icon: BarChart3, source: 'official', }, { id: 'web-terminal', translationKey: 'terminalPlugin', repoUrl: TERMINAL_PLUGIN_URL, installedNames: ['web-terminal'], icon: Terminal, source: 'official', }, ]; const UNOFFICIAL_PLUGIN_RECOMMENDATIONS: PluginRecommendation[] = [ { id: 'cloudcli-claude-watch', translationKey: 'claudeWatchPlugin', repoUrl: CLAUDE_WATCH_PLUGIN_URL, installedNames: ['cloudcli-claude-watch'], icon: Activity, source: 'unofficial', }, { id: 'workspace-scheduled-prompts', translationKey: 'scheduledPromptPlugin', repoUrl: SCHEDULED_PROMPT_PLUGIN_URL, installedNames: ['workspace-scheduled-prompts'], icon: Clock, source: 'unofficial', }, ]; function repoSlug(repoUrl: string) { return repoUrl.replace(/^https?:\/\/(www\.)?github\.com\//, ''); } function normalizeRepoUrl(repoUrl: string | null) { return repoUrl?.replace(/\.git$/, '').replace(/\/$/, '').toLowerCase() ?? null; } function pluginMatchesRecommendation(plugin: Plugin, recommendation: PluginRecommendation) { return ( recommendation.installedNames.includes(plugin.name) || normalizeRepoUrl(plugin.repoUrl) === normalizeRepoUrl(recommendation.repoUrl) ); } /* ─── Toggle Switch ─────────────────────────────────────────────────────── */ function ToggleSwitch({ checked, onChange, ariaLabel }: { checked: boolean; onChange: (v: boolean) => void; ariaLabel: string }) { return (