/** * Shared grouping for the versioned libraries (skills and agent profiles). Both pages show one card * per key with a version picker, and both must collapse a builtin that an org has forked at the same * version — the org's own copy shadows the builtin (it's the one that resolves at run time and the * one you can edit), keeping the picker unambiguous. Kept in one place so the two libraries can't drift. */ export interface VersionedItem { version: string origin: string } /** Group items by key, dedupe per version (org-owned shadows builtin), and sort keys alphabetically. */ export function groupVersions( items: T[], keyOf: (item: T) => string, ): [string, T[]][] { const byKey = new Map() for (const item of items) { const key = keyOf(item) const list = byKey.get(key) ?? [] list.push(item) byKey.set(key, list) } for (const [key, list] of byKey) { const perVersion = new Map() for (const item of list) { const existing = perVersion.get(item.version) if (!existing || (existing.origin === 'Builtin' && item.origin !== 'Builtin')) { perVersion.set(item.version, item) } } byKey.set(key, [...perVersion.values()]) } return [...byKey.entries()].sort((a, b) => a[0].localeCompare(b[0])) }