{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "project-brief",
  "title": "Project Brief",
  "description": "Shared ProjectBrief type + OG/thumbnail href helpers for Scope → Planner → social card glue.",
  "files": [
    {
      "path": "registry/default/lib/project-brief.ts",
      "content": "/**\n * Shared launch brief — glue between Scope → Planner → OG / Thumbnail.\n * Host-owned, serializable JSON. No AtroUI backend required.\n *\n * Install: npx shadcn@latest add @atroui/project-brief\n */\n\nexport type ProjectBrief = {\n  name: string\n  oneLiner: string\n  audience: string\n  pages: string[]\n  tone: string\n  constraints: string[]\n  ogTitle?: string\n  ogSubtitle?: string\n  thumbnailTitle?: string\n}\n\nexport const EMPTY_PROJECT_BRIEF: ProjectBrief = {\n  name: \"\",\n  oneLiner: \"\",\n  audience: \"\",\n  pages: [],\n  tone: \"\",\n  constraints: [],\n}\n\n/** localStorage key for optional client-side persistence on the host. */\nexport const PROJECT_BRIEF_STORAGE_KEY = \"atroui:project-brief\"\n\nexport function isProjectBrief(value: unknown): value is ProjectBrief {\n  if (!value || typeof value !== \"object\") return false\n  const v = value as Record<string, unknown>\n  return (\n    typeof v.name === \"string\" &&\n    typeof v.oneLiner === \"string\" &&\n    typeof v.audience === \"string\" &&\n    Array.isArray(v.pages) &&\n    typeof v.tone === \"string\" &&\n    Array.isArray(v.constraints)\n  )\n}\n\nexport function parseProjectBrief(raw: string): ProjectBrief | null {\n  try {\n    const data = JSON.parse(raw) as unknown\n    return isProjectBrief(data) ? data : null\n  } catch {\n    return null\n  }\n}\n\nexport function briefOgTitle(brief: ProjectBrief): string {\n  return (brief.ogTitle ?? brief.name).trim()\n}\n\nexport function briefOgSubtitle(brief: ProjectBrief): string {\n  return (brief.ogSubtitle ?? brief.oneLiner).trim()\n}\n\nexport function briefThumbnailTitle(brief: ProjectBrief): string {\n  return (brief.thumbnailTitle ?? brief.ogTitle ?? brief.name).trim()\n}\n\nexport function buildOgHref(\n  brief: ProjectBrief,\n  options?: { path?: string; style?: string }\n): string {\n  const path = options?.path ?? \"/og\"\n  const title = briefOgTitle(brief)\n  const subtitle = briefOgSubtitle(brief)\n  const params = new URLSearchParams({ mode: \"quick\" })\n  if (title) params.set(\"title\", title)\n  if (subtitle) params.set(\"subtitle\", subtitle)\n  if (options?.style) params.set(\"style\", options.style)\n  const qs = params.toString()\n  return `${path}?${qs}#og-workspace`\n}\n\nexport function buildThumbnailHref(\n  brief: ProjectBrief,\n  options?: { path?: string }\n): string {\n  const path = options?.path ?? \"/thumbnail\"\n  const title = briefThumbnailTitle(brief)\n  const params = new URLSearchParams()\n  if (title) params.set(\"title\", title)\n  const qs = params.toString()\n  return qs ? `${path}?${qs}` : path\n}\n\nexport function briefFromScopeMessage(text: string): ProjectBrief {\n  const oneLiner = text.trim().slice(0, 160)\n  return {\n    ...EMPTY_PROJECT_BRIEF,\n    name: oneLiner.slice(0, 48) || \"Untitled project\",\n    oneLiner,\n    ogTitle: oneLiner.slice(0, 64) || \"Ship in days, not quarters.\",\n    ogSubtitle: \"Built with AtroUI\",\n  }\n}\n",
      "type": "registry:lib",
      "target": "lib/project-brief.ts"
    }
  ],
  "type": "registry:lib"
}