@aglyn/plugins-ai 1.0.0-beta.231 → 1.0.0-beta.232

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (220) hide show
  1. package/package.json +17 -17
  2. package/src/lib/activity/ai-activity-actions.js +8 -4
  3. package/src/lib/activity/ai-activity-actions.js.map +1 -1
  4. package/src/lib/components/ai-job-follow.component.js +1 -0
  5. package/src/lib/components/ai-job-follow.component.js.map +1 -1
  6. package/src/lib/components/ai-job-links.js +13 -0
  7. package/src/lib/components/ai-job-links.js.map +1 -1
  8. package/src/lib/components/ai-jobs-list-page.component.js +1 -0
  9. package/src/lib/components/ai-jobs-list-page.component.js.map +1 -1
  10. package/src/lib/components/ai-media-create.component.d.ts +20 -7
  11. package/src/lib/components/ai-media-create.component.js +107 -55
  12. package/src/lib/components/ai-media-create.component.js.map +1 -1
  13. package/src/lib/components/ai-seo-fields-card.component.js +1 -0
  14. package/src/lib/components/ai-seo-fields-card.component.js.map +1 -1
  15. package/src/lib/components/ai-site-memory-card.component.d.ts +32 -0
  16. package/src/lib/components/ai-site-memory-card.component.js +187 -0
  17. package/src/lib/components/ai-site-memory-card.component.js.map +1 -0
  18. package/src/lib/components/ai-site-start-card.component.js +80 -77
  19. package/src/lib/components/ai-site-start-card.component.js.map +1 -1
  20. package/src/lib/components/ai-theme-proposal-card.component.js +4 -0
  21. package/src/lib/components/ai-theme-proposal-card.component.js.map +1 -1
  22. package/src/lib/components/ai-usage-strip.component.js +1 -0
  23. package/src/lib/components/ai-usage-strip.component.js.map +1 -1
  24. package/src/lib/components/assist-panel.component.d.ts +10 -0
  25. package/src/lib/components/assist-panel.component.js +119 -9
  26. package/src/lib/components/assist-panel.component.js.map +1 -1
  27. package/src/lib/components/assist-signals-page.component.js +2 -0
  28. package/src/lib/components/assist-signals-page.component.js.map +1 -1
  29. package/src/lib/components/billing-ai-allotments.component.js +3 -0
  30. package/src/lib/components/billing-ai-allotments.component.js.map +1 -1
  31. package/src/lib/components/billing-ai-top-users.component.js +1 -0
  32. package/src/lib/components/billing-ai-top-users.component.js.map +1 -1
  33. package/src/lib/components/billing-assist-overage-card.component.js +2 -0
  34. package/src/lib/components/billing-assist-overage-card.component.js.map +1 -1
  35. package/src/lib/components/member-ai-usage-card.component.js +10 -0
  36. package/src/lib/components/member-ai-usage-card.component.js.map +1 -1
  37. package/src/lib/components/staff-org-ai-card.component.js +1 -0
  38. package/src/lib/components/staff-org-ai-card.component.js.map +1 -1
  39. package/src/lib/components/staff-org-ai-conversations.component.d.ts +23 -0
  40. package/src/lib/components/staff-org-ai-conversations.component.js +346 -0
  41. package/src/lib/components/staff-org-ai-conversations.component.js.map +1 -0
  42. package/src/lib/jobs/ai-build-capabilities.d.ts +13 -1
  43. package/src/lib/jobs/ai-build-capabilities.js +101 -7
  44. package/src/lib/jobs/ai-build-capabilities.js.map +1 -1
  45. package/src/lib/jobs/ai-business-profile-prefill.d.ts +29 -0
  46. package/src/lib/jobs/ai-business-profile-prefill.js +85 -0
  47. package/src/lib/jobs/ai-business-profile-prefill.js.map +1 -0
  48. package/src/lib/jobs/ai-job-build-step.js +3 -1
  49. package/src/lib/jobs/ai-job-build-step.js.map +1 -1
  50. package/src/lib/jobs/ai-job-edit-step.d.ts +225 -0
  51. package/src/lib/jobs/ai-job-edit-step.js +631 -0
  52. package/src/lib/jobs/ai-job-edit-step.js.map +1 -0
  53. package/src/lib/jobs/ai-job-insight-step.js +21 -4
  54. package/src/lib/jobs/ai-job-insight-step.js.map +1 -1
  55. package/src/lib/jobs/ai-job-layout-language.d.ts +8 -3
  56. package/src/lib/jobs/ai-job-layout-language.js +8 -2
  57. package/src/lib/jobs/ai-job-layout-language.js.map +1 -1
  58. package/src/lib/jobs/ai-job-layout-step.js +7 -6
  59. package/src/lib/jobs/ai-job-layout-step.js.map +1 -1
  60. package/src/lib/jobs/ai-job-logic-step.d.ts +20 -0
  61. package/src/lib/jobs/ai-job-logic-step.js +87 -6
  62. package/src/lib/jobs/ai-job-logic-step.js.map +1 -1
  63. package/src/lib/jobs/ai-job-page-language.d.ts +52 -7
  64. package/src/lib/jobs/ai-job-page-language.js +72 -9
  65. package/src/lib/jobs/ai-job-page-language.js.map +1 -1
  66. package/src/lib/jobs/ai-job-page-step.js +12 -2
  67. package/src/lib/jobs/ai-job-page-step.js.map +1 -1
  68. package/src/lib/jobs/ai-job-plan-step.d.ts +19 -5
  69. package/src/lib/jobs/ai-job-plan-step.js +54 -20
  70. package/src/lib/jobs/ai-job-plan-step.js.map +1 -1
  71. package/src/lib/jobs/ai-job-site-content.d.ts +163 -0
  72. package/src/lib/jobs/ai-job-site-content.js +443 -0
  73. package/src/lib/jobs/ai-job-site-content.js.map +1 -0
  74. package/src/lib/jobs/ai-job-site-look.d.ts +112 -0
  75. package/src/lib/jobs/ai-job-site-look.js +322 -0
  76. package/src/lib/jobs/ai-job-site-look.js.map +1 -0
  77. package/src/lib/jobs/ai-job-site-step.d.ts +26 -5
  78. package/src/lib/jobs/ai-job-site-step.js +163 -24
  79. package/src/lib/jobs/ai-job-site-step.js.map +1 -1
  80. package/src/lib/jobs/ai-jobs-notify.d.ts +6 -1
  81. package/src/lib/jobs/ai-jobs-notify.js +15 -3
  82. package/src/lib/jobs/ai-jobs-notify.js.map +1 -1
  83. package/src/lib/layout-language/ai-layout-compiler.d.ts +9 -0
  84. package/src/lib/layout-language/ai-layout-compiler.js +120 -33
  85. package/src/lib/layout-language/ai-layout-compiler.js.map +1 -1
  86. package/src/lib/layout-language/ai-layout-frame.js +5 -4
  87. package/src/lib/layout-language/ai-layout-frame.js.map +1 -1
  88. package/src/lib/layout-language/ai-layout-language.d.ts +12 -5
  89. package/src/lib/layout-language/ai-layout-language.js +92 -9
  90. package/src/lib/layout-language/ai-layout-language.js.map +1 -1
  91. package/src/lib/layout-language/ai-layout-pictures.d.ts +144 -0
  92. package/src/lib/layout-language/ai-layout-pictures.js +214 -0
  93. package/src/lib/layout-language/ai-layout-pictures.js.map +1 -0
  94. package/src/lib/layout-language/ai-layout-store.d.ts +2 -0
  95. package/src/lib/layout-language/ai-layout-store.js +7 -1
  96. package/src/lib/layout-language/ai-layout-store.js.map +1 -1
  97. package/src/lib/model/ai-build-progress.js +4 -1
  98. package/src/lib/model/ai-build-progress.js.map +1 -1
  99. package/src/lib/model/ai-edit-job.d.ts +109 -0
  100. package/src/lib/model/ai-edit-job.js +157 -0
  101. package/src/lib/model/ai-edit-job.js.map +1 -0
  102. package/src/lib/model/ai-job-activity.js +1 -0
  103. package/src/lib/model/ai-job-activity.js.map +1 -1
  104. package/src/lib/model/ai-jobs.types.d.ts +3 -1
  105. package/src/lib/model/ai-jobs.types.js.map +1 -1
  106. package/src/lib/model/ai-logic-job.d.ts +18 -1
  107. package/src/lib/model/ai-logic-job.js +24 -3
  108. package/src/lib/model/ai-logic-job.js.map +1 -1
  109. package/src/lib/model/ai-media-credits.d.ts +8 -4
  110. package/src/lib/model/ai-media-credits.js +11 -4
  111. package/src/lib/model/ai-media-credits.js.map +1 -1
  112. package/src/lib/model/ai-media-kinds.d.ts +68 -0
  113. package/src/lib/model/ai-media-kinds.js +98 -0
  114. package/src/lib/model/ai-media-kinds.js.map +1 -0
  115. package/src/lib/model/ai-site-build-progress.d.ts +4 -0
  116. package/src/lib/model/ai-site-build-progress.js +28 -11
  117. package/src/lib/model/ai-site-build-progress.js.map +1 -1
  118. package/src/lib/model/ai-site-context.d.ts +111 -0
  119. package/src/lib/model/ai-site-context.js +222 -0
  120. package/src/lib/model/ai-site-context.js.map +1 -0
  121. package/src/lib/model/ai-site-job.d.ts +10 -2
  122. package/src/lib/model/ai-site-job.js +12 -5
  123. package/src/lib/model/ai-site-job.js.map +1 -1
  124. package/src/lib/model/ai-site-kinds.d.ts +164 -0
  125. package/src/lib/model/ai-site-kinds.js +1942 -0
  126. package/src/lib/model/ai-site-kinds.js.map +1 -0
  127. package/src/lib/model/ai-site-look.d.ts +150 -0
  128. package/src/lib/model/ai-site-look.js +1236 -0
  129. package/src/lib/model/ai-site-look.js.map +1 -0
  130. package/src/lib/model/ai-site-memory.d.ts +80 -0
  131. package/src/lib/model/ai-site-memory.js +171 -0
  132. package/src/lib/model/ai-site-memory.js.map +1 -0
  133. package/src/lib/model/ai-site-start.d.ts +10 -1
  134. package/src/lib/model/ai-site-start.js +16 -2
  135. package/src/lib/model/ai-site-start.js.map +1 -1
  136. package/src/lib/model/assist-follow-up.d.ts +92 -0
  137. package/src/lib/model/assist-follow-up.js +128 -0
  138. package/src/lib/model/assist-follow-up.js.map +1 -0
  139. package/src/lib/plugin-config.js +2 -0
  140. package/src/lib/plugin-config.js.map +1 -1
  141. package/src/lib/plugin.js +20 -1
  142. package/src/lib/plugin.js.map +1 -1
  143. package/src/lib/providers/anthropic.d.ts +9 -1
  144. package/src/lib/providers/anthropic.js +143 -9
  145. package/src/lib/providers/anthropic.js.map +1 -1
  146. package/src/lib/providers/catalog.d.ts +37 -7
  147. package/src/lib/providers/catalog.js +103 -11
  148. package/src/lib/providers/catalog.js.map +1 -1
  149. package/src/lib/providers/contract.d.ts +29 -0
  150. package/src/lib/providers/contract.js.map +1 -1
  151. package/src/lib/providers/image-contract.d.ts +22 -1
  152. package/src/lib/providers/image-contract.js +40 -1
  153. package/src/lib/providers/image-contract.js.map +1 -1
  154. package/src/lib/providers/image-endpoints.d.ts +24 -0
  155. package/src/lib/providers/image-endpoints.js +28 -0
  156. package/src/lib/providers/image-endpoints.js.map +1 -0
  157. package/src/lib/providers/model-choice.js +23 -2
  158. package/src/lib/providers/model-choice.js.map +1 -1
  159. package/src/lib/providers/routing.js +18 -0
  160. package/src/lib/providers/routing.js.map +1 -1
  161. package/src/lib/providers/vertex-image-endpoint.d.ts +48 -0
  162. package/src/lib/providers/vertex-image-endpoint.js +80 -0
  163. package/src/lib/providers/vertex-image-endpoint.js.map +1 -0
  164. package/src/lib/providers/vertex-image.d.ts +13 -27
  165. package/src/lib/providers/vertex-image.js +15 -42
  166. package/src/lib/providers/vertex-image.js.map +1 -1
  167. package/src/lib/runtime/ai-blog-post-generation.d.ts +62 -0
  168. package/src/lib/runtime/ai-blog-post-generation.js +89 -0
  169. package/src/lib/runtime/ai-blog-post-generation.js.map +1 -0
  170. package/src/lib/runtime/ai-dev-env.d.ts +53 -0
  171. package/src/lib/runtime/ai-dev-env.js +72 -0
  172. package/src/lib/runtime/ai-dev-env.js.map +1 -0
  173. package/src/lib/runtime/ai-dev-replay.d.ts +116 -0
  174. package/src/lib/runtime/ai-dev-replay.js +313 -0
  175. package/src/lib/runtime/ai-dev-replay.js.map +1 -0
  176. package/src/lib/runtime/ai-doctrine.js +5 -1
  177. package/src/lib/runtime/ai-doctrine.js.map +1 -1
  178. package/src/lib/runtime/ai-eval-live.js +4 -0
  179. package/src/lib/runtime/ai-eval-live.js.map +1 -1
  180. package/src/lib/runtime/ai-eval.d.ts +13 -1
  181. package/src/lib/runtime/ai-eval.js +84 -1
  182. package/src/lib/runtime/ai-eval.js.map +1 -1
  183. package/src/lib/runtime/ai-live-batch.d.ts +45 -0
  184. package/src/lib/runtime/ai-live-batch.js +89 -0
  185. package/src/lib/runtime/ai-live-batch.js.map +1 -0
  186. package/src/lib/runtime/ai-runtime.js +46 -2
  187. package/src/lib/runtime/ai-runtime.js.map +1 -1
  188. package/src/lib/runtime/site-context.d.ts +58 -0
  189. package/src/lib/runtime/site-context.js +127 -0
  190. package/src/lib/runtime/site-context.js.map +1 -0
  191. package/src/lib/server/ai-admin-conversations.d.ts +22 -0
  192. package/src/lib/server/ai-admin-conversations.js +197 -0
  193. package/src/lib/server/ai-admin-conversations.js.map +1 -0
  194. package/src/lib/server/ai-media-image.d.ts +5 -5
  195. package/src/lib/server/ai-media-image.js +25 -11
  196. package/src/lib/server/ai-media-image.js.map +1 -1
  197. package/src/lib/server/ai-media-raster-prompt.d.ts +34 -0
  198. package/src/lib/server/ai-media-raster-prompt.js +53 -0
  199. package/src/lib/server/ai-media-raster-prompt.js.map +1 -0
  200. package/src/lib/server/assist-chat.d.ts +11 -0
  201. package/src/lib/server/assist-chat.js +57 -18
  202. package/src/lib/server/assist-chat.js.map +1 -1
  203. package/src/lib/server/assist-edit-applied.js +16 -3
  204. package/src/lib/server/assist-edit-applied.js.map +1 -1
  205. package/src/lib/server/assist-view-context.d.ts +19 -1
  206. package/src/lib/server/assist-view-context.js +38 -1
  207. package/src/lib/server/assist-view-context.js.map +1 -1
  208. package/src/lib/server.js +10 -0
  209. package/src/lib/server.js.map +1 -1
  210. package/src/lib/subprocessors.js +17 -1
  211. package/src/lib/subprocessors.js.map +1 -1
  212. package/src/lib/tools/ai-blog-post-tool.d.ts +60 -0
  213. package/src/lib/tools/ai-blog-post-tool.js +175 -0
  214. package/src/lib/tools/ai-blog-post-tool.js.map +1 -0
  215. package/src/lib/usage/assist-usage.d.ts +3 -0
  216. package/src/lib/usage/assist-usage.js +4 -2
  217. package/src/lib/usage/assist-usage.js.map +1 -1
  218. package/src/lib/usage/staff-org-ai-conversations.d.ts +103 -0
  219. package/src/lib/usage/staff-org-ai-conversations.js +152 -0
  220. package/src/lib/usage/staff-org-ai-conversations.js.map +1 -0
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../../../libs/plugins/ai/src/lib/components/ai-site-start-card.component.tsx"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n'use client'\n\nimport { lockdownRefusalText, parseLockdownRefusal, PLATFORM_BRAND_NAME } from '@aglyn/aglyn'\nimport { trackEvent } from '@aglyn/aglyn/app-utils/analytics-events'\nimport type { ConsoleHostFirstRunZoneProps } from '@aglyn/aglyn/plugin-manager/feature-plugins'\nimport { ICON_VARIANT_CLOSE } from '@aglyn/shared-data-enums'\nimport {\n mdiCheckCircle,\n mdiCreation,\n mdiInformationOutline,\n mdiPageLayoutHeaderFooter,\n} from '@aglyn/shared-data-mdi'\nimport { MdiIcon } from '@aglyn/shared-ui-jsx'\nimport { authorizedFetch } from '@aglyn/shared-util-http/authorized-token'\nimport { useUser } from '@aglyn/tenant-feature-instance'\nimport {\n Alert,\n AppBar,\n Box,\n Button,\n Card,\n CardActionArea,\n Chip,\n CircularProgress,\n Container,\n Dialog,\n DialogActions,\n DialogContent,\n IconButton,\n MenuItem,\n Stack,\n Step,\n StepLabel,\n Stepper,\n TextField,\n Toolbar,\n Tooltip,\n Typography,\n} from '@mui/material'\nimport { alpha, type Theme } from '@mui/material/styles'\nimport { useRouter } from 'next/navigation'\nimport { useCallback, useEffect, useId, useRef, useState, type ReactNode } from 'react'\nimport {\n AI_JOB_AUTO_CONFIRM_INPUT,\n AI_SITE_FREE_PAGES,\n AI_SITE_FREE_PAGES_NOTE,\n AI_SITE_SUBMISSION_CHOICES,\n aiFreeSiteCreditEstimate,\n aiSiteCreditEstimate,\n aiSitePagesBand,\n type AiSiteSubmissions,\n} from '../model/ai-site-job'\nimport { FREE_AI_TASTE_CREDITS_PER_MONTH } from '../plan-entitlements'\nimport {\n AI_SITE_START_ANSWERS,\n AI_SITE_START_EXAMPLES,\n AI_SITE_START_TYPES,\n aiSiteStartBrief,\n aiSiteStartInputs,\n aiSiteStartRefusal,\n type AiSiteStartAnswers,\n} from '../model/ai-site-start'\nimport type { AiJobSummary } from '../model/ai-jobs.types'\nimport { AiJobFollow } from './ai-job-follow.component'\nimport { aiSiteBuildHref } from './ai-job-links'\nimport { publishAiJob } from './ai-jobs-store'\n\n/**\n * The guided start (AGL-2918), on the `hostFirstRun` zone of the page a newly\n * created site lands on: a choice, a few questions, and the site scaffold they\n * become.\n *\n * ── Two steps (AGL-3594) ─────────────────────────────────────────────────\n *\n * Step 1 asks how to start, as two equal cards: the starter site — a\n * ready-made home page with a header and footer — or AI. The starter card is\n * the zone's `startBlank`, which gives a site born for the guided start the\n * starter every other new site is born with. The AI card moves to step 2, the\n * questions, which have a Back to step 1.\n *\n * ── A full screen dialog, and therefore three ways out ───────────────────\n *\n * The questions take the whole screen, which is the only presentation that\n * gets them read — but a surface that takes the screen and cannot be left is\n * a funnel, so leaving is drawn first and works three ways on both steps:\n *\n * - the close control at the start of the header,\n * - \"Skip\" at the end of it, named \"Skip and start blank\",\n * - Escape, which `Dialog` reports through `onClose`.\n *\n * Before a job is started all three are the zone's own `startBlank`: the\n * starter site, and no job, no draft, no record of a site half begun. After,\n * they close through `leave`, and the job builds the site.\n *\n * The header is the dialog's own chrome rather than part of its body, so the\n * way out cannot be scrolled off, and it is never disabled — least of all\n * while a request is in flight, which is the moment a person most wants it.\n * Nothing is focused ahead of the dialog's own frame, so the first thing a\n * keyboard reaches is the close control.\n *\n * ── It is absent until the route has answered ────────────────────────────\n *\n * The dialog covers the page, so being drawn on a guess is worse here than it\n * is for a card: it would be a takeover every flag-off workspace watches\n * disappear. Nothing renders at all — no `Dialog`, no portal — until the jobs\n * route has admitted this workspace, and a 404, a 403 or an unreachable route\n * is this widget staying absent and the ordinary blank page being all there\n * is. That the widget is mounted is itself the last of a stack of gates: the\n * shell held the plan's `aiGenerative` entitlement, the site's AI switch and\n * the reader's `ai.generate` first. A lockdown is the start door's to say,\n * here, in its own words.\n *\n * ── It asks, it does not build ───────────────────────────────────────────\n *\n * \"Plan my site\" starts a `site` job, which PLANS first: the pages, their\n * addresses, the navigation, the layout, the contact form and a palette, with\n * an estimated cost beside the button that confirms it. Nothing is built\n * until the person confirms that plan, and everything it then builds is an\n * unpublished draft.\n *\n * ── It stays with the job (AGL-3593) ─────────────────────────────────────\n *\n * Once the job exists the dialog follows it live — planning, the plan with\n * its Confirm, building, then the draft pages to open — so a person never has\n * to leave it to get their site built. \"Open AI jobs\" follows the job in the\n * Assist panel instead; it leaves the guided start the way every other exit\n * does, because the dialog covers the panel it opens.\n */\n\ntype Verdict = 'checking' | 'ready' | 'hidden'\n\ntype Step = 'choose' | 'describe'\n\n/** Labels the dialog for a reader, from its own heading. */\nconst TITLE_ID = 'ai-site-start-title'\n\n/**\n * The takeover's surface, for its paper, its bar and its footer alike: the\n * console page's own background (AGL-3596). The paper sits at elevation 0,\n * which is what keeps MUI's dark-mode elevation overlay off it.\n */\nexport const AI_SITE_START_SURFACE_SX = { bgcolor: 'background.default' } as const\n\n/** The two steps, as the indicator under the header names them. */\nconst STEP_LABELS = ['Choose', 'Describe'] as const\n\n/** The soft round badge an icon sits in, in its accent's tint. */\nfunction IconBadge({ accent, children }: { accent: 'primary' | 'secondary'; children: ReactNode }) {\n return (\n <Box\n aria-hidden\n sx={(theme: Theme) => ({\n width: theme.spacing(9),\n height: theme.spacing(9),\n borderRadius: '50%',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n bgcolor: alpha(theme.palette[accent].main, theme.palette.mode === 'dark' ? 0.24 : 0.12),\n color: `${accent}.main`,\n fontSize: theme.spacing(5.5),\n })}\n >\n {children}\n </Box>\n )\n}\n\n/**\n * One way to start, as a card the whole of which is the button. Its accessible\n * name is its title; its description describes it.\n */\nfunction ChoiceCard({\n accent,\n icon,\n iconId,\n title,\n description,\n busy = false,\n onChoose,\n children,\n}: {\n accent: 'primary' | 'secondary'\n icon: string\n /** Names the icon for a reader of the markup; the icon itself is decorative. */\n iconId: string\n title: string\n description: string\n busy?: boolean\n onChoose: () => void\n children?: ReactNode\n}) {\n const id = useId()\n return (\n <Card\n variant=\"outlined\"\n sx={(theme: Theme) => ({\n borderRadius: 2,\n height: '100%',\n transition: theme.transitions.create(['border-color', 'box-shadow', 'transform'], {\n duration: theme.transitions.duration.shorter,\n }),\n '&:hover, &:focus-within': {\n borderColor: `${accent}.main`,\n boxShadow: theme.shadows[4],\n transform: `translateY(-${theme.spacing(0.25)})`,\n },\n '@media (prefers-reduced-motion: reduce)': {\n transition: 'none',\n '&:hover, &:focus-within': { transform: 'none' },\n },\n })}\n >\n <CardActionArea\n onClick={onChoose}\n disabled={busy}\n aria-labelledby={`${id}-title`}\n aria-describedby={`${id}-description`}\n aria-busy={busy || undefined}\n sx={{ height: '100%', p: { xs: 3, sm: 4 } }}\n >\n <Stack spacing={2} sx={{ alignItems: 'center', textAlign: 'center' }}>\n <IconBadge accent={accent}>\n {busy ? (\n <CircularProgress size=\"1em\" color={accent} aria-label={`${title}…`} />\n ) : (\n <MdiIcon path={icon} data-icon={iconId} aria-hidden />\n )}\n </IconBadge>\n <Typography id={`${id}-title`} variant=\"h6\" component=\"h2\">\n {title}\n </Typography>\n <Typography id={`${id}-description`} variant=\"body2\" color=\"text.secondary\">\n {description}\n </Typography>\n {children}\n </Stack>\n </CardActionArea>\n </Card>\n )\n}\n\n/** A small label above a group of questions. */\nfunction SectionLabel({ children }: { children: ReactNode }) {\n return (\n <Typography variant=\"overline\" color=\"text.secondary\" component=\"h2\" sx={{ display: 'block' }}>\n {children}\n </Typography>\n )\n}\n\n/**\n * The guided start, as the `hostFirstRun` zone draws it, or reopened on a\n * failed start's own answers (AGL-3596): `initialAnswers` opens it on the\n * questions, filled in, for the person to adjust and start a fresh job.\n */\nexport type AiSiteStartCardProps = ConsoleHostFirstRunZoneProps & {\n initialAnswers?: AiSiteStartAnswers | null\n}\n\nexport function AiSiteStartCard({\n hostId,\n orgId,\n orgSlug,\n host,\n startBlank,\n leave,\n initialAnswers = null,\n}: AiSiteStartCardProps) {\n const { data: user } = useUser()\n const router = useRouter()\n // Held in a ref so a request reads WHO is signed in, never the identity of\n // the object that says so.\n const userRef = useRef(user)\n userRef.current = user\n const uid = user?.uid ?? null\n const [verdict, setVerdict] = useState<Verdict>('checking')\n // Read once: a start reopened on its answers stays one while it is open.\n const reopened = useRef(initialAnswers !== null)\n const [step, setStep] = useState<Step>(initialAnswers ? 'describe' : 'choose')\n const [answers, setAnswers] = useState<AiSiteStartAnswers>(initialAnswers ?? AI_SITE_START_ANSWERS)\n const [busy, setBusy] = useState(false)\n // The starter card's own busy state while `startBlank` runs (AGL-3594).\n const [startingStarter, setStartingStarter] = useState(false)\n const [notice, setNotice] = useState<string | null>(null)\n /** The site job \"Plan my site\" started, as the create door answered with it. */\n const [started, setStarted] = useState<AiJobSummary | null>(null)\n // The Free taste's page band (AGL-3594), read off the verdict request.\n const [freeTaste, setFreeTaste] = useState(false)\n\n useEffect(() => {\n if (!orgId || !uid) return\n let active = true\n void (async () => {\n try {\n const response = await authorizedFetch(\n userRef.current,\n `/api/ai/jobs?orgId=${encodeURIComponent(orgId)}&limit=1`,\n )\n const payload = response.ok ? await response.json().catch(() => null) : null\n if (active) {\n if (payload?.freeTaste === true) {\n setFreeTaste(true)\n // A reopened start keeps the pages it asked for, within the band.\n setAnswers((current) => ({\n ...current,\n pages: reopened.current ? Math.min(current.pages, AI_SITE_FREE_PAGES.max) : AI_SITE_FREE_PAGES.max,\n welcomeEmail: false,\n }))\n }\n setVerdict(response.status === 404 || response.status === 403 ? 'hidden' : 'ready')\n }\n } catch {\n if (active) setVerdict('hidden')\n }\n })()\n return () => {\n active = false\n }\n }, [orgId, uid])\n\n const answer = useCallback(\n (patch: Partial<AiSiteStartAnswers>) =>\n setAnswers((current) => ({ ...current, ...patch })),\n [],\n )\n\n const refusal = aiSiteStartRefusal(answers, { freeTaste })\n const band = aiSitePagesBand(freeTaste)\n\n const plan = useCallback(async () => {\n if (!orgId || aiSiteStartRefusal(answers, { freeTaste })) return\n setBusy(true)\n setNotice(null)\n try {\n const response = await authorizedFetch(userRef.current, '/api/ai/jobs', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n orgId,\n hostId,\n kind: 'site',\n brief: aiSiteStartBrief(answers),\n // The guided start confirms its own plan (AGL-3594): the build\n // follows the plan with no approval to make.\n inputs: { ...aiSiteStartInputs(answers), [AI_JOB_AUTO_CONFIRM_INPUT]: true },\n }),\n })\n const payload = await response.json().catch(() => null)\n if (!response.ok) {\n const locked = parseLockdownRefusal(response.status, payload)\n setNotice(\n locked\n ? lockdownRefusalText(locked)\n : String(payload?.error ?? 'The site could not be started. Try again.'),\n )\n return\n }\n const created = (payload?.job as AiJobSummary | undefined) ?? null\n if (!created) {\n setNotice('The site could not be started. Try again.')\n return\n }\n // The indicator and the launcher count it from the moment it exists.\n publishAiJob(created)\n // Where the next step is (AGL-3594): the site's \"Building your site\"\n // page for this job. The zone closes without the starter first, so the\n // setup page does not ask again behind it.\n const href = aiSiteBuildHref(orgSlug, host, created.id)\n if (href) {\n ;(leave ?? (() => undefined))()\n router.push(href)\n return\n }\n setStarted(created)\n } catch {\n setNotice('The site could not be started. Try again.')\n } finally {\n setBusy(false)\n }\n }, [orgId, hostId, answers, freeTaste, orgSlug, host, leave, router])\n\n const chooseStarter = useCallback(() => {\n setStartingStarter(true)\n trackEvent('site_start_choice', { choice: 'starter' })\n startBlank()\n }, [startBlank])\n\n const chooseAi = useCallback(() => {\n trackEvent('site_start_choice', { choice: 'ai' })\n setStep('describe')\n }, [])\n\n if (verdict !== 'ready') return null\n\n // Before a job is started every way out is the blank site, which writes the\n // starter (AGL-3594); after, it only closes — the job builds the site.\n const exit = started ? (leave ?? startBlank) : startBlank\n\n const estimate = freeTaste\n ? aiFreeSiteCreditEstimate(answers.pages)\n : aiSiteCreditEstimate(answers.pages, {\n welcomeEmail: answers.welcomeEmail,\n })\n const estimateText = freeTaste\n ? `Up to about ${estimate.toLocaleString('en-US')} of the ${FREE_AI_TASTE_CREDITS_PER_MONTH} AI credits your Free workspace has each month`\n : `About ${estimate.toLocaleString('en-US')} credits, estimated`\n\n const choosing = step === 'choose' && !started\n\n return (\n <Dialog\n open\n fullScreen\n onClose={exit}\n aria-labelledby={TITLE_ID}\n // The console's own page surface, in both modes. A Dialog's paper sits\n // at elevation 24 by default, and in dark mode MUI lightens an elevated\n // paper with a white overlay, which turned the whole takeover a\n // washed-out gray; the overlay is for floating surfaces, and this one\n // fills the screen, so its paper is flat.\n slotProps={{ paper: { elevation: 0, sx: AI_SITE_START_SURFACE_SX } }}\n >\n {/*\n The way out, before anything it is a way out of: a slim header on the\n paper surface. On a narrow screen it is the TITLE that gives way, so\n the exits keep their words at every width.\n */}\n <AppBar\n position=\"relative\"\n color=\"inherit\"\n elevation={0}\n enableColorOnDark\n sx={{ ...AI_SITE_START_SURFACE_SX, borderBottom: 1, borderColor: 'divider' }}\n >\n <Toolbar variant=\"dense\" sx={{ gap: 1 }}>\n <IconButton\n edge=\"start\"\n color=\"inherit\"\n onClick={exit}\n aria-label=\"Close the guided start\"\n >\n <MdiIcon path={ICON_VARIANT_CLOSE.path} />\n </IconButton>\n <Typography\n id={TITLE_ID}\n variant=\"subtitle1\"\n component=\"div\"\n noWrap\n sx={{ textOverflow: 'ellipsis', flex: 1 }}\n >\n {'Start your site'}\n </Typography>\n <Button color=\"inherit\" onClick={exit} aria-label={started ? 'Close' : 'Skip and start blank'}>\n {started ? 'Close' : 'Skip'}\n </Button>\n </Toolbar>\n </AppBar>\n <DialogContent sx={{ px: { xs: 2, sm: 3 } }}>\n <Container maxWidth={choosing ? 'md' : 'sm'} disableGutters sx={{ py: { xs: 3, sm: 5 } }}>\n <Stack spacing={4}>\n <Stepper\n activeStep={choosing ? 0 : 1}\n aria-label={choosing ? 'Step 1 of 2' : 'Step 2 of 2'}\n sx={{ maxWidth: (theme: Theme) => theme.spacing(40), width: '100%', mx: 'auto' }}\n >\n {STEP_LABELS.map((label) => (\n <Step key={label}>\n <StepLabel>{label}</StepLabel>\n </Step>\n ))}\n </Stepper>\n <Stack spacing={1} sx={{ textAlign: choosing ? 'center' : 'left' }}>\n <Typography variant=\"h4\" component=\"h1\">\n {choosing ? 'How do you want to start?' : 'Tell us about your site'}\n </Typography>\n <Typography variant=\"body1\" color=\"text.secondary\">\n {choosing\n ? 'You can change everything later.'\n : `A few answers and ${PLATFORM_BRAND_NAME} AI plans and writes your pages, then publishes your site.`}\n </Typography>\n </Stack>\n {notice && <Alert severity=\"info\">{notice}</Alert>}\n {choosing ? (\n <Box\n sx={{\n display: 'grid',\n gridTemplateColumns: { xs: '1fr', sm: '1fr 1fr' },\n gap: 3,\n }}\n >\n <ChoiceCard\n accent=\"secondary\"\n icon={mdiPageLayoutHeaderFooter.path}\n iconId=\"page-layout-header-footer\"\n title=\"Start from the starter site\"\n description=\"A ready-made home page with a header, footer and contact form you can edit.\"\n busy={startingStarter}\n onChoose={chooseStarter}\n />\n <ChoiceCard\n accent=\"primary\"\n icon={mdiCreation.path}\n iconId=\"creation\"\n title=\"Start with AI\"\n description={`Answer a few questions and ${PLATFORM_BRAND_NAME} AI plans your pages.`}\n onChoose={chooseAi}\n >\n <Chip size=\"small\" color=\"primary\" label=\"Recommended\" />\n {freeTaste && (\n <Typography variant=\"caption\" color=\"text.secondary\">\n {`Up to ${AI_SITE_FREE_PAGES.max} pages on the Free plan`}\n </Typography>\n )}\n </ChoiceCard>\n </Box>\n ) : started && orgId ? (\n <Card variant=\"outlined\" sx={{ borderRadius: 2, p: { xs: 2, sm: 3 } }}>\n <AiJobFollow\n job={started}\n orgId={orgId}\n orgSlug={orgSlug}\n user={user}\n intro={\n 'Your site is being planned. Review the plan here or in AI jobs, and confirm ' +\n 'it to build — nothing is built, and nothing is published, until you do.'\n }\n // Full screen: AI jobs opens in the panel this dialog covers.\n onOpenJobs={exit}\n />\n </Card>\n ) : (\n <>\n <Stack spacing={2} component=\"section\" aria-label=\"Your business\">\n <SectionLabel>{'Your business'}</SectionLabel>\n <TextField\n fullWidth\n required\n label=\"What kind of site are you creating?\"\n placeholder=\"a neighborhood dog groomer that takes bookings\"\n value={answers.siteType}\n onChange={(event) => answer({ siteType: event.target.value })}\n helperText=\"A few words is enough, or pick one below.\"\n />\n <Box sx={{ display: 'flex', flexWrap: 'wrap', gap: 1 }}>\n {AI_SITE_START_TYPES.map((type) => (\n <Chip\n key={type}\n label={type}\n size=\"small\"\n color={answers.siteType === type ? 'primary' : 'default'}\n variant={answers.siteType === type ? 'filled' : 'outlined'}\n onClick={() => answer({ siteType: type })}\n />\n ))}\n </Box>\n <TextField\n fullWidth\n label=\"Who is it for?\"\n placeholder=\"local dog owners who want a regular groom booked online\"\n value={answers.audience}\n onChange={(event) => answer({ audience: event.target.value })}\n helperText=\"Optional. It narrows who the pages are written for.\"\n />\n </Stack>\n <Stack spacing={2} component=\"section\" aria-label=\"Look & layout\">\n <SectionLabel>{'Look & layout'}</SectionLabel>\n <Typography variant=\"body2\" color=\"text.secondary\">\n {'Optional. Picking one steers the shape of the site, not its words.'}\n </Typography>\n <Box\n sx={{\n display: 'grid',\n gridTemplateColumns: { xs: '1fr', sm: '1fr 1fr' },\n gap: 2,\n }}\n >\n {AI_SITE_START_EXAMPLES.map((example) => {\n const selected = answers.example === example.id\n return (\n <Card\n key={example.id}\n variant=\"outlined\"\n sx={(theme: Theme) => ({\n borderRadius: 2,\n borderColor: selected ? 'primary.main' : 'divider',\n bgcolor: selected ? alpha(theme.palette.primary.main, 0.08) : 'transparent',\n })}\n >\n <CardActionArea\n aria-pressed={selected}\n aria-label={`${example.label} — ${example.blurb}`}\n onClick={() => answer({ example: selected ? null : example.id })}\n sx={{ p: 2, height: '100%' }}\n >\n <Stack direction=\"row\" spacing={1.5} sx={{ alignItems: 'flex-start' }}>\n <Box sx={{ flex: 1, minWidth: 0 }}>\n <Typography variant=\"subtitle2\">{example.label}</Typography>\n <Typography variant=\"body2\" color=\"text.secondary\">\n {example.blurb}\n </Typography>\n </Box>\n {selected && (\n <Box sx={{ color: 'primary.main', display: 'flex' }} aria-hidden>\n <MdiIcon path={mdiCheckCircle.path} />\n </Box>\n )}\n </Stack>\n </CardActionArea>\n </Card>\n )\n })}\n </Box>\n </Stack>\n <Stack spacing={2} component=\"section\" aria-label=\"Details\">\n <SectionLabel>{'Details'}</SectionLabel>\n {/*\n The one setting a new site owner has to make, asked where\n they are already answering: a contact form nobody routed\n files its messages somewhere the person has not looked.\n */}\n <TextField\n select\n fullWidth\n label=\"Where do form submissions go?\"\n value={answers.submissions}\n onChange={(event) =>\n answer({ submissions: event.target.value as AiSiteSubmissions })\n }\n helperText=\"You can change this on the form itself afterwards.\"\n >\n {AI_SITE_SUBMISSION_CHOICES.map((option) => (\n <MenuItem key={option.id} value={option.id}>\n {`${option.label} — ${option.blurb}`}\n </MenuItem>\n ))}\n </TextField>\n <Stack direction={{ xs: 'column', sm: 'row' }} spacing={2}>\n <TextField\n select\n fullWidth\n label=\"Pages\"\n value={answers.pages}\n onChange={(event) => answer({ pages: Number(event.target.value) })}\n helperText={freeTaste ? AI_SITE_FREE_PAGES_NOTE : undefined}\n >\n {Array.from(\n { length: band.max - band.min + 1 },\n (_, index) => band.min + index,\n ).map((count) => (\n <MenuItem key={count} value={count}>\n {count}\n </MenuItem>\n ))}\n </TextField>\n {!freeTaste && (\n <TextField\n select\n fullWidth\n label=\"Welcome email\"\n value={answers.welcomeEmail ? 'yes' : 'no'}\n onChange={(event) => answer({ welcomeEmail: event.target.value === 'yes' })}\n >\n <MenuItem value=\"yes\">{'Draft one'}</MenuItem>\n <MenuItem value=\"no\">{'No'}</MenuItem>\n </TextField>\n )}\n </Stack>\n </Stack>\n </>\n )}\n </Stack>\n </Container>\n </DialogContent>\n {step === 'describe' && !started && (\n /* The footer stays put while the questions scroll. It wraps, because\n the estimate, the reason and the buttons are wider than a phone. */\n <DialogActions\n sx={{\n px: { xs: 2, sm: 3 },\n py: 2,\n flexWrap: 'wrap',\n rowGap: 1,\n columnGap: 2,\n borderTop: 1,\n borderColor: 'divider',\n ...AI_SITE_START_SURFACE_SX,\n }}\n >\n <Stack direction=\"row\" spacing={0.5} sx={{ alignItems: 'center', mr: 'auto', minWidth: 0 }}>\n <Typography variant=\"body2\" color=\"text.secondary\">\n {`${estimateText}.`}\n </Typography>\n <Tooltip title=\"What it really costs is what each step spends, and you can watch that add up while it runs.\">\n <Box\n component=\"span\"\n tabIndex={0}\n aria-label=\"How the estimate works\"\n sx={{ display: 'inline-flex', color: 'text.secondary' }}\n >\n <MdiIcon path={mdiInformationOutline.path} fontSize=\"small\" />\n </Box>\n </Tooltip>\n </Stack>\n {refusal && (\n <Typography variant=\"body2\" color=\"text.secondary\">\n {refusal}\n </Typography>\n )}\n <Button onClick={() => setStep('choose')}>{'Back'}</Button>\n <Button\n variant=\"contained\"\n size=\"large\"\n disabled={busy || Boolean(refusal)}\n onClick={plan}\n startIcon={<MdiIcon path={mdiCreation.path} />}\n >\n {busy ? 'Starting…' : 'Plan my site'}\n </Button>\n </DialogActions>\n )}\n </Dialog>\n )\n}\n\nexport default AiSiteStartCard\n"],"names":["lockdownRefusalText","parseLockdownRefusal","PLATFORM_BRAND_NAME","trackEvent","ICON_VARIANT_CLOSE","mdiCheckCircle","mdiCreation","mdiInformationOutline","mdiPageLayoutHeaderFooter","MdiIcon","authorizedFetch","useUser","Alert","AppBar","Box","Button","Card","CardActionArea","Chip","CircularProgress","Container","Dialog","DialogActions","DialogContent","IconButton","MenuItem","Stack","Step","StepLabel","Stepper","TextField","Toolbar","Tooltip","Typography","alpha","useRouter","useCallback","useEffect","useId","useRef","useState","AI_JOB_AUTO_CONFIRM_INPUT","AI_SITE_FREE_PAGES","AI_SITE_FREE_PAGES_NOTE","AI_SITE_SUBMISSION_CHOICES","aiFreeSiteCreditEstimate","aiSiteCreditEstimate","aiSitePagesBand","FREE_AI_TASTE_CREDITS_PER_MONTH","AI_SITE_START_ANSWERS","AI_SITE_START_EXAMPLES","AI_SITE_START_TYPES","aiSiteStartBrief","aiSiteStartInputs","aiSiteStartRefusal","AiJobFollow","aiSiteBuildHref","publishAiJob","TITLE_ID","AI_SITE_START_SURFACE_SX","bgcolor","STEP_LABELS","IconBadge","accent","children","aria-hidden","sx","theme","width","spacing","height","borderRadius","display","alignItems","justifyContent","palette","main","mode","color","fontSize","ChoiceCard","icon","iconId","title","description","busy","onChoose","id","variant","transition","transitions","create","duration","shorter","borderColor","boxShadow","shadows","transform","onClick","disabled","aria-labelledby","aria-describedby","aria-busy","undefined","p","xs","sm","textAlign","size","aria-label","path","data-icon","component","SectionLabel","AiSiteStartCard","hostId","orgId","orgSlug","host","startBlank","leave","initialAnswers","data","user","router","userRef","current","uid","verdict","setVerdict","reopened","step","setStep","answers","setAnswers","setBusy","startingStarter","setStartingStarter","notice","setNotice","started","setStarted","freeTaste","setFreeTaste","active","response","encodeURIComponent","payload","ok","json","catch","pages","Math","min","max","welcomeEmail","status","answer","patch","refusal","band","plan","method","headers","body","JSON","stringify","kind","brief","inputs","locked","String","error","created","job","href","push","chooseStarter","choice","chooseAi","exit","estimate","estimateText","toLocaleString","choosing","open","fullScreen","onClose","slotProps","paper","elevation","position","enableColorOnDark","borderBottom","gap","edge","noWrap","textOverflow","flex","px","maxWidth","disableGutters","py","activeStep","mx","map","label","severity","gridTemplateColumns","intro","onOpenJobs","fullWidth","required","placeholder","value","siteType","onChange","event","target","helperText","flexWrap","type","audience","example","selected","primary","aria-pressed","blurb","direction","minWidth","select","submissions","option","Number","Array","from","length","_","index","count","rowGap","columnGap","borderTop","mr","tabIndex","Boolean","startIcon"],"mappings":"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"}
1
+ {"version":3,"sources":["../../../../../../../libs/plugins/ai/src/lib/components/ai-site-start-card.component.tsx"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n'use client'\n\nimport { lockdownRefusalText, parseLockdownRefusal, PLATFORM_BRAND_NAME } from '@aglyn/aglyn'\nimport { trackEvent } from '@aglyn/aglyn/app-utils/analytics-events'\nimport type { ConsoleHostFirstRunZoneProps } from '@aglyn/aglyn/plugin-manager/feature-plugins'\nimport { ICON_VARIANT_CLOSE } from '@aglyn/shared-data-enums'\nimport {\n mdiAccount,\n mdiBookOpenPageVariant,\n mdiBriefcaseOutline,\n mdiCalendarHeart,\n mdiCamera,\n mdiClockOutline,\n mdiContentCut,\n mdiCreation,\n mdiDumbbell,\n mdiHandHeart,\n mdiHeartPulse,\n mdiHomeCity,\n mdiMusic,\n mdiPaletteOutline,\n mdiRocketLaunch,\n mdiScaleBalance,\n mdiSchool,\n mdiShopping,\n mdiSilverwareForkKnife,\n mdiViewGridOutline,\n mdiWrench,\n mdiYoga,\n mdiInformationOutline,\n mdiPageLayoutHeaderFooter,\n} from '@aglyn/shared-data-mdi'\nimport { MdiIcon } from '@aglyn/shared-ui-jsx'\nimport { OptionCardGrid } from '@aglyn/shared-ui-jsx/components/option-card-grid.component'\nimport { authorizedFetch } from '@aglyn/shared-util-http/authorized-token'\nimport { useUser } from '@aglyn/tenant-feature-instance'\nimport {\n Alert,\n AppBar,\n Box,\n Button,\n Card,\n CardActionArea,\n Chip,\n CircularProgress,\n Container,\n Dialog,\n DialogActions,\n DialogContent,\n IconButton,\n MenuItem,\n Stack,\n Step,\n StepLabel,\n Stepper,\n TextField,\n Toolbar,\n Tooltip,\n Typography,\n} from '@mui/material'\nimport { alpha, type Theme } from '@mui/material/styles'\nimport { useRouter } from 'next/navigation'\nimport { useCallback, useEffect, useId, useRef, useState, type ReactNode } from 'react'\nimport {\n AI_JOB_AUTO_CONFIRM_INPUT,\n AI_SITE_FREE_PAGES,\n AI_SITE_FREE_PAGES_NOTE,\n AI_SITE_SUBMISSION_CHOICES,\n aiFreeSiteCreditEstimate,\n aiSiteCreditEstimate,\n aiSitePagesBand,\n type AiSiteSubmissions,\n} from '../model/ai-site-job'\nimport { FREE_AI_TASTE_CREDITS_PER_MONTH } from '../plan-entitlements'\nimport {\n AI_SITE_START_ANSWERS,\n AI_SITE_START_TYPES,\n aiSiteStartBrief,\n aiSiteStartKind,\n aiSiteStartInputs,\n aiSiteStartRefusal,\n type AiSiteStartAnswers,\n} from '../model/ai-site-start'\nimport type { AiJobSummary } from '../model/ai-jobs.types'\nimport { AI_SITE_KINDS } from '../model/ai-site-kinds'\n\n/** The icon each kind of site's card shows. */\nconst AI_SITE_KIND_ICONS: Record<string, string> = {\n business: mdiBriefcaseOutline.path,\n trades: mdiWrench.path,\n professional: mdiScaleBalance.path,\n wellness: mdiHeartPulse.path,\n restaurant: mdiSilverwareForkKnife.path,\n store: mdiShopping.path,\n portfolio: mdiViewGridOutline.path,\n studio: mdiPaletteOutline.path,\n photography: mdiCamera.path,\n blog: mdiBookOpenPageVariant.path,\n events: mdiCalendarHeart.path,\n fitness: mdiDumbbell.path,\n yoga: mdiYoga.path,\n beauty: mdiContentCut.path,\n realestate: mdiHomeCity.path,\n education: mdiSchool.path,\n nonprofit: mdiHandHeart.path,\n music: mdiMusic.path,\n personal: mdiAccount.path,\n landing: mdiRocketLaunch.path,\n 'coming-soon': mdiClockOutline.path,\n}\nimport { AiJobFollow } from './ai-job-follow.component'\nimport { AiModelSelector } from './ai-model-selector.component'\nimport { useAiModelChoice } from './use-ai-model-choice'\nimport { aiSiteBuildHref } from './ai-job-links'\nimport { publishAiJob } from './ai-jobs-store'\n\n/**\n * The guided start (AGL-2918), on the `hostFirstRun` zone of the page a newly\n * created site lands on: a choice, a few questions, and the site scaffold they\n * become.\n *\n * ── Two steps (AGL-3594) ─────────────────────────────────────────────────\n *\n * Step 1 asks how to start, as two equal cards: the starter site — a\n * ready-made home page with a header and footer — or AI. The starter card is\n * the zone's `startBlank`, which gives a site born for the guided start the\n * starter every other new site is born with. The AI card moves to step 2, the\n * questions, which have a Back to step 1.\n *\n * ── A full screen dialog, and therefore three ways out ───────────────────\n *\n * The questions take the whole screen, which is the only presentation that\n * gets them read — but a surface that takes the screen and cannot be left is\n * a funnel, so leaving is drawn first and works three ways on both steps:\n *\n * - the close control at the start of the header,\n * - \"Skip\" at the end of it, named \"Skip and start blank\",\n * - Escape, which `Dialog` reports through `onClose`.\n *\n * Before a job is started all three are the zone's own `startBlank`: the\n * starter site, and no job, no draft, no record of a site half begun. After,\n * they close through `leave`, and the job builds the site.\n *\n * The header is the dialog's own chrome rather than part of its body, so the\n * way out cannot be scrolled off, and it is never disabled — least of all\n * while a request is in flight, which is the moment a person most wants it.\n * Nothing is focused ahead of the dialog's own frame, so the first thing a\n * keyboard reaches is the close control.\n *\n * ── It is absent until the route has answered ────────────────────────────\n *\n * The dialog covers the page, so being drawn on a guess is worse here than it\n * is for a card: it would be a takeover every flag-off workspace watches\n * disappear. Nothing renders at all — no `Dialog`, no portal — until the jobs\n * route has admitted this workspace, and a 404, a 403 or an unreachable route\n * is this widget staying absent and the ordinary blank page being all there\n * is. That the widget is mounted is itself the last of a stack of gates: the\n * shell held the plan's `aiGenerative` entitlement, the site's AI switch and\n * the reader's `ai.generate` first. A lockdown is the start door's to say,\n * here, in its own words.\n *\n * ── It asks, it does not build ───────────────────────────────────────────\n *\n * \"Plan my site\" starts a `site` job, which PLANS first: the pages, their\n * addresses, the navigation, the layout, the contact form and a palette, with\n * an estimated cost beside the button that confirms it. Nothing is built\n * until the person confirms that plan, and everything it then builds is an\n * unpublished draft.\n *\n * ── It stays with the job (AGL-3593) ─────────────────────────────────────\n *\n * Once the job exists the dialog follows it live — planning, the plan with\n * its Confirm, building, then the draft pages to open — so a person never has\n * to leave it to get their site built. \"Open AI jobs\" follows the job in the\n * Assist panel instead; it leaves the guided start the way every other exit\n * does, because the dialog covers the panel it opens.\n */\n\ntype Verdict = 'checking' | 'ready' | 'hidden'\n\ntype Step = 'choose' | 'describe'\n\n/** Labels the dialog for a reader, from its own heading. */\nconst TITLE_ID = 'ai-site-start-title'\n\n/**\n * The takeover's surface, for its paper, its bar and its footer alike: the\n * console page's own background (AGL-3596). The paper sits at elevation 0,\n * which is what keeps MUI's dark-mode elevation overlay off it.\n */\nexport const AI_SITE_START_SURFACE_SX = { bgcolor: 'background.default' } as const\n\n/** The two steps, as the indicator under the header names them. */\nconst STEP_LABELS = ['Choose', 'Describe'] as const\n\n/** The soft round badge an icon sits in, in its accent's tint. */\nfunction IconBadge({ accent, children }: { accent: 'primary' | 'secondary'; children: ReactNode }) {\n return (\n <Box\n aria-hidden\n sx={(theme: Theme) => ({\n width: theme.spacing(9),\n height: theme.spacing(9),\n borderRadius: '50%',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n bgcolor: alpha(theme.palette[accent].main, theme.palette.mode === 'dark' ? 0.24 : 0.12),\n color: `${accent}.main`,\n fontSize: theme.spacing(5.5),\n })}\n >\n {children}\n </Box>\n )\n}\n\n/**\n * One way to start, as a card the whole of which is the button. Its accessible\n * name is its title; its description describes it.\n */\nfunction ChoiceCard({\n accent,\n icon,\n iconId,\n title,\n description,\n busy = false,\n onChoose,\n children,\n}: {\n accent: 'primary' | 'secondary'\n icon: string\n /** Names the icon for a reader of the markup; the icon itself is decorative. */\n iconId: string\n title: string\n description: string\n busy?: boolean\n onChoose: () => void\n children?: ReactNode\n}) {\n const id = useId()\n return (\n <Card\n variant=\"outlined\"\n sx={(theme: Theme) => ({\n borderRadius: 2,\n height: '100%',\n transition: theme.transitions.create(['border-color', 'box-shadow', 'transform'], {\n duration: theme.transitions.duration.shorter,\n }),\n '&:hover, &:focus-within': {\n borderColor: `${accent}.main`,\n boxShadow: theme.shadows[4],\n transform: `translateY(-${theme.spacing(0.25)})`,\n },\n '@media (prefers-reduced-motion: reduce)': {\n transition: 'none',\n '&:hover, &:focus-within': { transform: 'none' },\n },\n })}\n >\n <CardActionArea\n onClick={onChoose}\n disabled={busy}\n aria-labelledby={`${id}-title`}\n aria-describedby={`${id}-description`}\n aria-busy={busy || undefined}\n sx={{ height: '100%', p: { xs: 3, sm: 4 } }}\n >\n <Stack spacing={2} sx={{ alignItems: 'center', textAlign: 'center' }}>\n <IconBadge accent={accent}>\n {busy ? (\n <CircularProgress size=\"1em\" color={accent} aria-label={`${title}…`} />\n ) : (\n <MdiIcon path={icon} data-icon={iconId} aria-hidden />\n )}\n </IconBadge>\n <Typography id={`${id}-title`} variant=\"h6\" component=\"h2\">\n {title}\n </Typography>\n <Typography id={`${id}-description`} variant=\"body2\" color=\"text.secondary\">\n {description}\n </Typography>\n {children}\n </Stack>\n </CardActionArea>\n </Card>\n )\n}\n\n/** A small label above a group of questions. */\nfunction SectionLabel({ children }: { children: ReactNode }) {\n return (\n <Typography variant=\"overline\" color=\"text.secondary\" component=\"h2\" sx={{ display: 'block' }}>\n {children}\n </Typography>\n )\n}\n\n/**\n * The guided start, as the `hostFirstRun` zone draws it, or reopened on a\n * failed start's own answers (AGL-3596): `initialAnswers` opens it on the\n * questions, filled in, for the person to adjust and start a fresh job.\n */\nexport type AiSiteStartCardProps = ConsoleHostFirstRunZoneProps & {\n initialAnswers?: AiSiteStartAnswers | null\n}\n\nexport function AiSiteStartCard({\n hostId,\n orgId,\n orgSlug,\n host,\n startBlank,\n leave,\n initialAnswers = null,\n}: AiSiteStartCardProps) {\n const { data: user } = useUser()\n const router = useRouter()\n // Held in a ref so a request reads WHO is signed in, never the identity of\n // the object that says so.\n const userRef = useRef(user)\n userRef.current = user\n const uid = user?.uid ?? null\n const [verdict, setVerdict] = useState<Verdict>('checking')\n // Read once: a start reopened on its answers stays one while it is open.\n const reopened = useRef(initialAnswers !== null)\n const [step, setStep] = useState<Step>(initialAnswers ? 'describe' : 'choose')\n const [answers, setAnswers] = useState<AiSiteStartAnswers>(initialAnswers ?? AI_SITE_START_ANSWERS)\n const [busy, setBusy] = useState(false)\n // The starter card's own busy state while `startBlank` runs (AGL-3594).\n const [startingStarter, setStartingStarter] = useState(false)\n const [notice, setNotice] = useState<string | null>(null)\n /** The site job \"Plan my site\" started, as the create door answered with it. */\n const [started, setStarted] = useState<AiJobSummary | null>(null)\n // The Free taste's page band (AGL-3594), read off the verdict request.\n const [freeTaste, setFreeTaste] = useState(false)\n\n useEffect(() => {\n if (!orgId || !uid) return\n let active = true\n void (async () => {\n try {\n const response = await authorizedFetch(\n userRef.current,\n `/api/ai/jobs?orgId=${encodeURIComponent(orgId)}&limit=1`,\n )\n const payload = response.ok ? await response.json().catch(() => null) : null\n if (active) {\n if (payload?.freeTaste === true) {\n setFreeTaste(true)\n // A reopened start keeps the pages it asked for, within the band.\n setAnswers((current) => ({\n ...current,\n pages: reopened.current ? Math.min(current.pages, AI_SITE_FREE_PAGES.max) : AI_SITE_FREE_PAGES.max,\n welcomeEmail: false,\n }))\n }\n setVerdict(response.status === 404 || response.status === 403 ? 'hidden' : 'ready')\n }\n } catch {\n if (active) setVerdict('hidden')\n }\n })()\n return () => {\n active = false\n }\n }, [orgId, uid])\n\n const answer = useCallback(\n (patch: Partial<AiSiteStartAnswers>) =>\n setAnswers((current) => ({ ...current, ...patch })),\n [],\n )\n\n const refusal = aiSiteStartRefusal(answers, { freeTaste })\n const band = aiSitePagesBand(freeTaste)\n // On a paid plan the person picks the model that builds the site (AGL-3660),\n // Auto by default, from the models their plan allows; every step of the job\n // runs on it. A Free workspace builds on the default and is offered none.\n const modelChoice = useAiModelChoice({ orgId, hostId, surface: 'jobs', kind: 'job.page' })\n // A pick remembered from before needs its cost to estimate by; Auto does not,\n // and the list is otherwise read when the picker opens.\n const { load: loadModels, model: rememberedModel } = modelChoice\n useEffect(() => {\n if (!freeTaste && step === 'describe' && rememberedModel) loadModels()\n }, [freeTaste, step, rememberedModel, loadModels])\n const pickedModel = freeTaste ? null : modelChoice.model\n\n const plan = useCallback(async () => {\n if (!orgId || aiSiteStartRefusal(answers, { freeTaste })) return\n setBusy(true)\n setNotice(null)\n try {\n const response = await authorizedFetch(userRef.current, '/api/ai/jobs', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n orgId,\n hostId,\n kind: 'site',\n brief: aiSiteStartBrief(answers),\n // The guided start confirms its own plan (AGL-3594): the build\n // follows the plan with no approval to make.\n inputs: { ...aiSiteStartInputs(answers), [AI_JOB_AUTO_CONFIRM_INPUT]: true },\n ...(pickedModel ? { model: pickedModel } : {}),\n }),\n })\n const payload = await response.json().catch(() => null)\n if (!response.ok) {\n const locked = parseLockdownRefusal(response.status, payload)\n setNotice(\n locked\n ? lockdownRefusalText(locked)\n : String(payload?.error ?? 'The site could not be started. Try again.'),\n )\n return\n }\n const created = (payload?.job as AiJobSummary | undefined) ?? null\n if (!created) {\n setNotice('The site could not be started. Try again.')\n return\n }\n // The indicator and the launcher count it from the moment it exists.\n publishAiJob(created)\n // Where the next step is (AGL-3594): the site's \"Building your site\"\n // page for this job. The zone closes without the starter first, so the\n // setup page does not ask again behind it.\n const href = aiSiteBuildHref(orgSlug, host, created.id)\n if (href) {\n ;(leave ?? (() => undefined))()\n router.push(href)\n return\n }\n setStarted(created)\n } catch {\n setNotice('The site could not be started. Try again.')\n } finally {\n setBusy(false)\n }\n }, [orgId, hostId, answers, freeTaste, orgSlug, host, leave, router, pickedModel])\n\n const chooseStarter = useCallback(() => {\n setStartingStarter(true)\n trackEvent('site_start_choice', { choice: 'starter' })\n startBlank()\n }, [startBlank])\n\n const chooseAi = useCallback(() => {\n trackEvent('site_start_choice', { choice: 'ai' })\n setStep('describe')\n }, [])\n\n if (verdict !== 'ready') return null\n\n // Before a job is started every way out is the blank site, which writes the\n // starter (AGL-3594); after, it only closes — the job builds the site.\n const exit = started ? (leave ?? startBlank) : startBlank\n\n // The chosen model's cost against Auto's, as the model list states it.\n const modelMultiplier =\n (pickedModel && modelChoice.options?.options.find((option) => option.id === pickedModel)?.multiplier) || 1\n const estimate = freeTaste\n ? aiFreeSiteCreditEstimate(answers.pages)\n : Math.round(\n aiSiteCreditEstimate(answers.pages, {\n welcomeEmail: answers.welcomeEmail,\n }) * modelMultiplier,\n )\n const estimateText = freeTaste\n ? `Up to about ${estimate.toLocaleString('en-US')} of the ${FREE_AI_TASTE_CREDITS_PER_MONTH} AI credits your Free workspace has each month`\n : `About ${estimate.toLocaleString('en-US')} credits, estimated`\n\n const choosing = step === 'choose' && !started\n\n return (\n <Dialog\n open\n fullScreen\n onClose={exit}\n aria-labelledby={TITLE_ID}\n // The console's own page surface, in both modes. A Dialog's paper sits\n // at elevation 24 by default, and in dark mode MUI lightens an elevated\n // paper with a white overlay, which turned the whole takeover a\n // washed-out gray; the overlay is for floating surfaces, and this one\n // fills the screen, so its paper is flat.\n slotProps={{ paper: { elevation: 0, sx: AI_SITE_START_SURFACE_SX } }}\n >\n {/*\n The way out, before anything it is a way out of: a slim header on the\n paper surface. On a narrow screen it is the TITLE that gives way, so\n the exits keep their words at every width.\n */}\n <AppBar\n position=\"relative\"\n color=\"inherit\"\n elevation={0}\n enableColorOnDark\n sx={{ ...AI_SITE_START_SURFACE_SX, borderBottom: 1, borderColor: 'divider' }}\n >\n <Toolbar variant=\"dense\" sx={{ gap: 1 }}>\n <IconButton\n edge=\"start\"\n color=\"inherit\"\n onClick={exit}\n aria-label=\"Close the guided start\"\n >\n <MdiIcon path={ICON_VARIANT_CLOSE.path} />\n </IconButton>\n <Typography\n id={TITLE_ID}\n variant=\"subtitle1\"\n component=\"div\"\n noWrap\n sx={{ textOverflow: 'ellipsis', flex: 1 }}\n >\n {'Start your site'}\n </Typography>\n <Button color=\"inherit\" onClick={exit} aria-label={started ? 'Close' : 'Skip and start blank'}>\n {started ? 'Close' : 'Skip'}\n </Button>\n </Toolbar>\n </AppBar>\n <DialogContent sx={{ px: { xs: 2, sm: 3 } }}>\n <Container maxWidth={choosing ? 'md' : 'sm'} disableGutters sx={{ py: { xs: 3, sm: 5 } }}>\n <Stack spacing={4}>\n <Stepper\n activeStep={choosing ? 0 : 1}\n aria-label={choosing ? 'Step 1 of 2' : 'Step 2 of 2'}\n sx={{ maxWidth: (theme: Theme) => theme.spacing(40), width: '100%', mx: 'auto' }}\n >\n {STEP_LABELS.map((label) => (\n <Step key={label}>\n <StepLabel>{label}</StepLabel>\n </Step>\n ))}\n </Stepper>\n <Stack spacing={1} sx={{ textAlign: choosing ? 'center' : 'left' }}>\n <Typography variant=\"h4\" component=\"h1\">\n {choosing ? 'How do you want to start?' : 'Tell us about your site'}\n </Typography>\n <Typography variant=\"body1\" color=\"text.secondary\">\n {choosing\n ? 'You can change everything later.'\n : `A few answers and ${PLATFORM_BRAND_NAME} AI plans and writes your pages, then publishes your site.`}\n </Typography>\n </Stack>\n {notice && <Alert severity=\"info\">{notice}</Alert>}\n {choosing ? (\n <Box\n sx={{\n display: 'grid',\n gridTemplateColumns: { xs: '1fr', sm: '1fr 1fr' },\n gap: 3,\n }}\n >\n <ChoiceCard\n accent=\"secondary\"\n icon={mdiPageLayoutHeaderFooter.path}\n iconId=\"page-layout-header-footer\"\n title=\"Start from the starter site\"\n description=\"A ready-made home page with a header, footer and contact form you can edit.\"\n busy={startingStarter}\n onChoose={chooseStarter}\n />\n <ChoiceCard\n accent=\"primary\"\n icon={mdiCreation.path}\n iconId=\"creation\"\n title=\"Start with AI\"\n description={`Answer a few questions and ${PLATFORM_BRAND_NAME} AI plans your pages.`}\n onChoose={chooseAi}\n >\n <Chip size=\"small\" color=\"primary\" label=\"Recommended\" />\n {freeTaste && (\n <Typography variant=\"caption\" color=\"text.secondary\">\n {`Up to ${AI_SITE_FREE_PAGES.max} pages on the Free plan`}\n </Typography>\n )}\n </ChoiceCard>\n </Box>\n ) : started && orgId ? (\n <Card variant=\"outlined\" sx={{ borderRadius: 2, p: { xs: 2, sm: 3 } }}>\n <AiJobFollow\n job={started}\n orgId={orgId}\n orgSlug={orgSlug}\n user={user}\n intro={\n 'Your site is being planned. Review the plan here or in AI jobs, and confirm ' +\n 'it to build — nothing is built, and nothing is published, until you do.'\n }\n // Full screen: AI jobs opens in the panel this dialog covers.\n onOpenJobs={exit}\n />\n </Card>\n ) : (\n <>\n <Stack spacing={2} component=\"section\" aria-label=\"Your business\">\n <SectionLabel>{'Your business'}</SectionLabel>\n <TextField\n fullWidth\n required\n label=\"What kind of site are you creating?\"\n placeholder=\"a neighborhood dog groomer that takes bookings\"\n value={answers.siteType}\n onChange={(event) => answer({ siteType: event.target.value })}\n helperText=\"A few words is enough, or pick one below.\"\n />\n <Box sx={{ display: 'flex', flexWrap: 'wrap', gap: 1 }}>\n {AI_SITE_START_TYPES.map((type) => (\n <Chip\n key={type}\n label={type}\n size=\"small\"\n color={answers.siteType === type ? 'primary' : 'default'}\n variant={answers.siteType === type ? 'filled' : 'outlined'}\n onClick={() => answer({ siteType: type })}\n />\n ))}\n </Box>\n <TextField\n fullWidth\n label=\"Who is it for?\"\n placeholder=\"local dog owners who want a regular groom booked online\"\n value={answers.audience}\n onChange={(event) => answer({ audience: event.target.value })}\n helperText=\"Optional. It narrows who the pages are written for.\"\n />\n </Stack>\n <Stack spacing={2} component=\"section\" aria-label=\"Style\">\n <SectionLabel>{'Style'}</SectionLabel>\n <Typography variant=\"body2\" color=\"text.secondary\">\n {answers.kind\n ? 'This decides how your site looks and which pages it usually has.'\n : 'Picked from your answer above. Choose another to change how your site looks and which pages it usually has.'}\n </Typography>\n <OptionCardGrid\n label=\"Style of site\"\n options={AI_SITE_KINDS.map((kind) => ({\n id: kind.id,\n title: kind.label,\n description: kind.blurb,\n icon: AI_SITE_KIND_ICONS[kind.id],\n }))}\n value={aiSiteStartKind(answers).id}\n onChange={(kind) => answer({ kind })}\n />\n </Stack>\n <Stack spacing={2} component=\"section\" aria-label=\"Details\">\n <SectionLabel>{'Details'}</SectionLabel>\n {/*\n The one setting a new site owner has to make, asked where\n they are already answering: a contact form nobody routed\n files its messages somewhere the person has not looked.\n */}\n <TextField\n select\n fullWidth\n label=\"Where do form submissions go?\"\n value={answers.submissions}\n onChange={(event) =>\n answer({ submissions: event.target.value as AiSiteSubmissions })\n }\n helperText=\"You can change this on the form itself afterwards.\"\n >\n {AI_SITE_SUBMISSION_CHOICES.map((option) => (\n <MenuItem key={option.id} value={option.id}>\n {`${option.label} — ${option.blurb}`}\n </MenuItem>\n ))}\n </TextField>\n <Stack direction={{ xs: 'column', sm: 'row' }} spacing={2}>\n <TextField\n select\n fullWidth\n label=\"Pages\"\n value={answers.pages}\n onChange={(event) => answer({ pages: Number(event.target.value) })}\n helperText={freeTaste ? AI_SITE_FREE_PAGES_NOTE : undefined}\n >\n {Array.from(\n { length: band.max - band.min + 1 },\n (_, index) => band.min + index,\n ).map((count) => (\n <MenuItem key={count} value={count}>\n {count}\n </MenuItem>\n ))}\n </TextField>\n {!freeTaste && (\n <TextField\n select\n fullWidth\n label=\"Welcome email\"\n value={answers.welcomeEmail ? 'yes' : 'no'}\n onChange={(event) => answer({ welcomeEmail: event.target.value === 'yes' })}\n >\n <MenuItem value=\"yes\">{'Draft one'}</MenuItem>\n <MenuItem value=\"no\">{'No'}</MenuItem>\n </TextField>\n )}\n </Stack>\n </Stack>\n </>\n )}\n </Stack>\n </Container>\n </DialogContent>\n {step === 'describe' && !started && (\n /* The footer stays put while the questions scroll. It wraps, because\n the estimate, the reason and the buttons are wider than a phone. */\n <DialogActions\n sx={{\n px: { xs: 2, sm: 3 },\n py: 2,\n flexWrap: 'wrap',\n rowGap: 1,\n columnGap: 2,\n borderTop: 1,\n borderColor: 'divider',\n ...AI_SITE_START_SURFACE_SX,\n }}\n >\n <Stack direction=\"row\" spacing={0.5} sx={{ alignItems: 'center', mr: 'auto', minWidth: 0 }}>\n <Typography variant=\"body2\" color=\"text.secondary\">\n {`${estimateText}.`}\n </Typography>\n <Tooltip title=\"What it really costs is what each step spends, and you can watch that add up while it runs.\">\n <Box\n component=\"span\"\n tabIndex={0}\n aria-label=\"How the estimate works\"\n sx={{ display: 'inline-flex', color: 'text.secondary' }}\n >\n <MdiIcon path={mdiInformationOutline.path} fontSize=\"small\" />\n </Box>\n </Tooltip>\n </Stack>\n {refusal && (\n <Typography variant=\"body2\" color=\"text.secondary\">\n {refusal}\n </Typography>\n )}\n {!freeTaste && <AiModelSelector choice={modelChoice} disabled={busy} />}\n <Button onClick={() => setStep('choose')}>{'Back'}</Button>\n <Button\n variant=\"contained\"\n size=\"large\"\n disabled={busy || Boolean(refusal)}\n onClick={plan}\n startIcon={<MdiIcon path={mdiCreation.path} />}\n >\n {busy ? 'Starting…' : 'Plan my site'}\n </Button>\n </DialogActions>\n )}\n </Dialog>\n )\n}\n\nexport default AiSiteStartCard\n"],"names":["lockdownRefusalText","parseLockdownRefusal","PLATFORM_BRAND_NAME","trackEvent","ICON_VARIANT_CLOSE","mdiAccount","mdiBookOpenPageVariant","mdiBriefcaseOutline","mdiCalendarHeart","mdiCamera","mdiClockOutline","mdiContentCut","mdiCreation","mdiDumbbell","mdiHandHeart","mdiHeartPulse","mdiHomeCity","mdiMusic","mdiPaletteOutline","mdiRocketLaunch","mdiScaleBalance","mdiSchool","mdiShopping","mdiSilverwareForkKnife","mdiViewGridOutline","mdiWrench","mdiYoga","mdiInformationOutline","mdiPageLayoutHeaderFooter","MdiIcon","OptionCardGrid","authorizedFetch","useUser","Alert","AppBar","Box","Button","Card","CardActionArea","Chip","CircularProgress","Container","Dialog","DialogActions","DialogContent","IconButton","MenuItem","Stack","Step","StepLabel","Stepper","TextField","Toolbar","Tooltip","Typography","alpha","useRouter","useCallback","useEffect","useId","useRef","useState","AI_JOB_AUTO_CONFIRM_INPUT","AI_SITE_FREE_PAGES","AI_SITE_FREE_PAGES_NOTE","AI_SITE_SUBMISSION_CHOICES","aiFreeSiteCreditEstimate","aiSiteCreditEstimate","aiSitePagesBand","FREE_AI_TASTE_CREDITS_PER_MONTH","AI_SITE_START_ANSWERS","AI_SITE_START_TYPES","aiSiteStartBrief","aiSiteStartKind","aiSiteStartInputs","aiSiteStartRefusal","AI_SITE_KINDS","AI_SITE_KIND_ICONS","business","path","trades","professional","wellness","restaurant","store","portfolio","studio","photography","blog","events","fitness","yoga","beauty","realestate","education","nonprofit","music","personal","landing","AiJobFollow","AiModelSelector","useAiModelChoice","aiSiteBuildHref","publishAiJob","TITLE_ID","AI_SITE_START_SURFACE_SX","bgcolor","STEP_LABELS","IconBadge","accent","children","aria-hidden","sx","theme","width","spacing","height","borderRadius","display","alignItems","justifyContent","palette","main","mode","color","fontSize","ChoiceCard","icon","iconId","title","description","busy","onChoose","id","variant","transition","transitions","create","duration","shorter","borderColor","boxShadow","shadows","transform","onClick","disabled","aria-labelledby","aria-describedby","aria-busy","undefined","p","xs","sm","textAlign","size","aria-label","data-icon","component","SectionLabel","AiSiteStartCard","hostId","orgId","orgSlug","host","startBlank","leave","initialAnswers","modelChoice","data","user","router","userRef","current","uid","verdict","setVerdict","reopened","step","setStep","answers","setAnswers","setBusy","startingStarter","setStartingStarter","notice","setNotice","started","setStarted","freeTaste","setFreeTaste","active","response","encodeURIComponent","payload","ok","json","catch","pages","Math","min","max","welcomeEmail","status","answer","patch","refusal","band","surface","kind","load","loadModels","model","rememberedModel","pickedModel","plan","method","headers","body","JSON","stringify","brief","inputs","locked","String","error","created","job","href","push","chooseStarter","choice","chooseAi","exit","modelMultiplier","options","find","option","multiplier","estimate","round","estimateText","toLocaleString","choosing","open","fullScreen","onClose","slotProps","paper","elevation","position","enableColorOnDark","borderBottom","gap","edge","noWrap","textOverflow","flex","px","maxWidth","disableGutters","py","activeStep","mx","map","label","severity","gridTemplateColumns","intro","onOpenJobs","fullWidth","required","placeholder","value","siteType","onChange","event","target","helperText","flexWrap","type","audience","blurb","select","submissions","direction","Number","Array","from","length","_","index","count","rowGap","columnGap","borderTop","mr","minWidth","tabIndex","Boolean","startIcon"],"mappings":"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"}
@@ -592,6 +592,10 @@ export function AiThemeProposalCard(props) {
592
592
  /*#__PURE__*/ _jsxs(Stack, {
593
593
  direction: "row",
594
594
  spacing: 1,
595
+ useFlexGap: true,
596
+ sx: {
597
+ flexWrap: 'wrap'
598
+ },
595
599
  children: [
596
600
  /*#__PURE__*/ _jsx(Button, {
597
601
  variant: "contained",
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../../../libs/plugins/ai/src/lib/components/ai-theme-proposal-card.component.tsx"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n'use client'\n\nimport { lockdownRefusalText, parseLockdownRefusal } from '@aglyn/aglyn'\nimport { pluginDocsHelp } from '@aglyn/aglyn/app-utils/docs-help'\nimport type { HostThemeSource } from '@aglyn/aglyn/app-utils/site-theme'\nimport type { ConsoleHostThemeZoneProps } from '@aglyn/aglyn/plugin-manager/feature-plugins'\nimport type { HostThemeScheme } from '@aglyn/shared-data-types'\nimport { CardDisplay } from '@aglyn/shared-ui-jsx'\nimport { ScrollTable } from '@aglyn/shared-ui-jsx/components/scroll-table.component'\nimport { themeEditorControl } from '@aglyn/shared-ui-theme/util/theme-editor-fields'\nimport { authorizedFetch } from '@aglyn/shared-util-http/authorized-token'\nimport { useUser } from '@aglyn/tenant-feature-instance'\nimport {\n Alert,\n Box,\n Button,\n Chip,\n CircularProgress,\n Grid,\n Stack,\n Tab,\n TableBody,\n TableCell,\n TableHead,\n TableRow,\n Tabs,\n TextField,\n ToggleButton,\n ToggleButtonGroup,\n Typography,\n} from '@mui/material'\nimport { useCallback, useEffect, useMemo, useRef, useState } from 'react'\nimport {\n AI_JOB_TERMINAL_STATUSES,\n type AiJobSummary,\n} from '../model/ai-jobs.types'\nimport {\n aiThemeColorToken,\n aiThemeProposalAfter,\n aiThemeStaleChanges,\n readAiThemeProposal,\n type AiThemeControlChange,\n type AiThemeCorrection,\n type AiThemeProposal,\n type AiThemeProposalMode,\n} from '../model/ai-theme-proposal'\nimport { readEventFrames } from './assist-jobs-drawer.component'\n\n/**\n * The theme assistant (AGL-2938), on the site's Theme section through the\n * `hostTheme` zone: a brief in, a theme proposal out, previewed before and\n * after with the editor's own preview, and put in the editor below as\n * unsaved changes when the person chooses. It never writes the theme — the\n * editor's Save does, through the same guarded path every edit takes.\n *\n * It renders nothing until the jobs route has answered for this workspace.\n * The shell has already decided the plan and the member's permission before\n * mounting it, but a released-off feature does not exist, and the release\n * flag is the route's to decide: a 404 there is this card staying absent.\n * The same read lists the site's recent proposals, so one made while the\n * person was elsewhere is still here to preview.\n */\n\n/** How many recent jobs the card reads to find this site's proposals. */\nconst RECENT_JOBS_READ = 20\n\n/** How many of this site's proposals the card offers again. */\nconst RECENT_PROPOSALS_SHOWN = 3\n\nconst BRIEF_MAX_CHARS = 4_000\n\nconst SOURCE_COPY: Record<HostThemeSource, string> = {\n installed:\n 'Saved as your changes on top of the installed theme. The publisher’s version stays as it is and can still take an update.',\n preset:\n 'Saved as your changes on top of the built-in theme, which stays as it is and can be restored.',\n custom:\n 'Saved as your changes on top of this theme of yours. Update it to keep them in the theme itself.',\n default:\n 'Only these values are stored. Everything else keeps following the default theme.',\n}\n\ntype Verdict = 'checking' | 'ready' | 'hidden'\n\nconst isTerminal = (job: AiJobSummary) => AI_JOB_TERMINAL_STATUSES.includes(job.status)\n\n/** The proposal a theme job produced, when it produced one. */\nfunction proposalOf(job: AiJobSummary | null): AiThemeProposal | null {\n const output = job?.outputs.find((entry) => entry.resource === 'theme')\n return output ? readAiThemeProposal(output.proposal) : null\n}\n\n/** A control's label, with its scheme when it has one. */\nfunction changeLabel(change: Pick<AiThemeControlChange, 'control' | 'scheme'>): string {\n return themeEditorControl(change.control).label\n}\n\nfunction Swatch({ value }: { value: string | number | null }) {\n if (value === null) {\n return (\n <Typography variant=\"caption\" color=\"text.secondary\">\n {'Default'}\n </Typography>\n )\n }\n const text = String(value)\n const color = typeof value === 'string' && /^#[0-9a-f]{6}$/i.test(value)\n return (\n <Stack direction=\"row\" spacing={1} sx={{ alignItems: 'center' }}>\n {color ? (\n <Box\n aria-hidden\n sx={{\n width: 14,\n height: 14,\n borderRadius: 0.5,\n border: 1,\n borderColor: 'divider',\n backgroundColor: text,\n flexShrink: 0,\n }}\n />\n ) : null}\n <Typography variant=\"body2\" sx={{ fontFamily: 'monospace', wordBreak: 'break-all' }}>\n {text}\n </Typography>\n </Stack>\n )\n}\n\nfunction correctionText(correction: AiThemeCorrection): string {\n const label = `${changeLabel(correction)} (${correction.scheme})`\n if (correction.reason === 'dark-value') {\n return `${label} set to ${correction.to} so the color keeps reading on the dark background.`\n }\n return (\n `${label} moved to ${correction.to} to reach ${correction.required}:1` +\n (correction.against?.length ? ` against ${correction.against.join(' and ')}` : '') +\n (correction.ratio ? ` (it was ${correction.ratio}:1).` : '.')\n )\n}\n\nexport function AiThemeProposalCard(props: ConsoleHostThemeZoneProps) {\n const { hostId, orgId, theme, themeSource, ThemePreview, proposeDraft } = props\n const { data: user } = useUser()\n // Held in a ref so the reads below key on WHO is signed in, never on the\n // identity of the object that says so.\n const userRef = useRef(user)\n userRef.current = user\n const uid = user?.uid ?? null\n\n const [verdict, setVerdict] = useState<Verdict>('checking')\n const [notice, setNotice] = useState<string | null>(null)\n const [recent, setRecent] = useState<AiJobSummary[]>([])\n const [brief, setBrief] = useState('')\n const [mode, setMode] = useState<AiThemeProposalMode>('modify')\n const [busy, setBusy] = useState(false)\n const [job, setJob] = useState<AiJobSummary | null>(null)\n const [scheme, setScheme] = useState<HostThemeScheme>('light')\n const [applied, setApplied] = useState<string | null>(null)\n const watchRef = useRef<AbortController | null>(null)\n\n useEffect(() => () => watchRef.current?.abort(), [])\n\n useEffect(() => {\n if (!orgId || !hostId || !uid) return\n let active = true\n setVerdict('checking')\n void (async () => {\n try {\n const response = await authorizedFetch(\n userRef.current,\n `/api/ai/jobs?orgId=${encodeURIComponent(orgId)}&limit=${RECENT_JOBS_READ}`,\n )\n if (!active) return\n // The flag off (404) and the plan without generation (403): the\n // feature is not this workspace's, so the card is not here at all.\n if (response.status === 404 || response.status === 403) {\n setVerdict('hidden')\n return\n }\n const payload = await response.json().catch(() => null)\n if (!active) return\n if (!response.ok) {\n const locked = parseLockdownRefusal(response.status, payload)\n setNotice(\n locked\n ? lockdownRefusalText(locked)\n : String(payload?.error ?? 'Recent theme proposals could not be loaded.'),\n )\n } else {\n const jobs = (payload?.jobs ?? []) as AiJobSummary[]\n setRecent(\n jobs\n .filter((entry) => entry.kind === 'theme' && entry.hostId === hostId)\n .filter((entry) => proposalOf(entry) !== null)\n .slice(0, RECENT_PROPOSALS_SHOWN),\n )\n }\n setVerdict('ready')\n } catch {\n if (!active) return\n setNotice('Recent theme proposals could not be loaded.')\n setVerdict('ready')\n }\n })()\n return () => {\n active = false\n }\n }, [orgId, hostId, uid])\n\n /** Follows a job through the events route until it settles. */\n const watch = useCallback(async (jobId: string, org: string) => {\n watchRef.current?.abort()\n const controller = new AbortController()\n watchRef.current = controller\n let again = true\n while (again && !controller.signal.aborted) {\n again = false\n try {\n const response = await authorizedFetch(\n userRef.current,\n `/api/ai/jobs/${encodeURIComponent(jobId)}/events?orgId=${encodeURIComponent(org)}`,\n { signal: controller.signal },\n )\n if (!response.ok || !response.body) return\n await readEventFrames(response.body, (event) => {\n if (event['type'] === 'state') setJob(event['job'] as AiJobSummary)\n else if (event['type'] === 'reconnect') again = true\n })\n } catch {\n return\n }\n }\n }, [])\n\n const propose = useCallback(async () => {\n if (!orgId || !brief.trim()) return\n setBusy(true)\n setNotice(null)\n setApplied(null)\n try {\n const response = await authorizedFetch(userRef.current, '/api/ai/jobs', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n orgId,\n hostId,\n kind: 'theme',\n brief: brief.trim(),\n inputs: { mode },\n }),\n })\n const payload = await response.json().catch(() => null)\n if (!response.ok) {\n const locked = parseLockdownRefusal(response.status, payload)\n setNotice(\n locked\n ? lockdownRefusalText(locked)\n : String(payload?.error ?? 'The theme proposal could not be started — try again.'),\n )\n return\n }\n const next = payload?.job as AiJobSummary | undefined\n if (!next) return\n setJob(next)\n if (!isTerminal(next)) await watch(next.id, orgId)\n } catch {\n setNotice('The theme proposal could not be started — try again.')\n } finally {\n setBusy(false)\n }\n }, [orgId, hostId, brief, mode, watch])\n\n const proposal = useMemo(() => proposalOf(job), [job])\n const after = useMemo(\n () => (proposal ? aiThemeProposalAfter(theme, proposal) : null),\n [theme, proposal],\n )\n const stale = useMemo(\n () => (proposal ? aiThemeStaleChanges(theme, proposal).length > 0 : false),\n [theme, proposal],\n )\n\n const apply = useCallback(() => {\n if (!job || !after) return\n proposeDraft(after.theme, job.id)\n setApplied(job.id)\n }, [job, after, proposeDraft])\n\n if (verdict !== 'ready') return null\n\n const running = Boolean(job && !isTerminal(job))\n\n return (\n <CardDisplay\n contentGutterX\n contentGutterY\n header=\"Theme assistant\"\n help={pluginDocsHelp('aiThemes', {\n excerpt:\n 'Describe the change and get a proposal for every control the editor has, previewed before and after. Nothing is saved until you save it in the editor.',\n })}\n >\n <Stack spacing={2}>\n <ToggleButtonGroup\n exclusive\n size=\"small\"\n value={mode}\n onChange={(_, value: AiThemeProposalMode | null) => value && setMode(value)}\n aria-label=\"What to propose\"\n >\n <ToggleButton value=\"modify\">{'Change what I describe'}</ToggleButton>\n <ToggleButton value=\"create\">{'Design a new theme'}</ToggleButton>\n </ToggleButtonGroup>\n <TextField\n multiline\n minRows={2}\n fullWidth\n label=\"Describe the change\"\n placeholder=\"Warmer, with a deep green primary and bigger headings on mobile\"\n helperText=\"A hex color in your description is used exactly. Paste a link to borrow a page’s colors.\"\n value={brief}\n onChange={(event) => setBrief(event.target.value.slice(0, BRIEF_MAX_CHARS))}\n disabled={busy}\n />\n <Stack direction=\"row\" spacing={1} sx={{ alignItems: 'center' }}>\n <Button variant=\"contained\" disabled={busy || !brief.trim()} onClick={() => void propose()}>\n {'Propose changes'}\n </Button>\n {running ? <CircularProgress size={18} aria-label=\"Working on a proposal\" /> : null}\n </Stack>\n {notice ? <Alert severity=\"warning\">{notice}</Alert> : null}\n\n {job && job.error && !proposal ? (\n <Alert severity={job.status === 'failed' ? 'error' : 'warning'}>{job.error}</Alert>\n ) : null}\n\n {!job && recent.length ? (\n <Stack spacing={1}>\n <Typography variant=\"subtitle2\">{'Recent proposals for this site'}</Typography>\n {recent.map((entry) => (\n <Stack key={entry.id} direction=\"row\" spacing={1} sx={{ alignItems: 'center' }}>\n <Typography variant=\"body2\" sx={{ flexGrow: 1, minWidth: 0 }} noWrap>\n {entry.brief}\n </Typography>\n <Button size=\"small\" onClick={() => setJob(entry)}>\n {'Show'}\n </Button>\n </Stack>\n ))}\n </Stack>\n ) : null}\n\n {proposal && after ? (\n <Stack spacing={2} aria-label=\"Theme proposal\">\n {proposal.summary ? <Typography variant=\"body1\">{proposal.summary}</Typography> : null}\n <Typography variant=\"body2\" color=\"text.secondary\">\n {SOURCE_COPY[proposal.source]}\n </Typography>\n {stale ? (\n <Alert severity=\"info\">\n {'The theme has changed since this proposal was made. The preview and the editor apply it to the theme as it is now.'}\n </Alert>\n ) : null}\n\n {proposal.changes.length || proposal.components.length || proposal.resetComponents ? (\n <Box>\n <ScrollTable size=\"small\" aria-label=\"Proposed changes\">\n <TableHead>\n <TableRow>\n <TableCell>{'Control'}</TableCell>\n <TableCell>{'Now'}</TableCell>\n <TableCell>{'Proposed'}</TableCell>\n </TableRow>\n </TableHead>\n <TableBody>\n {proposal.changes.map((change) => (\n <TableRow key={`${change.control}:${change.scheme ?? ''}`}>\n <TableCell>\n <Stack direction=\"row\" spacing={1} sx={{ alignItems: 'center' }}>\n <Typography variant=\"body2\">{changeLabel(change)}</Typography>\n {aiThemeColorToken(change.control) && change.scheme ? (\n <Chip size=\"small\" variant=\"outlined\" label={change.scheme} />\n ) : null}\n </Stack>\n </TableCell>\n <TableCell>\n <Swatch value={change.before} />\n </TableCell>\n <TableCell>\n <Swatch value={change.value} />\n </TableCell>\n </TableRow>\n ))}\n {proposal.resetComponents ? (\n <TableRow>\n <TableCell>{themeEditorControl('components').label}</TableCell>\n <TableCell>{'This site’s overrides'}</TableCell>\n <TableCell>{'Theme defaults'}</TableCell>\n </TableRow>\n ) : null}\n {proposal.components.map((leaf) => (\n <TableRow key={`${leaf.component}:${leaf.target}:${leaf.slot}:${leaf.media}:${leaf.property}`}>\n <TableCell>\n <Typography variant=\"body2\">\n {[\n leaf.component,\n leaf.target === 'defaultProps' ? 'default' : leaf.slot,\n leaf.property,\n ].join(' · ')}\n </Typography>\n {leaf.media ? <Chip size=\"small\" variant=\"outlined\" label={leaf.media} /> : null}\n </TableCell>\n <TableCell>{'—'}</TableCell>\n <TableCell>\n <Swatch value={typeof leaf.value === 'boolean' ? String(leaf.value) : leaf.value} />\n </TableCell>\n </TableRow>\n ))}\n </TableBody>\n </ScrollTable>\n </Box>\n ) : (\n <Typography variant=\"body2\">{'No changes proposed.'}</Typography>\n )}\n\n {[...proposal.corrections, ...after.corrections].length ? (\n <Stack spacing={0.5}>\n <Typography variant=\"subtitle2\">{'Adjusted for readability'}</Typography>\n {[...proposal.corrections, ...after.corrections].map((correction) => (\n <Typography\n key={`${correction.control}:${correction.scheme}:${correction.to}`}\n variant=\"body2\"\n >\n {correctionText(correction)}\n </Typography>\n ))}\n </Stack>\n ) : null}\n\n {[...proposal.notes, ...after.notes, ...proposal.dropped].length ? (\n <Stack spacing={0.5}>\n <Typography variant=\"subtitle2\">{'Worth knowing'}</Typography>\n {[...proposal.notes, ...after.notes].map((line) => (\n <Typography key={`note:${line}`} variant=\"body2\" color=\"text.secondary\">\n {line}\n </Typography>\n ))}\n {proposal.dropped.map((line) => (\n <Typography key={`dropped:${line}`} variant=\"body2\" color=\"text.secondary\">\n {`Left out — ${line}`}\n </Typography>\n ))}\n </Stack>\n ) : null}\n\n <Tabs\n value={scheme}\n onChange={(_, value: HostThemeScheme) => setScheme(value)}\n aria-label=\"Preview scheme\"\n >\n <Tab label=\"Light\" value=\"light\" />\n <Tab label=\"Dark\" value=\"dark\" />\n </Tabs>\n <Grid container spacing={2}>\n <Grid size={{ xs: 12, md: 6 }}>\n <Typography variant=\"subtitle2\" gutterBottom>\n {'Before'}\n </Typography>\n <Box data-preview=\"before\">\n <ThemePreview theme={theme ?? {}} scheme={scheme} />\n </Box>\n </Grid>\n <Grid size={{ xs: 12, md: 6 }}>\n <Typography variant=\"subtitle2\" gutterBottom>\n {'After'}\n </Typography>\n <Box data-preview=\"after\">\n <ThemePreview theme={after.theme} scheme={scheme} />\n </Box>\n </Grid>\n </Grid>\n\n {applied === job?.id ? (\n <Alert severity=\"success\">\n {'In the editor below as unsaved changes. Review them there, then Save — or Discard changes to go back.'}\n </Alert>\n ) : null}\n <Stack direction=\"row\" spacing={1}>\n <Button variant=\"contained\" onClick={apply} disabled={applied === job?.id}>\n {'Put in the editor'}\n </Button>\n <Button\n onClick={() => {\n setJob(null)\n setApplied(null)\n }}\n >\n {'Dismiss'}\n </Button>\n </Stack>\n </Stack>\n ) : null}\n </Stack>\n </CardDisplay>\n )\n}\nAiThemeProposalCard.displayName = 'AiThemeProposalCard'\n\nexport default AiThemeProposalCard\n"],"names":["lockdownRefusalText","parseLockdownRefusal","pluginDocsHelp","CardDisplay","ScrollTable","themeEditorControl","authorizedFetch","useUser","Alert","Box","Button","Chip","CircularProgress","Grid","Stack","Tab","TableBody","TableCell","TableHead","TableRow","Tabs","TextField","ToggleButton","ToggleButtonGroup","Typography","useCallback","useEffect","useMemo","useRef","useState","AI_JOB_TERMINAL_STATUSES","aiThemeColorToken","aiThemeProposalAfter","aiThemeStaleChanges","readAiThemeProposal","readEventFrames","RECENT_JOBS_READ","RECENT_PROPOSALS_SHOWN","BRIEF_MAX_CHARS","SOURCE_COPY","installed","preset","custom","default","isTerminal","job","includes","status","proposalOf","output","outputs","find","entry","resource","proposal","changeLabel","change","control","label","Swatch","value","variant","color","text","String","test","direction","spacing","sx","alignItems","aria-hidden","width","height","borderRadius","border","borderColor","backgroundColor","flexShrink","fontFamily","wordBreak","correctionText","correction","scheme","reason","to","required","against","length","join","ratio","AiThemeProposalCard","props","hostId","orgId","theme","themeSource","ThemePreview","proposeDraft","data","user","userRef","current","uid","verdict","setVerdict","notice","setNotice","recent","setRecent","brief","setBrief","mode","setMode","busy","setBusy","setJob","setScheme","applied","setApplied","watchRef","abort","active","response","encodeURIComponent","payload","json","catch","ok","locked","error","jobs","filter","kind","slice","watch","jobId","org","controller","AbortController","again","signal","aborted","body","event","propose","trim","method","headers","JSON","stringify","inputs","next","id","after","stale","apply","running","Boolean","contentGutterX","contentGutterY","header","help","excerpt","exclusive","size","onChange","_","aria-label","multiline","minRows","fullWidth","placeholder","helperText","target","disabled","onClick","severity","map","flexGrow","minWidth","noWrap","summary","source","changes","components","resetComponents","before","leaf","component","slot","property","media","corrections","notes","dropped","line","container","xs","md","gutterBottom","data-preview","displayName"],"mappings":"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"}
1
+ {"version":3,"sources":["../../../../../../../libs/plugins/ai/src/lib/components/ai-theme-proposal-card.component.tsx"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n'use client'\n\nimport { lockdownRefusalText, parseLockdownRefusal } from '@aglyn/aglyn'\nimport { pluginDocsHelp } from '@aglyn/aglyn/app-utils/docs-help'\nimport type { HostThemeSource } from '@aglyn/aglyn/app-utils/site-theme'\nimport type { ConsoleHostThemeZoneProps } from '@aglyn/aglyn/plugin-manager/feature-plugins'\nimport type { HostThemeScheme } from '@aglyn/shared-data-types'\nimport { CardDisplay } from '@aglyn/shared-ui-jsx'\nimport { ScrollTable } from '@aglyn/shared-ui-jsx/components/scroll-table.component'\nimport { themeEditorControl } from '@aglyn/shared-ui-theme/util/theme-editor-fields'\nimport { authorizedFetch } from '@aglyn/shared-util-http/authorized-token'\nimport { useUser } from '@aglyn/tenant-feature-instance'\nimport {\n Alert,\n Box,\n Button,\n Chip,\n CircularProgress,\n Grid,\n Stack,\n Tab,\n TableBody,\n TableCell,\n TableHead,\n TableRow,\n Tabs,\n TextField,\n ToggleButton,\n ToggleButtonGroup,\n Typography,\n} from '@mui/material'\nimport { useCallback, useEffect, useMemo, useRef, useState } from 'react'\nimport {\n AI_JOB_TERMINAL_STATUSES,\n type AiJobSummary,\n} from '../model/ai-jobs.types'\nimport {\n aiThemeColorToken,\n aiThemeProposalAfter,\n aiThemeStaleChanges,\n readAiThemeProposal,\n type AiThemeControlChange,\n type AiThemeCorrection,\n type AiThemeProposal,\n type AiThemeProposalMode,\n} from '../model/ai-theme-proposal'\nimport { readEventFrames } from './assist-jobs-drawer.component'\n\n/**\n * The theme assistant (AGL-2938), on the site's Theme section through the\n * `hostTheme` zone: a brief in, a theme proposal out, previewed before and\n * after with the editor's own preview, and put in the editor below as\n * unsaved changes when the person chooses. It never writes the theme — the\n * editor's Save does, through the same guarded path every edit takes.\n *\n * It renders nothing until the jobs route has answered for this workspace.\n * The shell has already decided the plan and the member's permission before\n * mounting it, but a released-off feature does not exist, and the release\n * flag is the route's to decide: a 404 there is this card staying absent.\n * The same read lists the site's recent proposals, so one made while the\n * person was elsewhere is still here to preview.\n */\n\n/** How many recent jobs the card reads to find this site's proposals. */\nconst RECENT_JOBS_READ = 20\n\n/** How many of this site's proposals the card offers again. */\nconst RECENT_PROPOSALS_SHOWN = 3\n\nconst BRIEF_MAX_CHARS = 4_000\n\nconst SOURCE_COPY: Record<HostThemeSource, string> = {\n installed:\n 'Saved as your changes on top of the installed theme. The publisher’s version stays as it is and can still take an update.',\n preset:\n 'Saved as your changes on top of the built-in theme, which stays as it is and can be restored.',\n custom:\n 'Saved as your changes on top of this theme of yours. Update it to keep them in the theme itself.',\n default:\n 'Only these values are stored. Everything else keeps following the default theme.',\n}\n\ntype Verdict = 'checking' | 'ready' | 'hidden'\n\nconst isTerminal = (job: AiJobSummary) => AI_JOB_TERMINAL_STATUSES.includes(job.status)\n\n/** The proposal a theme job produced, when it produced one. */\nfunction proposalOf(job: AiJobSummary | null): AiThemeProposal | null {\n const output = job?.outputs.find((entry) => entry.resource === 'theme')\n return output ? readAiThemeProposal(output.proposal) : null\n}\n\n/** A control's label, with its scheme when it has one. */\nfunction changeLabel(change: Pick<AiThemeControlChange, 'control' | 'scheme'>): string {\n return themeEditorControl(change.control).label\n}\n\nfunction Swatch({ value }: { value: string | number | null }) {\n if (value === null) {\n return (\n <Typography variant=\"caption\" color=\"text.secondary\">\n {'Default'}\n </Typography>\n )\n }\n const text = String(value)\n const color = typeof value === 'string' && /^#[0-9a-f]{6}$/i.test(value)\n return (\n <Stack direction=\"row\" spacing={1} sx={{ alignItems: 'center' }}>\n {color ? (\n <Box\n aria-hidden\n sx={{\n width: 14,\n height: 14,\n borderRadius: 0.5,\n border: 1,\n borderColor: 'divider',\n backgroundColor: text,\n flexShrink: 0,\n }}\n />\n ) : null}\n <Typography variant=\"body2\" sx={{ fontFamily: 'monospace', wordBreak: 'break-all' }}>\n {text}\n </Typography>\n </Stack>\n )\n}\n\nfunction correctionText(correction: AiThemeCorrection): string {\n const label = `${changeLabel(correction)} (${correction.scheme})`\n if (correction.reason === 'dark-value') {\n return `${label} set to ${correction.to} so the color keeps reading on the dark background.`\n }\n return (\n `${label} moved to ${correction.to} to reach ${correction.required}:1` +\n (correction.against?.length ? ` against ${correction.against.join(' and ')}` : '') +\n (correction.ratio ? ` (it was ${correction.ratio}:1).` : '.')\n )\n}\n\nexport function AiThemeProposalCard(props: ConsoleHostThemeZoneProps) {\n const { hostId, orgId, theme, themeSource, ThemePreview, proposeDraft } = props\n const { data: user } = useUser()\n // Held in a ref so the reads below key on WHO is signed in, never on the\n // identity of the object that says so.\n const userRef = useRef(user)\n userRef.current = user\n const uid = user?.uid ?? null\n\n const [verdict, setVerdict] = useState<Verdict>('checking')\n const [notice, setNotice] = useState<string | null>(null)\n const [recent, setRecent] = useState<AiJobSummary[]>([])\n const [brief, setBrief] = useState('')\n const [mode, setMode] = useState<AiThemeProposalMode>('modify')\n const [busy, setBusy] = useState(false)\n const [job, setJob] = useState<AiJobSummary | null>(null)\n const [scheme, setScheme] = useState<HostThemeScheme>('light')\n const [applied, setApplied] = useState<string | null>(null)\n const watchRef = useRef<AbortController | null>(null)\n\n useEffect(() => () => watchRef.current?.abort(), [])\n\n useEffect(() => {\n if (!orgId || !hostId || !uid) return\n let active = true\n setVerdict('checking')\n void (async () => {\n try {\n const response = await authorizedFetch(\n userRef.current,\n `/api/ai/jobs?orgId=${encodeURIComponent(orgId)}&limit=${RECENT_JOBS_READ}`,\n )\n if (!active) return\n // The flag off (404) and the plan without generation (403): the\n // feature is not this workspace's, so the card is not here at all.\n if (response.status === 404 || response.status === 403) {\n setVerdict('hidden')\n return\n }\n const payload = await response.json().catch(() => null)\n if (!active) return\n if (!response.ok) {\n const locked = parseLockdownRefusal(response.status, payload)\n setNotice(\n locked\n ? lockdownRefusalText(locked)\n : String(payload?.error ?? 'Recent theme proposals could not be loaded.'),\n )\n } else {\n const jobs = (payload?.jobs ?? []) as AiJobSummary[]\n setRecent(\n jobs\n .filter((entry) => entry.kind === 'theme' && entry.hostId === hostId)\n .filter((entry) => proposalOf(entry) !== null)\n .slice(0, RECENT_PROPOSALS_SHOWN),\n )\n }\n setVerdict('ready')\n } catch {\n if (!active) return\n setNotice('Recent theme proposals could not be loaded.')\n setVerdict('ready')\n }\n })()\n return () => {\n active = false\n }\n }, [orgId, hostId, uid])\n\n /** Follows a job through the events route until it settles. */\n const watch = useCallback(async (jobId: string, org: string) => {\n watchRef.current?.abort()\n const controller = new AbortController()\n watchRef.current = controller\n let again = true\n while (again && !controller.signal.aborted) {\n again = false\n try {\n const response = await authorizedFetch(\n userRef.current,\n `/api/ai/jobs/${encodeURIComponent(jobId)}/events?orgId=${encodeURIComponent(org)}`,\n { signal: controller.signal },\n )\n if (!response.ok || !response.body) return\n await readEventFrames(response.body, (event) => {\n if (event['type'] === 'state') setJob(event['job'] as AiJobSummary)\n else if (event['type'] === 'reconnect') again = true\n })\n } catch {\n return\n }\n }\n }, [])\n\n const propose = useCallback(async () => {\n if (!orgId || !brief.trim()) return\n setBusy(true)\n setNotice(null)\n setApplied(null)\n try {\n const response = await authorizedFetch(userRef.current, '/api/ai/jobs', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n orgId,\n hostId,\n kind: 'theme',\n brief: brief.trim(),\n inputs: { mode },\n }),\n })\n const payload = await response.json().catch(() => null)\n if (!response.ok) {\n const locked = parseLockdownRefusal(response.status, payload)\n setNotice(\n locked\n ? lockdownRefusalText(locked)\n : String(payload?.error ?? 'The theme proposal could not be started — try again.'),\n )\n return\n }\n const next = payload?.job as AiJobSummary | undefined\n if (!next) return\n setJob(next)\n if (!isTerminal(next)) await watch(next.id, orgId)\n } catch {\n setNotice('The theme proposal could not be started — try again.')\n } finally {\n setBusy(false)\n }\n }, [orgId, hostId, brief, mode, watch])\n\n const proposal = useMemo(() => proposalOf(job), [job])\n const after = useMemo(\n () => (proposal ? aiThemeProposalAfter(theme, proposal) : null),\n [theme, proposal],\n )\n const stale = useMemo(\n () => (proposal ? aiThemeStaleChanges(theme, proposal).length > 0 : false),\n [theme, proposal],\n )\n\n const apply = useCallback(() => {\n if (!job || !after) return\n proposeDraft(after.theme, job.id)\n setApplied(job.id)\n }, [job, after, proposeDraft])\n\n if (verdict !== 'ready') return null\n\n const running = Boolean(job && !isTerminal(job))\n\n return (\n <CardDisplay\n contentGutterX\n contentGutterY\n header=\"Theme assistant\"\n help={pluginDocsHelp('aiThemes', {\n excerpt:\n 'Describe the change and get a proposal for every control the editor has, previewed before and after. Nothing is saved until you save it in the editor.',\n })}\n >\n <Stack spacing={2}>\n <ToggleButtonGroup\n exclusive\n size=\"small\"\n value={mode}\n onChange={(_, value: AiThemeProposalMode | null) => value && setMode(value)}\n aria-label=\"What to propose\"\n >\n <ToggleButton value=\"modify\">{'Change what I describe'}</ToggleButton>\n <ToggleButton value=\"create\">{'Design a new theme'}</ToggleButton>\n </ToggleButtonGroup>\n <TextField\n multiline\n minRows={2}\n fullWidth\n label=\"Describe the change\"\n placeholder=\"Warmer, with a deep green primary and bigger headings on mobile\"\n helperText=\"A hex color in your description is used exactly. Paste a link to borrow a page’s colors.\"\n value={brief}\n onChange={(event) => setBrief(event.target.value.slice(0, BRIEF_MAX_CHARS))}\n disabled={busy}\n />\n <Stack direction=\"row\" spacing={1} sx={{ alignItems: 'center' }}>\n <Button variant=\"contained\" disabled={busy || !brief.trim()} onClick={() => void propose()}>\n {'Propose changes'}\n </Button>\n {running ? <CircularProgress size={18} aria-label=\"Working on a proposal\" /> : null}\n </Stack>\n {notice ? <Alert severity=\"warning\">{notice}</Alert> : null}\n\n {job && job.error && !proposal ? (\n <Alert severity={job.status === 'failed' ? 'error' : 'warning'}>{job.error}</Alert>\n ) : null}\n\n {!job && recent.length ? (\n <Stack spacing={1}>\n <Typography variant=\"subtitle2\">{'Recent proposals for this site'}</Typography>\n {recent.map((entry) => (\n <Stack key={entry.id} direction=\"row\" spacing={1} sx={{ alignItems: 'center' }}>\n <Typography variant=\"body2\" sx={{ flexGrow: 1, minWidth: 0 }} noWrap>\n {entry.brief}\n </Typography>\n <Button size=\"small\" onClick={() => setJob(entry)}>\n {'Show'}\n </Button>\n </Stack>\n ))}\n </Stack>\n ) : null}\n\n {proposal && after ? (\n <Stack spacing={2} aria-label=\"Theme proposal\">\n {proposal.summary ? <Typography variant=\"body1\">{proposal.summary}</Typography> : null}\n <Typography variant=\"body2\" color=\"text.secondary\">\n {SOURCE_COPY[proposal.source]}\n </Typography>\n {stale ? (\n <Alert severity=\"info\">\n {'The theme has changed since this proposal was made. The preview and the editor apply it to the theme as it is now.'}\n </Alert>\n ) : null}\n\n {proposal.changes.length || proposal.components.length || proposal.resetComponents ? (\n <Box>\n <ScrollTable size=\"small\" aria-label=\"Proposed changes\">\n <TableHead>\n <TableRow>\n <TableCell>{'Control'}</TableCell>\n <TableCell>{'Now'}</TableCell>\n <TableCell>{'Proposed'}</TableCell>\n </TableRow>\n </TableHead>\n <TableBody>\n {proposal.changes.map((change) => (\n <TableRow key={`${change.control}:${change.scheme ?? ''}`}>\n <TableCell>\n <Stack direction=\"row\" spacing={1} sx={{ alignItems: 'center' }}>\n <Typography variant=\"body2\">{changeLabel(change)}</Typography>\n {aiThemeColorToken(change.control) && change.scheme ? (\n <Chip size=\"small\" variant=\"outlined\" label={change.scheme} />\n ) : null}\n </Stack>\n </TableCell>\n <TableCell>\n <Swatch value={change.before} />\n </TableCell>\n <TableCell>\n <Swatch value={change.value} />\n </TableCell>\n </TableRow>\n ))}\n {proposal.resetComponents ? (\n <TableRow>\n <TableCell>{themeEditorControl('components').label}</TableCell>\n <TableCell>{'This site’s overrides'}</TableCell>\n <TableCell>{'Theme defaults'}</TableCell>\n </TableRow>\n ) : null}\n {proposal.components.map((leaf) => (\n <TableRow key={`${leaf.component}:${leaf.target}:${leaf.slot}:${leaf.media}:${leaf.property}`}>\n <TableCell>\n <Typography variant=\"body2\">\n {[\n leaf.component,\n leaf.target === 'defaultProps' ? 'default' : leaf.slot,\n leaf.property,\n ].join(' · ')}\n </Typography>\n {leaf.media ? <Chip size=\"small\" variant=\"outlined\" label={leaf.media} /> : null}\n </TableCell>\n <TableCell>{'—'}</TableCell>\n <TableCell>\n <Swatch value={typeof leaf.value === 'boolean' ? String(leaf.value) : leaf.value} />\n </TableCell>\n </TableRow>\n ))}\n </TableBody>\n </ScrollTable>\n </Box>\n ) : (\n <Typography variant=\"body2\">{'No changes proposed.'}</Typography>\n )}\n\n {[...proposal.corrections, ...after.corrections].length ? (\n <Stack spacing={0.5}>\n <Typography variant=\"subtitle2\">{'Adjusted for readability'}</Typography>\n {[...proposal.corrections, ...after.corrections].map((correction) => (\n <Typography\n key={`${correction.control}:${correction.scheme}:${correction.to}`}\n variant=\"body2\"\n >\n {correctionText(correction)}\n </Typography>\n ))}\n </Stack>\n ) : null}\n\n {[...proposal.notes, ...after.notes, ...proposal.dropped].length ? (\n <Stack spacing={0.5}>\n <Typography variant=\"subtitle2\">{'Worth knowing'}</Typography>\n {[...proposal.notes, ...after.notes].map((line) => (\n <Typography key={`note:${line}`} variant=\"body2\" color=\"text.secondary\">\n {line}\n </Typography>\n ))}\n {proposal.dropped.map((line) => (\n <Typography key={`dropped:${line}`} variant=\"body2\" color=\"text.secondary\">\n {`Left out — ${line}`}\n </Typography>\n ))}\n </Stack>\n ) : null}\n\n <Tabs\n value={scheme}\n onChange={(_, value: HostThemeScheme) => setScheme(value)}\n aria-label=\"Preview scheme\"\n >\n <Tab label=\"Light\" value=\"light\" />\n <Tab label=\"Dark\" value=\"dark\" />\n </Tabs>\n <Grid container spacing={2}>\n <Grid size={{ xs: 12, md: 6 }}>\n <Typography variant=\"subtitle2\" gutterBottom>\n {'Before'}\n </Typography>\n <Box data-preview=\"before\">\n <ThemePreview theme={theme ?? {}} scheme={scheme} />\n </Box>\n </Grid>\n <Grid size={{ xs: 12, md: 6 }}>\n <Typography variant=\"subtitle2\" gutterBottom>\n {'After'}\n </Typography>\n <Box data-preview=\"after\">\n <ThemePreview theme={after.theme} scheme={scheme} />\n </Box>\n </Grid>\n </Grid>\n\n {applied === job?.id ? (\n <Alert severity=\"success\">\n {'In the editor below as unsaved changes. Review them there, then Save — or Discard changes to go back.'}\n </Alert>\n ) : null}\n <Stack\n direction=\"row\"\n spacing={1}\n useFlexGap\n sx={{ flexWrap: 'wrap' }}\n >\n <Button variant=\"contained\" onClick={apply} disabled={applied === job?.id}>\n {'Put in the editor'}\n </Button>\n <Button\n onClick={() => {\n setJob(null)\n setApplied(null)\n }}\n >\n {'Dismiss'}\n </Button>\n </Stack>\n </Stack>\n ) : null}\n </Stack>\n </CardDisplay>\n )\n}\nAiThemeProposalCard.displayName = 'AiThemeProposalCard'\n\nexport default AiThemeProposalCard\n"],"names":["lockdownRefusalText","parseLockdownRefusal","pluginDocsHelp","CardDisplay","ScrollTable","themeEditorControl","authorizedFetch","useUser","Alert","Box","Button","Chip","CircularProgress","Grid","Stack","Tab","TableBody","TableCell","TableHead","TableRow","Tabs","TextField","ToggleButton","ToggleButtonGroup","Typography","useCallback","useEffect","useMemo","useRef","useState","AI_JOB_TERMINAL_STATUSES","aiThemeColorToken","aiThemeProposalAfter","aiThemeStaleChanges","readAiThemeProposal","readEventFrames","RECENT_JOBS_READ","RECENT_PROPOSALS_SHOWN","BRIEF_MAX_CHARS","SOURCE_COPY","installed","preset","custom","default","isTerminal","job","includes","status","proposalOf","output","outputs","find","entry","resource","proposal","changeLabel","change","control","label","Swatch","value","variant","color","text","String","test","direction","spacing","sx","alignItems","aria-hidden","width","height","borderRadius","border","borderColor","backgroundColor","flexShrink","fontFamily","wordBreak","correctionText","correction","scheme","reason","to","required","against","length","join","ratio","AiThemeProposalCard","props","hostId","orgId","theme","themeSource","ThemePreview","proposeDraft","data","user","userRef","current","uid","verdict","setVerdict","notice","setNotice","recent","setRecent","brief","setBrief","mode","setMode","busy","setBusy","setJob","setScheme","applied","setApplied","watchRef","abort","active","response","encodeURIComponent","payload","json","catch","ok","locked","error","jobs","filter","kind","slice","watch","jobId","org","controller","AbortController","again","signal","aborted","body","event","propose","trim","method","headers","JSON","stringify","inputs","next","id","after","stale","apply","running","Boolean","contentGutterX","contentGutterY","header","help","excerpt","exclusive","size","onChange","_","aria-label","multiline","minRows","fullWidth","placeholder","helperText","target","disabled","onClick","severity","map","flexGrow","minWidth","noWrap","summary","source","changes","components","resetComponents","before","leaf","component","slot","property","media","corrections","notes","dropped","line","container","xs","md","gutterBottom","data-preview","useFlexGap","flexWrap","displayName"],"mappings":"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"}
@@ -66,6 +66,7 @@ const credits = (value)=>value.toLocaleString();
66
66
  },
67
67
  children: [
68
68
  /*#__PURE__*/ _jsxs(Stack, {
69
+ useFlexGap: true,
69
70
  direction: "row",
70
71
  spacing: 1,
71
72
  sx: {
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../../../libs/plugins/ai/src/lib/components/ai-usage-strip.component.tsx"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n'use client'\n\nimport { buildRoute, Route } from '@aglyn/aglyn/app-utils/console-routes'\nimport { AppLink } from '@aglyn/shared-ui-jsx'\nimport { Box, LinearProgress, Stack, Typography } from '@mui/material'\nimport type { AiUsageMeterWire } from '../usage/ai-usage-wire'\nimport { useAiUsageMeter } from './use-ai-usage-meter'\n\nexport interface AiUsageStripProps {\n /** The workspace the strip speaks for; nothing renders without one. */\n orgId?: string | null\n /** For the link to who can raise an allotment; the link is omitted without it. */\n orgSlug?: string | null\n}\n\nconst credits = (value: number): string => value.toLocaleString()\n\n/** The line about the reader's own month, in the words the strip uses. */\nexport function aiUsageStripMineLabel(meter: AiUsageMeterWire): string {\n const { mine } = meter\n if (mine.limit === null) return `You: ${credits(mine.used)} credits this month`\n const who = mine.scope === 'host' ? 'This site' : mine.scope === 'collab' ? 'You, on this site' : 'You'\n return `${who}: ${credits(mine.used)} of ${credits(mine.limit)} credits this month`\n}\n\n/** The line about the workspace's pool. */\nexport function aiUsageStripPoolLabel(meter: AiUsageMeterWire): string {\n const { pool } = meter\n return pool.limit === null\n ? `Workspace: ${credits(pool.used)} credits`\n : `Workspace: ${credits(pool.used)} of ${credits(pool.limit)} credits`\n}\n\n/**\n * THE USAGE STRIP (AGL-2942): the reader's AI credits while they use AI —\n * in the assistant panel and every generation dialog, with no dashboard to\n * visit and no read of its own.\n *\n * It shows the reader's month against the allotment that binds them (or\n * their month alone and the workspace's pool when none does), the pool, what\n * the last request cost, and the model that answered. From 80% it warns; at\n * a hard allotment it says who can raise it. It renders nothing until a door\n * has answered this reader in this workspace — see `use-ai-usage-meter.ts`.\n */\nexport function AiUsageStrip({ orgId, orgSlug }: AiUsageStripProps) {\n const meter = useAiUsageMeter(orgId)\n if (!meter) return null\n const { mine, pool } = meter\n const bound = mine.limit !== null\n const used = bound ? mine.used : pool.used\n const limit = bound ? mine.limit : pool.limit\n const pct = limit ? Math.min(100, Math.round((used / limit) * 100)) : null\n const tone = meter.state === 'capped' ? 'error' : meter.state === 'warn' ? 'warning' : 'primary'\n const allotmentReached = bound && mine.mode === 'hard' && mine.limit !== null && mine.used >= mine.limit\n const raiseHref =\n orgSlug && mine.scope !== 'collab'\n ? `${buildRoute(Route.MANAGE_BILLING_USAGE, { orgSlug })}#ai-allotments`\n : null\n const whose = !bound\n ? 'the workspace’s credits'\n : mine.scope === 'host'\n ? 'this site’s AI allotment'\n : 'your AI allotment'\n\n return (\n <Box\n role=\"status\"\n aria-live=\"polite\"\n data-testid=\"ai-usage-strip\"\n sx={{ px: 1, py: 0.75, borderRadius: 1, bgcolor: 'action.hover' }}\n >\n <Stack direction=\"row\" spacing={1} sx={{ alignItems: 'baseline', flexWrap: 'wrap' }}>\n <Typography variant=\"caption\" sx={{ flexGrow: 1 }}>\n {aiUsageStripMineLabel(meter)}\n </Typography>\n {meter.last !== null ? (\n <Typography variant=\"caption\" color=\"text.secondary\">\n {`Last request: ${credits(meter.last)} credits`}\n </Typography>\n ) : null}\n </Stack>\n {pct !== null ? (\n <LinearProgress\n variant=\"determinate\"\n value={pct}\n color={tone}\n aria-label={`${pct}% of ${whose} used`}\n sx={{ my: 0.5, height: 4, borderRadius: 2 }}\n />\n ) : null}\n <Typography variant=\"caption\" color=\"text.secondary\" component=\"div\">\n {aiUsageStripPoolLabel(meter)}\n {bound ? '' : ' this month'}\n {meter.model ? ` · ${meter.model.label}${meter.model.auto ? ' (Auto)' : ''}` : ''}\n </Typography>\n {meter.state === 'warn' ? (\n <Typography variant=\"caption\" color=\"warning.main\" component=\"div\">\n {`Past 80% of ${whose}.`}\n {bound && mine.mode === 'soft' ? ' It is soft, so requests keep working.' : ''}\n </Typography>\n ) : null}\n {meter.state === 'capped' ? (\n <Typography variant=\"caption\" color=\"error\" component=\"div\">\n {allotmentReached\n ? mine.scope === 'collab'\n ? 'Your AI allotment on this site is used for the month. The site’s admin, or an organization admin, can raise it.'\n : mine.scope === 'host'\n ? 'This site’s AI allotment is used for the month. An organization admin can raise it'\n : 'Your AI allotment is used for the month. An organization admin can raise it'\n : 'That request was stopped by a limit on this workspace.'}\n {allotmentReached && raiseHref ? (\n <>\n {' under '}\n <AppLink componentVariant=\"naked\" href={raiseHref}>\n {'Billing → Usage'}\n </AppLink>\n {'.'}\n </>\n ) : allotmentReached && mine.scope !== 'collab' ? (\n '.'\n ) : null}\n </Typography>\n ) : null}\n </Box>\n )\n}\nAiUsageStrip.displayName = 'AiUsageStrip'\n\nexport default AiUsageStrip\n"],"names":["buildRoute","Route","AppLink","Box","LinearProgress","Stack","Typography","useAiUsageMeter","credits","value","toLocaleString","aiUsageStripMineLabel","meter","mine","limit","used","who","scope","aiUsageStripPoolLabel","pool","AiUsageStrip","orgId","orgSlug","bound","pct","Math","min","round","tone","state","allotmentReached","mode","raiseHref","MANAGE_BILLING_USAGE","whose","role","aria-live","data-testid","sx","px","py","borderRadius","bgcolor","direction","spacing","alignItems","flexWrap","variant","flexGrow","last","color","aria-label","my","height","component","model","label","auto","componentVariant","href","displayName"],"mappings":"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"}
1
+ {"version":3,"sources":["../../../../../../../libs/plugins/ai/src/lib/components/ai-usage-strip.component.tsx"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n'use client'\n\nimport { buildRoute, Route } from '@aglyn/aglyn/app-utils/console-routes'\nimport { AppLink } from '@aglyn/shared-ui-jsx'\nimport { Box, LinearProgress, Stack, Typography } from '@mui/material'\nimport type { AiUsageMeterWire } from '../usage/ai-usage-wire'\nimport { useAiUsageMeter } from './use-ai-usage-meter'\n\nexport interface AiUsageStripProps {\n /** The workspace the strip speaks for; nothing renders without one. */\n orgId?: string | null\n /** For the link to who can raise an allotment; the link is omitted without it. */\n orgSlug?: string | null\n}\n\nconst credits = (value: number): string => value.toLocaleString()\n\n/** The line about the reader's own month, in the words the strip uses. */\nexport function aiUsageStripMineLabel(meter: AiUsageMeterWire): string {\n const { mine } = meter\n if (mine.limit === null) return `You: ${credits(mine.used)} credits this month`\n const who = mine.scope === 'host' ? 'This site' : mine.scope === 'collab' ? 'You, on this site' : 'You'\n return `${who}: ${credits(mine.used)} of ${credits(mine.limit)} credits this month`\n}\n\n/** The line about the workspace's pool. */\nexport function aiUsageStripPoolLabel(meter: AiUsageMeterWire): string {\n const { pool } = meter\n return pool.limit === null\n ? `Workspace: ${credits(pool.used)} credits`\n : `Workspace: ${credits(pool.used)} of ${credits(pool.limit)} credits`\n}\n\n/**\n * THE USAGE STRIP (AGL-2942): the reader's AI credits while they use AI —\n * in the assistant panel and every generation dialog, with no dashboard to\n * visit and no read of its own.\n *\n * It shows the reader's month against the allotment that binds them (or\n * their month alone and the workspace's pool when none does), the pool, what\n * the last request cost, and the model that answered. From 80% it warns; at\n * a hard allotment it says who can raise it. It renders nothing until a door\n * has answered this reader in this workspace — see `use-ai-usage-meter.ts`.\n */\nexport function AiUsageStrip({ orgId, orgSlug }: AiUsageStripProps) {\n const meter = useAiUsageMeter(orgId)\n if (!meter) return null\n const { mine, pool } = meter\n const bound = mine.limit !== null\n const used = bound ? mine.used : pool.used\n const limit = bound ? mine.limit : pool.limit\n const pct = limit ? Math.min(100, Math.round((used / limit) * 100)) : null\n const tone = meter.state === 'capped' ? 'error' : meter.state === 'warn' ? 'warning' : 'primary'\n const allotmentReached = bound && mine.mode === 'hard' && mine.limit !== null && mine.used >= mine.limit\n const raiseHref =\n orgSlug && mine.scope !== 'collab'\n ? `${buildRoute(Route.MANAGE_BILLING_USAGE, { orgSlug })}#ai-allotments`\n : null\n const whose = !bound\n ? 'the workspace’s credits'\n : mine.scope === 'host'\n ? 'this site’s AI allotment'\n : 'your AI allotment'\n\n return (\n <Box\n role=\"status\"\n aria-live=\"polite\"\n data-testid=\"ai-usage-strip\"\n sx={{ px: 1, py: 0.75, borderRadius: 1, bgcolor: 'action.hover' }}\n >\n <Stack useFlexGap direction=\"row\" spacing={1} sx={{ alignItems: 'baseline', flexWrap: 'wrap' }}>\n <Typography variant=\"caption\" sx={{ flexGrow: 1 }}>\n {aiUsageStripMineLabel(meter)}\n </Typography>\n {meter.last !== null ? (\n <Typography variant=\"caption\" color=\"text.secondary\">\n {`Last request: ${credits(meter.last)} credits`}\n </Typography>\n ) : null}\n </Stack>\n {pct !== null ? (\n <LinearProgress\n variant=\"determinate\"\n value={pct}\n color={tone}\n aria-label={`${pct}% of ${whose} used`}\n sx={{ my: 0.5, height: 4, borderRadius: 2 }}\n />\n ) : null}\n <Typography variant=\"caption\" color=\"text.secondary\" component=\"div\">\n {aiUsageStripPoolLabel(meter)}\n {bound ? '' : ' this month'}\n {meter.model ? ` · ${meter.model.label}${meter.model.auto ? ' (Auto)' : ''}` : ''}\n </Typography>\n {meter.state === 'warn' ? (\n <Typography variant=\"caption\" color=\"warning.main\" component=\"div\">\n {`Past 80% of ${whose}.`}\n {bound && mine.mode === 'soft' ? ' It is soft, so requests keep working.' : ''}\n </Typography>\n ) : null}\n {meter.state === 'capped' ? (\n <Typography variant=\"caption\" color=\"error\" component=\"div\">\n {allotmentReached\n ? mine.scope === 'collab'\n ? 'Your AI allotment on this site is used for the month. The site’s admin, or an organization admin, can raise it.'\n : mine.scope === 'host'\n ? 'This site’s AI allotment is used for the month. An organization admin can raise it'\n : 'Your AI allotment is used for the month. An organization admin can raise it'\n : 'That request was stopped by a limit on this workspace.'}\n {allotmentReached && raiseHref ? (\n <>\n {' under '}\n <AppLink componentVariant=\"naked\" href={raiseHref}>\n {'Billing → Usage'}\n </AppLink>\n {'.'}\n </>\n ) : allotmentReached && mine.scope !== 'collab' ? (\n '.'\n ) : null}\n </Typography>\n ) : null}\n </Box>\n )\n}\nAiUsageStrip.displayName = 'AiUsageStrip'\n\nexport default AiUsageStrip\n"],"names":["buildRoute","Route","AppLink","Box","LinearProgress","Stack","Typography","useAiUsageMeter","credits","value","toLocaleString","aiUsageStripMineLabel","meter","mine","limit","used","who","scope","aiUsageStripPoolLabel","pool","AiUsageStrip","orgId","orgSlug","bound","pct","Math","min","round","tone","state","allotmentReached","mode","raiseHref","MANAGE_BILLING_USAGE","whose","role","aria-live","data-testid","sx","px","py","borderRadius","bgcolor","useFlexGap","direction","spacing","alignItems","flexWrap","variant","flexGrow","last","color","aria-label","my","height","component","model","label","auto","componentVariant","href","displayName"],"mappings":"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"}
@@ -1,4 +1,6 @@
1
1
  import { type AglynOrgBilling } from '@aglyn/aglyn';
2
+ import { type AssistBuildDraftLink } from '../model/assist-follow-up';
3
+ import type { AiJobSummary } from '../model/ai-jobs.types';
2
4
  /**
3
5
  * Aglyn Assist (AGL-1860, phase 1 — answer + guide): the floating chat
4
6
  * helper mounted on every authenticated console page. Docs-grounded answers
@@ -32,6 +34,14 @@ interface AssistDocLink {
32
34
  title: string;
33
35
  url: string;
34
36
  }
37
+ /**
38
+ * The drafts this thread's builds made that open in the Besigner, newest
39
+ * build first (AGL-3616): what a follow-up such as "make the about page
40
+ * shorter" may open.
41
+ */
42
+ export declare function assistThreadDraftLinks(messages: ReadonlyArray<{
43
+ buildJob?: AiJobSummary | null;
44
+ }>, orgSlug: string): AssistBuildDraftLink[];
35
45
  /**
36
46
  * Minimal renderer for assistant text: markdown links and bare URLs become
37
47
  * links (internal root-relative paths ride AppLink, external open in a new