SPB Git

Repository Public MIT

page.tsx 9.1 KB 162 lines tsx

1import Link from "next/link";2import { ArrowRight } from "lucide-react";3import { ARTIFACT_TYPES, TYPE_LABELS, type ArtifactType } from "@skills/registry-core";4import { ArtifactGrid, EmptyState } from "@/components/artifact-card";5import { CodeBlock } from "@/components/code";6import { SearchTrigger } from "@/components/command-palette";7import { plural } from "@/lib/format";8import { t } from "@/lib/i18n";9import { publicCtx } from "@/lib/session";10import { listCollections } from "@/server/community";11import { facets, listArtifacts } from "@/server/registry";1213const TYPE_ROUTE: Partial<Record<ArtifactType, string>> = { skill: "/skills", "mcp-server": "/mcp-servers", agent: "/agents", workflow: "/workflows" };1415export default async function Home() {16  const ctx = await publicCtx();17  const [f, recent, collections] = await Promise.all([facets(ctx), listArtifacts(ctx, { perPage: 6, sort: "updated" }), listCollections(ctx)]);18  // "Featured verified": only artifacts whose publisher identity AND source provenance were verified. Never hand-picked numbers.19  const featured = recent.items.filter((a) => a.publisher.identityVerified && a.sourceVerified).slice(0, 3);20  const example = recent.items.find((a) => a.type === "skill" && a.latestVersion);2122  return (23    <>24      <section className="border-b border-line">25        <div className="container-page pb-16 pt-20 sm:pb-20 sm:pt-28">26          <p className="eyebrow mb-5">The Open Agent Capability Registry</p>27          <h1 className="max-w-4xl text-4xl font-semibold leading-[1.05] tracking-tight sm:text-6xl">28            Discover. Build. Publish.29            <br />30            <span className="text-muted">Extend your agents.</span>31          </h1>32          <p className="mt-6 max-w-2xl text-lg text-muted">{t.statement}</p>33          <div className="mt-9 max-w-2xl">34            <SearchTrigger large />35          </div>36          <div className="mt-6 flex flex-wrap gap-3">37            <Link href="/explore" className="btn btn-primary">Explore the registry <ArrowRight size={15} aria-hidden /></Link>38            <Link href="/docs" className="btn">Read the docs</Link>39          </div>40          <dl className="mt-12 flex flex-wrap gap-x-10 gap-y-4 border-t border-line pt-6" aria-label="Live registry counts">41            {[42              [f.totals.artifacts, "public artifact"],43              [f.totals.releases, "immutable release"],44              [f.totals.publishers, "publisher"],45            ].map(([n, label]) => (46              <div key={label as string}>47                <dd className="font-mono text-2xl text-text" data-testid={`count-${label}`}>{(n as number).toLocaleString("en-CA")}</dd>48                <dt className="text-sm text-muted">{plural(n as number, label as string).replace(/^[\d\s,.]+/, "")}</dt>49              </div>50            ))}51          </dl>52          <p className="mt-4 font-mono text-[11px] text-faint">Counted live from the registry database.</p>53        </div>54      </section>5556      <section aria-labelledby="types-h" className="container-page pt-16">57        <div className="mb-6 flex items-end justify-between gap-4">58          <div>59            <p className="eyebrow mb-2">Browse by type</p>60            <h2 id="types-h" className="text-2xl font-semibold tracking-tight">Ten typed kinds of capability</h2>61          </div>62        </div>63        <ul className="grid gap-px overflow-hidden rounded-[10px] border border-line bg-line sm:grid-cols-2 lg:grid-cols-5">64          {ARTIFACT_TYPES.map((type) => (65            <li key={type} className="bg-graphite">66              <Link href={TYPE_ROUTE[type] ?? `/explore?type=${type}`} className="group flex h-full flex-col p-4 transition-colors hover:bg-raised">67                <span className="flex items-baseline justify-between gap-2">68                  <span className="text-sm font-medium text-text">{TYPE_LABELS[type].plural}</span>69                  <span className="font-mono text-xs text-faint">{f.types[type] ?? 0}</span>70                </span>71                <span className="mt-1.5 text-xs leading-relaxed text-muted">{TYPE_LABELS[type].blurb}</span>72              </Link>73            </li>74          ))}75        </ul>76      </section>7778      {featured.length > 0 && (79        <section aria-labelledby="featured-h" className="container-page pt-16">80          <p className="eyebrow mb-2">Verified identity and source</p>81          <h2 id="featured-h" className="mb-6 text-2xl font-semibold tracking-tight">Featured</h2>82          <ArtifactGrid items={featured} />83        </section>84      )}8586      <section aria-labelledby="recent-h" className="container-page pt-16">87        <div className="mb-6 flex items-end justify-between gap-4">88          <div>89            <p className="eyebrow mb-2">Activity</p>90            <h2 id="recent-h" className="text-2xl font-semibold tracking-tight">Recently updated</h2>91          </div>92          <Link href="/explore" className="text-sm text-muted hover:text-text">View all <ArrowRight size={13} aria-hidden className="inline" /></Link>93        </div>94        {recent.items.length ? <ArtifactGrid items={recent.items} /> : <EmptyState title="The registry is empty.">Nothing has been published yet. No placeholder content is shown.</EmptyState>}95      </section>9697      <section aria-labelledby="install-h" className="container-page grid gap-10 pt-20 lg:grid-cols-2">98        <div>99          <p className="eyebrow mb-2">Install</p>100          <h2 id="install-h" className="text-2xl font-semibold tracking-tight">Inspect first. Then install.</h2>101          <p className="mt-3 text-muted">102            Every release is an immutable archive with a SHA-256 checksum. The CLI shows declared permissions and the destination, verifies the checksum, copies files and stops there. It never runs package scripts.103          </p>104          <ul className="mt-5 space-y-2 text-sm text-muted">105            <li>— Claude Code, OpenAI Codex, Cursor and generic Skills or MCP clients</li>106            <li>— Download, configure and execute stay three separate decisions</li>107            <li>— Version pinning, conflict detection and one-command rollback</li>108          </ul>109          <Link href="/docs" className="link mt-5 inline-block text-sm">Installation guides</Link>110        </div>111        <div className="space-y-3">112          <CodeBlock prompt label="Inspect before installing" code={`skills inspect ${example ? example.name : "@namespace/artifact"}`} />113          <CodeBlock prompt label="Install into Claude Code" code={`skills install ${example ? `${example.name}@${example.latestVersion}` : "@namespace/artifact"} --client claude-code`} />114          <CodeBlock prompt label="Use the registry from any MCP client" code={`claude mcp add --transport http skills-registry ${"https://skills.spboucher.ai"}/mcp`} />115        </div>116      </section>117118      <section aria-labelledby="collections-h" className="container-page pt-20">119        <div className="mb-6 flex items-end justify-between gap-4">120          <div>121            <p className="eyebrow mb-2">Curated</p>122            <h2 id="collections-h" className="text-2xl font-semibold tracking-tight">Research collections</h2>123          </div>124          <Link href="/collections" className="text-sm text-muted hover:text-text">All collections <ArrowRight size={13} aria-hidden className="inline" /></Link>125        </div>126        {collections.length === 0 ? (127          <EmptyState title="No collections yet." />128        ) : (129          <ul className="grid gap-4 sm:grid-cols-2 lg:grid-cols-4">130            {collections.slice(0, 8).map((c) => (131              <li key={c.slug}>132                <Link href={`/collections/${c.slug}`} className="card card-hover flex h-full flex-col p-5">133                  <span className="text-sm font-medium text-text">{c.title}</span>134                  <span className="mt-1.5 flex-1 text-xs leading-relaxed text-muted">{c.description}</span>135                  <span className="mt-3 font-mono text-[11px] text-faint">{plural(c.item_count, "artifact")}</span>136                </Link>137              </li>138            ))}139          </ul>140        )}141      </section>142143      <section aria-labelledby="publish-h" className="container-page pt-20">144        <div className="card grid gap-8 p-8 sm:p-10 lg:grid-cols-[1.2fr_1fr]">145          <div>146            <p className="eyebrow mb-2">Open publishing</p>147            <h2 id="publish-h" className="text-2xl font-semibold tracking-tight">Publish what you build.</h2>148            <p className="mt-3 max-w-xl text-muted">149              Package a directory, validate it locally, review a dry run, and publish an immutable, checksummed release with a scoped token — from your terminal or directly from Claude Code. Preserve your upstream manifests; the registry adds a thin wrapper, not a new format.150            </p>151            <div className="mt-6 flex flex-wrap gap-3">152              <Link href="/publish" className="btn btn-primary">How to publish</Link>153              <Link href="/docs/security" className="btn">Trust &amp; security model</Link>154            </div>155          </div>156          <CodeBlock prompt label="Publish from a terminal" code={`skills validate ./my-skill\nskills publish ./my-skill --dry-run\nskills publish ./my-skill --visibility public`} />157        </div>158      </section>159    </>160  );161}162
Files main
Menu

Theme