From 306b75f1d26b74470e546e06071608045f391d8f Mon Sep 17 00:00:00 2001 From: Hangzhi Date: Fri, 27 Mar 2026 05:12:50 +0000 Subject: [PATCH] Add contributor and acknowledgement to registry dataset cards Display contributor names and acknowledgement (2077AI placeholder) above the uvx command in each dataset card. Data is sourced from a local registry-meta.json, generated by scripts/generate-registry-meta.py which mirrors the adapter pipeline from PR #43. Co-Authored-By: Claude Opus 4.6 (1M context) --- scripts/generate-registry-meta.py | 87 ++++++++++++++++++++++ src/app/(home)/registry/dataset-card.tsx | 21 ++++++ src/app/(home)/registry/page.tsx | 24 +++--- src/app/(home)/registry/registry-meta.json | 14 ++++ 4 files changed, 137 insertions(+), 9 deletions(-) create mode 100644 scripts/generate-registry-meta.py create mode 100644 src/app/(home)/registry/registry-meta.json diff --git a/scripts/generate-registry-meta.py b/scripts/generate-registry-meta.py new file mode 100644 index 0000000..afe277a --- /dev/null +++ b/scripts/generate-registry-meta.py @@ -0,0 +1,87 @@ +#!/usr/bin/env python3 +"""Pull adapter_metadata.json files from harbor repo and generate registry-meta.json.""" + +import json +import os +import re +import shutil +import subprocess +import sys +import tempfile + +HARBOR_REPO = "git@github.com:harbor-framework/harbor.git" +OUTPUT_PATH = os.path.join( + os.path.dirname(os.path.dirname(os.path.abspath(__file__))), + "src", + "app", + "(home)", + "registry", + "registry-meta.json", +) + +BUILDER_PATTERN = re.compile(r"^(.+?)\s*\(([^)]+)\)$") + + +def parse_builder(raw: str) -> dict: + """Parse 'Name (email)' into {"name": ..., "email": ...}.""" + match = BUILDER_PATTERN.match(raw.strip()) + if match: + return {"name": match.group(1).strip(), "email": match.group(2).strip()} + return {"name": raw.strip(), "email": ""} + + +def main(): + clone_dir = tempfile.mkdtemp(prefix="harbor-") + + try: + print(f"Cloning {HARBOR_REPO} (shallow)...") + subprocess.run( + ["git", "clone", "--depth", "1", HARBOR_REPO, clone_dir], + check=True, + capture_output=True, + text=True, + ) + + adapters_dir = os.path.join(clone_dir, "adapters") + if not os.path.isdir(adapters_dir): + print("Error: adapters directory not found in harbor repo", file=sys.stderr) + sys.exit(1) + + registry_meta: dict[str, dict] = {} + for entry in sorted(os.listdir(adapters_dir)): + metadata_path = os.path.join(adapters_dir, entry, "adapter_metadata.json") + if not os.path.isfile(metadata_path): + continue + + with open(metadata_path, "r") as f: + data = json.load(f) + + if not isinstance(data, list) or len(data) == 0: + continue + + item = data[0] + adapter_name = item.get("adapter_name", entry) + + raw_builders = item.get("adapter_builders", []) + if not isinstance(raw_builders, list): + raw_builders = [] + contributors = [parse_builder(b) for b in raw_builders] + + registry_meta[adapter_name] = { + "contributors": contributors, + "acknowledgement": "2077AI", + } + + os.makedirs(os.path.dirname(OUTPUT_PATH), exist_ok=True) + with open(OUTPUT_PATH, "w") as f: + json.dump(registry_meta, f, indent=2) + f.write("\n") + + print(f"Generated {OUTPUT_PATH} with {len(registry_meta)} entries.") + + finally: + shutil.rmtree(clone_dir, ignore_errors=True) + + +if __name__ == "__main__": + main() diff --git a/src/app/(home)/registry/dataset-card.tsx b/src/app/(home)/registry/dataset-card.tsx index 461a987..dff01f3 100644 --- a/src/app/(home)/registry/dataset-card.tsx +++ b/src/app/(home)/registry/dataset-card.tsx @@ -10,6 +10,7 @@ import { CardHeader, CardTitle, } from "@/components/ui/card"; +import { Heart, User } from "lucide-react"; import Link from "next/link"; import { toast } from "sonner"; @@ -18,6 +19,8 @@ interface DatasetCardProps { version: string; description: string | null; taskCount: number; + contributors?: { name: string; email: string }[]; + acknowledgement?: string; } export function DatasetCard({ @@ -25,6 +28,8 @@ export function DatasetCard({ version, description, taskCount, + contributors, + acknowledgement, }: DatasetCardProps) { const datasetString = `${name}@${version}`; @@ -64,6 +69,22 @@ export function DatasetCard({ + {(contributors?.length || acknowledgement) && ( +
+ {contributors?.map((c, i) => ( + + + {c.name} + + ))} + {acknowledgement && ( + + + {acknowledgement} + + )} +
+ )}
{ diff --git a/src/app/(home)/registry/page.tsx b/src/app/(home)/registry/page.tsx index 5a92ff7..e27c274 100644 --- a/src/app/(home)/registry/page.tsx +++ b/src/app/(home)/registry/page.tsx @@ -4,6 +4,7 @@ import { createClient } from "@/lib/supabase/server"; import type { Tables } from "@/lib/supabase/types"; import type { Metadata } from "next"; import { DatasetCard } from "./dataset-card"; +import registryMeta from "./registry-meta.json"; export const revalidate = 60; @@ -66,15 +67,20 @@ export default async function RegistryPage() { ) : (
- {datasets.map((dataset) => ( - - ))} + {datasets.map((dataset) => { + const meta = (registryMeta as Record)[dataset.name]; + return ( + + ); + })}
)} diff --git a/src/app/(home)/registry/registry-meta.json b/src/app/(home)/registry/registry-meta.json new file mode 100644 index 0000000..66d3e32 --- /dev/null +++ b/src/app/(home)/registry/registry-meta.json @@ -0,0 +1,14 @@ +{ + "terminal-bench": { + "contributors": [ + { "name": "Harbor Team", "email": "" } + ], + "acknowledgement": "2077AI" + }, + "swebench-verified": { + "contributors": [ + { "name": "Harbor Team", "email": "" } + ], + "acknowledgement": "2077AI" + } +}