1779 lines · 47.7 KB · TypeScript
RawDownload
import { useEffect, useMemo, useState, type CSSProperties, type ReactNode } from "react"import ReactMarkdown, { type Components } from "react-markdown"import remarkGfm from "remark-gfm"import {  ArrowUpRight,  BookOpen,  Bot,  ChevronLeft,  ChevronRight,  Check,  Copy,  FlaskConical,  GitBranch,  Layers,  Moon,  PackageCheck,  Rocket,  Search,  ShieldCheck,  Star,  Sun,  Terminal,} from "lucide-react"import { useTheme } from "./theme" const mono = `"JetBrains Mono", "SF Mono", ui-monospace, monospace` const DOCS_SERIF = `"Computer Modern Concrete", "Concrete Roman", Georgia, "Times New Roman", serif` type DocsConfig = {  name?: string  navigation: {    tabs: Array<{      tab: string      groups: Array<{        group: string        pages: Array<string | { group: string; pages: string[] }>      }>    }>    global?: {      anchors?: Array<{        anchor: string        href: string      }>    }  }  navbar?: {    links?: Array<{      label: string      href: string    }>    primary?: {      label: string      href: string    }  }} type DocsPage = {  path: string  title: string  description: string  icon: ReactNode  body: string  headings: string[]} type SearchResult = Pick<DocsPage, "path" | "title" | "description" | "icon"> & {  section: SectionKey  sectionLabel: string} type MintlifyCard = {  title: string  href: string  icon?: string  body: string  horizontal?: boolean} type SectionKey = "openscience" type Section = {  key: SectionKey  label: string  short: string  tagline: string  lead: boolean} const SECTIONS: Section[] = [  { key: "openscience", label: "OpenScience", short: "OpenScience", tagline: "Open-source AI workbench", lead: false },] const SECTION_KEYS = SECTIONS.map((section) => section.key) // All MDX content and per-section configs, loaded at build time. Adding a page is// just dropping an .mdx file into the right content/<section>/ folder.const RAW_PAGES = import.meta.glob("./content/**/*.{mdx,md}", {  query: "?raw",  import: "default",  eager: true,}) as Record<string, string> const RAW_CONFIGS = import.meta.glob("./content/**/docs.json", {  import: "default",  eager: true,}) as Record<string, DocsConfig> const ICONS: Record<string, ReactNode> = {  index: <GitBranch size={17} strokeWidth={1.8} />,  quickstart: <Rocket size={17} strokeWidth={1.8} />,  workspace: <Layers size={17} strokeWidth={1.8} />,  agents: <Bot size={17} strokeWidth={1.8} />,  models: <PackageCheck size={17} strokeWidth={1.8} />,  skills: <BookOpen size={17} strokeWidth={1.8} />,  sessions: <Terminal size={17} strokeWidth={1.8} />,  atlas: <GitBranch size={17} strokeWidth={1.8} />,  commands: <Terminal size={17} strokeWidth={1.8} />,  security: <ShieldCheck size={17} strokeWidth={1.8} />,} const SECTION_FALLBACK_ICON: Record<SectionKey, ReactNode> = {  openscience: <FlaskConical size={17} strokeWidth={1.8} />,} const FRONTMATTER_RE = /^---\n([\s\S]*?)\n---\n?/ function parseFrontmatter(source: string): { title: string; description: string; body: string } {  const match = source.match(FRONTMATTER_RE)  if (!match) return { title: "Untitled", description: "", body: source }  const frontmatter = match[1]  const body = source.slice(match[0].length)  const field = (name: string) => {    const line = frontmatter.split("\n").find((entry) => entry.trim().startsWith(`${name}:`))    return line      ? line          .split(":")          .slice(1)          .join(":")          .trim()          .replace(/^["']|["']$/g, "")      : ""  }  return {    title: field("title") || "Untitled",    description: field("description"),    body,  }} function extractHeadings(markdown: string): string[] {  return markdown    .split("\n")    .filter((line) => line.startsWith("## "))    .map((line) => line.replace(/^##\s+/, "").trim())    .slice(0, 10)} function flattenPages(items: Array<string | { group: string; pages: string[] }>): string[] {  return items.flatMap((item) => (typeof item === "string" ? [item] : item.pages))} function iconForPath(path: string, section: SectionKey): ReactNode {  const leaf = path.split("/").pop() ?? path  return ICONS[path] ?? ICONS[leaf] ?? SECTION_FALLBACK_ICON[section]} function buildSectionPages(section: SectionKey): Record<string, DocsPage> {  const prefix = `./content/${section}/`  const pages: Record<string, DocsPage> = {}  for (const [key, source] of Object.entries(RAW_PAGES)) {    if (!key.startsWith(prefix)) continue    const path = key.slice(prefix.length).replace(/\.(mdx|md)$/, "")    const parsed = parseFrontmatter(source)    pages[path] = {      path,      title: parsed.title,      description: parsed.description,      icon: iconForPath(path, section),      body: parsed.body,      headings: extractHeadings(parsed.body),    }  }  return pages} const SECTION_DOC_PAGES: Record<SectionKey, Record<string, DocsPage>> = {  openscience: buildSectionPages("openscience"),} const SECTION_CONFIGS: Record<SectionKey, DocsConfig> = {  openscience: RAW_CONFIGS["./content/openscience/docs.json"],} function pageExists(section: SectionKey, path: string): boolean {  return Boolean(SECTION_DOC_PAGES[section]?.[path])} // Retired first URL segments that redirect into the openscience scheme.const SECTION_ALIASES: Record<string, SectionKey> = {  "agent-cli": "openscience",} // Old CLI page names that moved during the OpenScience rebuild.const PAGE_ALIASES: Record<string, string> = {  "first-session": "sessions",  "sub-agents": "agents",  "web-ui": "workspace",  credentials: "atlas",} // Redirects from the oldest single-segment URLs to the #/<section>/<page> scheme.const LEGACY_REDIRECTS: Record<string, { section: SectionKey; path: string }> = {  "cli:index": { section: "openscience", path: "index" },  "cli:installation": { section: "openscience", path: "quickstart" },  "cli:quickstart": { section: "openscience", path: "quickstart" },  "cli:first-session": { section: "openscience", path: "sessions" },  "cli:sessions": { section: "openscience", path: "sessions" },  "cli:models": { section: "openscience", path: "models" },  "cli:codex": { section: "openscience", path: "models" },  "cli:sub-agents": { section: "openscience", path: "agents" },  "cli:skills": { section: "openscience", path: "skills" },  "cli:cli-runtime": { section: "openscience", path: "commands" },  "cli:connect": { section: "openscience", path: "atlas" },  "cli:credentials": { section: "openscience", path: "atlas" },  "cli:security": { section: "openscience", path: "security" },  "cli:feature-map": { section: "openscience", path: "commands" },  "cli:commands": { section: "openscience", path: "commands" },  "cli:web-ui": { section: "openscience", path: "workspace" },  "cli:server-mode": { section: "openscience", path: "workspace" },} type Route = { section: SectionKey; path: string } function defaultRoute(): Route {  return { section: "openscience", path: "index" }} function routeFromHash(): Route {  if (typeof window === "undefined") return defaultRoute()  const raw = decodeURIComponent(window.location.hash.replace(/^#\/?/, "")).replace(/\/$/, "")  if (!raw) return defaultRoute()  const segments = raw.split("/")  const maybeSection = segments[0] as SectionKey  if (SECTION_KEYS.includes(maybeSection)) {    const path = segments.slice(1).join("/") || "index"    if (pageExists(maybeSection, path)) return { section: maybeSection, path }    return { section: maybeSection, path: "index" }  }  // Retired section names redirect into the openscience scheme.  const aliasSection = SECTION_ALIASES[segments[0]]  if (aliasSection) {    const rawPath = segments.slice(1).join("/") || "index"    const path = PAGE_ALIASES[rawPath] ?? rawPath    if (pageExists(aliasSection, path)) return { section: aliasSection, path }    return { section: aliasSection, path: "index" }  }  // Legacy single-segment URL from the old CLI docs.  const redirect = LEGACY_REDIRECTS[`cli:${raw}`]  if (redirect && pageExists(redirect.section, redirect.path)) return redirect  return defaultRoute()} function pageHref(section: SectionKey, path: string): string {  return `#/${section}/${path}`} // Module-level pointers updated on each render so the markdown renderer (which// can't take props through react-markdown) can resolve links and card icons.let CURRENT_SECTION: SectionKey = "openscience" function resolveHref(href: string | undefined): string | undefined {  if (!href) return href  if (href.startsWith("http") || href.startsWith("#") || href.startsWith("mailto:")) return href  if (href.startsWith("/")) {    const clean = href.slice(1).replace(/\/$/, "")    if (!clean) return pageHref(CURRENT_SECTION, "index")    const segments = clean.split("/")    const maybeSection = segments[0] as SectionKey    if (SECTION_KEYS.includes(maybeSection)) {      const path = segments.slice(1).join("/") || "index"      if (pageExists(maybeSection, path)) return pageHref(maybeSection, path)    }    if (pageExists(CURRENT_SECTION, clean)) return pageHref(CURRENT_SECTION, clean)  }  return href} function sectionForHref(href: string): SectionKey {  const clean = href.replace(/^#\/?/, "").replace(/\/$/, "")  const segments = clean.split("/")  const maybeSection = segments[0] as SectionKey  return SECTION_KEYS.includes(maybeSection) ? maybeSection : CURRENT_SECTION} function parseMdxAttrs(attrs: string): Record<string, string | boolean> {  const parsed: Record<string, string | boolean> = {}  for (const match of attrs.matchAll(/([\w-]+)(?:=(?:"([^"]*)"|'([^']*)'|\{([^}]*)\}))?/g)) {    const key = match[1]    if (!key) continue    parsed[key] = match[2] ?? match[3] ?? match[4] ?? true  }  return parsed} function dedent(source: string): string {  const lines = source.replace(/\t/g, "  ").split("\n")  let min = Infinity  for (const line of lines) {    if (line.trim() === "") continue    const leading = line.match(/^( *)/)    if (leading) min = Math.min(min, leading[1].length)  }  if (!Number.isFinite(min) || min === 0) return source  return lines.map((line) => (line.length >= min ? line.slice(min) : line)).join("\n")} function parseCards(source: string): MintlifyCard[] {  return Array.from(source.matchAll(/<Card\b([^>]*)>\s*([\s\S]*?)\s*<\/Card>/g)).map((match) => {    const attrs = parseMdxAttrs(match[1] ?? "")    return {      title: String(attrs.title ?? "Untitled"),      href: String(attrs.href ?? "#"),      icon: attrs.icon ? String(attrs.icon) : undefined,      horizontal: Boolean(attrs.horizontal),      body: dedent(match[2] ?? "").trim(),    }  })} function iconForCard(card: MintlifyCard): ReactNode {  const resolved = resolveHref(card.href)  if (resolved && resolved.startsWith("#/")) {    const section = sectionForHref(resolved)    const path = resolved.replace(/^#\/?/, "").replace(/\/$/, "").split("/").slice(1).join("/")    const page = SECTION_DOC_PAGES[section]?.[path]    if (page) return page.icon  }  return <BookOpen size={17} strokeWidth={1.8} />} const OPENSCIENCE_REPO = "synthetic-sciences/openscience" function formatStars(count: number): string {  return count >= 1000 ? `${(count / 1000).toFixed(1).replace(/\.0$/, "")}k` : String(count)} function GitHubStars() {  const [stars, setStars] = useState<number | null>(null)   useEffect(() => {    let cancelled = false    const cacheKey = `docs-gh-stars:${OPENSCIENCE_REPO}`    try {      const cached = JSON.parse(window.localStorage.getItem(cacheKey) ?? "null") as { stars: number; at: number } | null      if (cached && Date.now() - cached.at < 60 * 60 * 1000) {        setStars(cached.stars)        return      }    } catch {      /* ignore */    }    fetch(`https://api.github.com/repos/${OPENSCIENCE_REPO}`)      .then((response) => (response.ok ? response.json() : null))      .then((data: { stargazers_count?: number } | null) => {        const count = data?.stargazers_count        if (typeof count !== "number" || cancelled) return        setStars(count)        try {          window.localStorage.setItem(cacheKey, JSON.stringify({ stars: count, at: Date.now() }))        } catch {          /* ignore */        }      })      .catch(() => undefined)    return () => {      cancelled = true    }  }, [])   return (    <div className="docs-ghstars">      <a        className="docs-ghstars-primary"        href={`https://github.com/${OPENSCIENCE_REPO}`}        target="_blank"        rel="noreferrer"      >        <Star size={13} strokeWidth={1.8} />        <span>Star on GitHub</span>        {stars !== null ? <em>{formatStars(stars)}</em> : null}      </a>      <a href={`https://github.com/${OPENSCIENCE_REPO}/blob/main/LICENSE`} target="_blank" rel="noreferrer">        Apache-2.0      </a>      <a href="https://www.npmjs.com/package/@synsci/openscience" target="_blank" rel="noreferrer">        npm · @synsci/openscience      </a>    </div>  )} function CopyButton({ text }: { text: string }) {  const [copied, setCopied] = useState(false)  return (    <button      type="button"      className="docs-copy"      onClick={() => {        void navigator.clipboard.writeText(text)        setCopied(true)        window.setTimeout(() => setCopied(false), 1200)      }}      aria-label="copy code"      title="copy code"    >      {copied ? <Check size={13} strokeWidth={1.8} /> : <Copy size={13} strokeWidth={1.8} />}      <span>{copied ? "copied" : "copy"}</span>    </button>  )} const markdownComponents: Components = {  h2({ children }) {    const id = String(children)      .toLowerCase()      .replace(/[^a-z0-9]+/g, "-")      .replace(/^-|-$/g, "")    return <h2 id={id}>{children}</h2>  },  a({ href, children }) {    const external = href?.startsWith("http")    const internalDocsHref = href ? resolveHref(href) : undefined    return (      <a href={internalDocsHref} target={external ? "_blank" : undefined} rel={external ? "noreferrer" : undefined}>        {children}        {external ? <ArrowUpRight size={12} strokeWidth={1.8} /> : null}      </a>    )  },  pre({ children }) {    const text = extractCodeText(children)    return (      <div className="docs-code-wrap">        <CopyButton text={text} />        <pre>{children}</pre>      </div>    )  },  code({ className, children }) {    const isBlock = className?.startsWith("language-")    return <code className={isBlock ? className : "docs-inline-code"}>{children}</code>  },  table({ children }) {    return (      <div className="docs-table-wrap">        <table>{children}</table>      </div>    )  },  blockquote({ children }) {    return <blockquote className="docs-callout">{children}</blockquote>  },} function extractCodeText(node: ReactNode): string {  if (typeof node === "string") return node  if (Array.isArray(node)) return node.map(extractCodeText).join("")  if (node && typeof node === "object" && "props" in node) {    const props = (node as { props?: { children?: ReactNode } }).props    return extractCodeText(props?.children ?? "")  }  return ""} function MarkdownChunk({ children }: { children: string }) {  if (!children.trim()) return null  return (    <ReactMarkdown remarkPlugins={[remarkGfm]} components={markdownComponents}>      {children}    </ReactMarkdown>  )} function MintlifyCardView({ card }: { card: MintlifyCard }) {  const external = card.href.startsWith("http")  return (    <a      className={card.horizontal ? "docs-card docs-card-horizontal" : "docs-card"}      href={resolveHref(card.href)}      target={external ? "_blank" : undefined}      rel={external ? "noreferrer" : undefined}    >      <span className="docs-card-icon">{iconForCard(card)}</span>      <span className="docs-card-copy">        <strong>{card.title}</strong>        <small>{card.body}</small>      </span>      <ArrowUpRight size={14} strokeWidth={1.8} />

Lines 1–500 of 1779.