import { useEffect, useState } from 'react'; import { api } from '@/api/client'; import type { Skill } from '@/api/types'; // Batch 9.6: shared in-memory cache for the slash-command dropdown. One fetch // per process; subsequent mounts of useSkills() return the cached list and // don't re-hit /api/skills. Matches the useSidebar / useChatStatus module- // singleton pattern so the dropdown stays cheap even with many ChatInputs // mounted at once. let cachedSkills: Skill[] | null = null; let inflight: Promise | null = null; const subscribers = new Set<(s: Skill[]) => void>(); async function loadSkills(): Promise { if (inflight) return inflight; inflight = api.skills .list() .then((r) => { cachedSkills = r.skills; for (const sub of subscribers) { try { sub(cachedSkills); } catch { /* swallow */ } } return cachedSkills; }) .finally(() => { inflight = null; }); return inflight; } export function useSkills(): { skills: Skill[]; loaded: boolean } { const [skills, setSkills] = useState(cachedSkills ?? []); const [loaded, setLoaded] = useState(cachedSkills !== null); useEffect(() => { subscribers.add(setSkills); if (cachedSkills === null) { void loadSkills().then(() => setLoaded(true)).catch(() => setLoaded(true)); } return () => { subscribers.delete(setSkills); }; }, []); return { skills, loaded }; }