1import type { Metadata } from 'next';2import Link from 'next/link';3import { Dash, str, TypedListing } from '@/components/listing/typed-listing';4import { EntityBadge } from '@/components/ui/badges';5import { EntityLink, QualityMark } from '@/components/ui/entity';6import { api } from '@/lib/api';7import { fmtDate, fmtInt, num } from '@/lib/format';8import { routes } from '@/lib/site';910export const metadata: Metadata = { title: 'AI frameworks, libraries and runtimes — versions, licenses, stars', description: 'Training, inference and agent frameworks with latest version, release date, license and repository stars read from PyPI, GitHub and release pages.', alternates: { canonical: '/frameworks' } };11export const revalidate = 300;1213export default async function FrameworksPage({ searchParams }: { searchParams: Promise<Record<string, string | undefined>> }) {14 const sp = await searchParams;15 return (16 <TypedListing17 title="Frameworks & runtimes"18 eyebrow="Frameworks"19 lede="Libraries, inference engines and agent frameworks. Versions and stars are read from PyPI, GitHub and release pages — never estimated."20 basePath="/frameworks"21 searchParams={sp}22 fetch={(q) => api.explore('framework', q)}23 sorts={[24 { value: 'updated', label: 'Recently updated' },25 { value: 'stars', label: 'Stars' },26 { value: 'release', label: 'Latest release' },27 { value: 'name', label: 'Name' },28 { value: 'quality', label: 'Data quality' },29 ]}30 filters={sp.org ? [{ kind: 'hidden', name: 'org', value: sp.org }] : []}31 compare32 columns={[33 {34 key: 'name',35 label: 'Framework',36 primary: true,37 render: (e) => (38 <>39 <span className="flex flex-wrap items-center gap-x-2 gap-y-0.5">40 <EntityLink e={e} />41 {e.entity_type !== 'framework' && <EntityBadge type={e.entity_type} small />}42 </span>43 {e.description && <span className="block max-w-md truncate text-xs text-ink-3">{e.description}</span>}44 </>45 ),46 },47 { key: 'version', label: 'Latest version', className: 'mono text-xs text-ink', render: (e) => str(e.attributes?.latest_version) ?? <Dash /> },48 { key: 'release', label: 'Release date', className: 'tnum text-ink-2 whitespace-nowrap', render: (e) => (str(e.attributes?.latest_release_at) ? fmtDate(str(e.attributes.latest_release_at)) : <Dash />) },49 { key: 'license', label: 'License', className: 'max-w-[10rem] truncate text-ink-2', render: (e) => str(e.attributes?.license) ?? <Dash /> },50 { key: 'stars', label: 'Stars', num: true, className: 'tnum', render: (e) => (num(e.attributes?.['metric.stars']) === null ? <Dash /> : fmtInt(e.attributes['metric.stars'])) },51 { key: 'language', label: 'Language', className: 'text-ink-2', render: (e) => str(e.attributes?.language) ?? <Dash /> },52 {53 key: 'org',54 label: 'Organization',55 className: 'text-ink-2',56 render: (e) =>57 e.organization ? (58 <Link href={routes.entity({ entity_type: 'company', slug: e.organization.slug })} className="hover:text-accent">59 {e.organization.name}60 </Link>61 ) : (62 <Dash />63 ),64 },65 { key: 'quality', label: 'Quality', num: true, render: (e) => <QualityMark q={e.quality?.score} /> },66 ]}67 note="Stars are a GitHub metric observed at crawl time (see each framework's Sources tab for the snapshot). Versions come from PyPI or the project's release feed."68 />69 );70}71