import { useEffect, useMemo, useState } from 'react' import { skillsApi } from '../../api/skills' import { mcpApi } from '../../api/mcp' import { useTranslation } from '../../i18n' import { useUIStore } from '../../stores/uiStore' import { SETTINGS_TAB_ID, useTabStore } from '../../stores/tabStore' import { useMcpStore } from '../../stores/mcpStore' import { useSkillStore } from '../../stores/skillStore' import type { McpServerRecord } from '../../types/mcp' import type { SkillMeta } from '../../types/skill' export type LocalSlashCommandName = 'mcp' | 'skills' | 'plugins' type Props = { command: LocalSlashCommandName cwd?: string onClose: () => void } function toneForStatus(status: McpServerRecord['status']) { switch (status) { case 'connected': return 'bg-emerald-500/10 text-emerald-600 border-emerald-500/20' case 'needs-auth': return 'bg-amber-500/10 text-amber-600 border-amber-500/20' case 'failed': return 'bg-rose-500/10 text-rose-600 border-rose-500/20' case 'disabled': return 'bg-[var(--color-surface-hover)] text-[var(--color-text-secondary)] border-[var(--color-border)]' default: return '' } } function scopeLabel(scope: string, t: ReturnType) { switch (scope) { case 'user': return t('settings.mcp.scope.user') case 'local': return t('settings.mcp.scope.local') case 'project': return t('settings.mcp.scope.project') default: return scope } } function projectBadge(path?: string, t?: ReturnType) { if (!path || !t) return null const label = path.replace(/\/$/, '').split('/').pop() || path return t('slash.mcp.projectBadge', { name: label }) } function PanelShell({ title, subtitle, children, onClose, }: { title: string subtitle: string children: React.ReactNode onClose: () => void }) { return (

{title}

{subtitle}

{children}
) } function LoadingState({ label }: { label: string }) { return (
{label}
) } function EmptyState({ title, body }: { title: string; body: string }) { return (
{title}
{body}
) } function ErrorState({ message }: { message: string }) { return (
{message}
) } function McpPanel({ cwd, onClose }: { cwd?: string; onClose: () => void }) { const t = useTranslation() const setPendingSettingsTab = useUIStore((s) => s.setPendingSettingsTab) const selectServer = useMcpStore((s) => s.selectServer) const [servers, setServers] = useState(null) const [error, setError] = useState(null) useEffect(() => { let cancelled = false mcpApi.list(cwd) .then((response) => { if (cancelled) return setServers(response.servers.filter((server) => server.scope === 'user' || server.scope === 'local' || server.scope === 'project')) }) .catch((err) => { if (cancelled) return setError(err instanceof Error ? err.message : String(err)) }) return () => { cancelled = true } }, [cwd]) const grouped = useMemo(() => { const groups = new Map() for (const server of servers ?? []) { const key = server.scope const existing = groups.get(key) ?? [] existing.push(server) groups.set(key, existing) } return groups }, [servers]) return ( {error ? ( ) : servers === null ? ( ) : servers.length === 0 ? ( ) : (
{['user', 'local', 'project'].filter((scope) => grouped.has(scope)).map((scope) => (
{scopeLabel(scope, t)}
{grouped.get(scope)?.length ?? 0}
{grouped.get(scope)?.map((server) => ( ))}
))}
)}
) } function SkillsPanel({ cwd, onClose }: { cwd?: string; onClose: () => void }) { const t = useTranslation() const setPendingSettingsTab = useUIStore((s) => s.setPendingSettingsTab) const fetchSkillDetail = useSkillStore((s) => s.fetchSkillDetail) const [skills, setSkills] = useState(null) const [error, setError] = useState(null) useEffect(() => { let cancelled = false skillsApi.list(cwd) .then((response) => { if (cancelled) return setSkills(response.skills.filter((skill) => skill.userInvocable)) }) .catch((err) => { if (cancelled) return setError(err instanceof Error ? err.message : String(err)) }) return () => { cancelled = true } }, [cwd]) return ( {error ? ( ) : skills === null ? ( ) : skills.length === 0 ? ( ) : (
{skills.map((skill) => ( ))}
)}
) } function PluginsPanel({ onClose }: { onClose: () => void }) { const t = useTranslation() return ( ) } export function LocalSlashCommandPanel({ command, cwd, onClose }: Props) { if (command === 'mcp') return if (command === 'skills') return return }