/** * @file hiddenProfilesStorage.ts * @description Claude login profiles this browser leaves out of Settings → * AI tools → Profiles, kept in localStorage with the same read/validate/ * fallback convention as laneOrderStorage.ts. A viewer preference only: the * profile files, the API and the database are untouched, and another browser * still lists every profile. The status bar's Usage panel reads the same list * (`HIDDEN_PROFILES_EVENT` tells it of a change in this tab), and when the * live login is hidden both show the first visible profile in its place * (`standIn`). * * @author Nguyễn Ngọc Trí Vĩ */ const STORAGE_KEY = "agenthub.cc.hiddenProfiles"; /** Fired on `window` after this tab changes the list. */ export const HIDDEN_PROFILES_EVENT = "agenthub:hidden-profiles"; /** A profile's stable key: its account (survives a rename), else its file name. */ export function profileKey(p: { accountUuid: string | null; name?: string }): string { return p.accountUuid || p.name || ""; } export function readHiddenProfiles(): string[] { try { const raw = localStorage.getItem(STORAGE_KEY); if (!raw) return []; const parsed: unknown = JSON.parse(raw); if (!Array.isArray(parsed)) return []; return parsed.filter((k): k is string => typeof k === "string" && k.length > 0); } catch { return []; } } export function writeHiddenProfiles(keys: string[]): void { try { localStorage.setItem(STORAGE_KEY, JSON.stringify(keys)); } catch { /* ignore quota / disabled storage */ } try { window.dispatchEvent(new Event(HIDDEN_PROFILES_EVENT)); } catch { /* no window (tests outside jsdom) */ } } /** True when `key` names a change to the hidden list (a `storage` event's key). */ export const isHiddenProfilesKey = (key: string | null) => key === STORAGE_KEY || key === null; /** * The entry shown in place of a hidden live login: the first one in `list` * that is not hidden, or null when the live one is visible (or none is left). */ export function standIn( list: T[], isActive: (x: T) => boolean, hidden: string[] ): T | null { const live = list.find(isActive); if ( !live || !hidden.includes(profileKey({ accountUuid: live.accountUuid ?? null, name: live.name })) ) return null; return ( list.find( (x) => !isActive(x) && !hidden.includes(profileKey({ accountUuid: x.accountUuid ?? null, name: x.name })) ) ?? null ); } /** `keys` with `key` added when absent, removed when present. */ export function toggleHidden(keys: string[], key: string): string[] { return keys.includes(key) ? keys.filter((k) => k !== key) : [...keys, key]; }