@aglyn/plugins-ai 1.0.0-beta.228 → 1.0.0-beta.229

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 (46) hide show
  1. package/package.json +17 -17
  2. package/src/lib/components/ai-jobs-list-page.component.js +12 -1
  3. package/src/lib/components/ai-jobs-list-page.component.js.map +1 -1
  4. package/src/lib/components/ai-site-build-page.component.d.ts +1 -1
  5. package/src/lib/components/ai-site-build-page.component.js +38 -5
  6. package/src/lib/components/ai-site-build-page.component.js.map +1 -1
  7. package/src/lib/components/ai-site-start-card.component.d.ts +10 -1
  8. package/src/lib/components/ai-site-start-card.component.js +7 -4
  9. package/src/lib/components/ai-site-start-card.component.js.map +1 -1
  10. package/src/lib/components/assist-jobs-drawer.component.d.ts +11 -0
  11. package/src/lib/components/assist-jobs-drawer.component.js +37 -1
  12. package/src/lib/components/assist-jobs-drawer.component.js.map +1 -1
  13. package/src/lib/jobs/ai-job-layout-site-pages.d.ts +70 -0
  14. package/src/lib/jobs/ai-job-layout-site-pages.js +216 -0
  15. package/src/lib/jobs/ai-job-layout-site-pages.js.map +1 -0
  16. package/src/lib/jobs/ai-job-layout-step.d.ts +2 -2
  17. package/src/lib/jobs/ai-job-layout-step.js +19 -1
  18. package/src/lib/jobs/ai-job-layout-step.js.map +1 -1
  19. package/src/lib/jobs/ai-job-site-step.js +7 -0
  20. package/src/lib/jobs/ai-job-site-step.js.map +1 -1
  21. package/src/lib/jobs/ai-jobs.d.ts +10 -0
  22. package/src/lib/jobs/ai-jobs.js +121 -51
  23. package/src/lib/jobs/ai-jobs.js.map +1 -1
  24. package/src/lib/model/ai-job-failure-copy.d.ts +20 -1
  25. package/src/lib/model/ai-job-failure-copy.js +28 -1
  26. package/src/lib/model/ai-job-failure-copy.js.map +1 -1
  27. package/src/lib/model/ai-job-notice.d.ts +3 -0
  28. package/src/lib/model/ai-job-notice.js +11 -2
  29. package/src/lib/model/ai-job-notice.js.map +1 -1
  30. package/src/lib/model/ai-jobs.types.d.ts +7 -0
  31. package/src/lib/model/ai-jobs.types.js.map +1 -1
  32. package/src/lib/model/ai-site-build-progress.d.ts +8 -0
  33. package/src/lib/model/ai-site-build-progress.js +66 -12
  34. package/src/lib/model/ai-site-build-progress.js.map +1 -1
  35. package/src/lib/model/ai-site-start-seo.d.ts +16 -0
  36. package/src/lib/model/ai-site-start-seo.js +54 -4
  37. package/src/lib/model/ai-site-start-seo.js.map +1 -1
  38. package/src/lib/model/ai-site-start.d.ts +14 -0
  39. package/src/lib/model/ai-site-start.js +43 -0
  40. package/src/lib/model/ai-site-start.js.map +1 -1
  41. package/src/lib/runtime/ai-doctrine.d.ts +6 -0
  42. package/src/lib/runtime/ai-doctrine.js +5 -1
  43. package/src/lib/runtime/ai-doctrine.js.map +1 -1
  44. package/src/lib/usage/assist-job-refund.d.ts +3 -2
  45. package/src/lib/usage/assist-job-refund.js +2 -1
  46. package/src/lib/usage/assist-job-refund.js.map +1 -1
@@ -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\nexport function AiSiteStartCard({\n hostId,\n orgId,\n orgSlug,\n host,\n startBlank,\n leave,\n}: ConsoleHostFirstRunZoneProps) {\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 const [step, setStep] = useState<Step>('choose')\n const [answers, setAnswers] = useState<AiSiteStartAnswers>(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 setAnswers((current) => ({ ...current, pages: AI_SITE_FREE_PAGES.max, welcomeEmail: false }))\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","data","user","router","userRef","current","uid","verdict","setVerdict","step","setStep","answers","setAnswers","setBusy","startingStarter","setStartingStarter","notice","setNotice","started","setStarted","freeTaste","setFreeTaste","active","response","encodeURIComponent","payload","ok","json","catch","pages","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","min","_","index","count","rowGap","columnGap","borderTop","mr","tabIndex","Boolean","startIcon"],"mappings":"AAAA;;;;;;;;;;;;;;;CAeC,GAED;;;AAEA,SAASA,mBAAmB,EAAEC,oBAAoB,EAAEC,mBAAmB,QAAQ,eAAc;AAC7F,SAASC,UAAU,QAAQ,0CAAyC;AAEpE,SAASC,kBAAkB,QAAQ,2BAA0B;AAC7D,SACEC,cAAc,EACdC,WAAW,EACXC,qBAAqB,EACrBC,yBAAyB,QACpB,yBAAwB;AAC/B,SAASC,OAAO,QAAQ,uBAAsB;AAC9C,SAASC,eAAe,QAAQ,2CAA0C;AAC1E,SAASC,OAAO,QAAQ,iCAAgC;AACxD,SACEC,KAAK,EACLC,MAAM,EACNC,GAAG,EACHC,MAAM,EACNC,IAAI,EACJC,cAAc,EACdC,IAAI,EACJC,gBAAgB,EAChBC,SAAS,EACTC,MAAM,EACNC,aAAa,EACbC,aAAa,EACbC,UAAU,EACVC,QAAQ,EACRC,KAAK,EACLC,IAAI,EACJC,SAAS,EACTC,OAAO,EACPC,SAAS,EACTC,OAAO,EACPC,OAAO,EACPC,UAAU,QACL,gBAAe;AACtB,SAASC,KAAK,QAAoB,uBAAsB;AACxD,SAASC,SAAS,QAAQ,kBAAiB;AAC3C,SAASC,WAAW,EAAEC,SAAS,EAAEC,KAAK,EAAEC,MAAM,EAAEC,QAAQ,QAAwB,QAAO;AACvF,SACEC,yBAAyB,EACzBC,kBAAkB,EAClBC,uBAAuB,EACvBC,0BAA0B,EAC1BC,wBAAwB,EACxBC,oBAAoB,EACpBC,eAAe,QAEV,0BAAsB;AAC7B,SAASC,+BAA+B,QAAQ,0BAAsB;AACtE,SACEC,qBAAqB,EACrBC,sBAAsB,EACtBC,mBAAmB,EACnBC,gBAAgB,EAChBC,iBAAiB,EACjBC,kBAAkB,QAEb,4BAAwB;AAE/B,SAASC,WAAW,QAAQ,+BAA2B;AACvD,SAASC,eAAe,QAAQ,oBAAgB;AAChD,SAASC,YAAY,QAAQ,qBAAiB;AAoE9C,0DAA0D,GAC1D,MAAMC,WAAW;AAEjB;;;;CAIC,GACD,OAAO,MAAMC,2BAA2B;IAAEC,SAAS;AAAqB,EAAU;AAElF,iEAAiE,GACjE,MAAMC,cAAc;IAAC;IAAU;CAAW;AAE1C,gEAAgE,GAChE,SAASC,UAAU,EAAEC,MAAM,EAAEC,QAAQ,EAA4D;IAC/F,qBACE,KAAClD;QACCmD,aAAW;QACXC,IAAI,CAACC,QAAkB,CAAA;gBACrBC,OAAOD,MAAME,OAAO,CAAC;gBACrBC,QAAQH,MAAME,OAAO,CAAC;gBACtBE,cAAc;gBACdC,SAAS;gBACTC,YAAY;gBACZC,gBAAgB;gBAChBd,SAAS1B,MAAMiC,MAAMQ,OAAO,CAACZ,OAAO,CAACa,IAAI,EAAET,MAAMQ,OAAO,CAACE,IAAI,KAAK,SAAS,OAAO;gBAClFC,OAAO,GAAGf,OAAO,KAAK,CAAC;gBACvBgB,UAAUZ,MAAME,OAAO,CAAC;YAC1B,CAAA;kBAECL;;AAGP;AAEA;;;CAGC,GACD,SAASgB,WAAW,EAClBjB,MAAM,EACNkB,IAAI,EACJC,MAAM,EACNC,KAAK,EACLC,WAAW,EACXC,OAAO,KAAK,EACZC,QAAQ,EACRtB,QAAQ,EAWT;IACC,MAAMuB,KAAKjD;IACX,qBACE,KAACtB;QACCwE,SAAQ;QACRtB,IAAI,CAACC,QAAkB,CAAA;gBACrBI,cAAc;gBACdD,QAAQ;gBACRmB,YAAYtB,MAAMuB,WAAW,CAACC,MAAM,CAAC;oBAAC;oBAAgB;oBAAc;iBAAY,EAAE;oBAChFC,UAAUzB,MAAMuB,WAAW,CAACE,QAAQ,CAACC,OAAO;gBAC9C;gBACA,2BAA2B;oBACzBC,aAAa,GAAG/B,OAAO,KAAK,CAAC;oBAC7BgC,WAAW5B,MAAM6B,OAAO,CAAC,EAAE;oBAC3BC,WAAW,CAAC,YAAY,EAAE9B,MAAME,OAAO,CAAC,MAAM,CAAC,CAAC;gBAClD;gBACA,2CAA2C;oBACzCoB,YAAY;oBACZ,2BAA2B;wBAAEQ,WAAW;oBAAO;gBACjD;YACF,CAAA;kBAEA,cAAA,KAAChF;YACCiF,SAASZ;YACTa,UAAUd;YACVe,mBAAiB,GAAGb,GAAG,MAAM,CAAC;YAC9Bc,oBAAkB,GAAGd,GAAG,YAAY,CAAC;YACrCe,aAAWjB,QAAQkB;YACnBrC,IAAI;gBAAEI,QAAQ;gBAAQkC,GAAG;oBAAEC,IAAI;oBAAGC,IAAI;gBAAE;YAAE;sBAE1C,cAAA,MAAChF;gBAAM2C,SAAS;gBAAGH,IAAI;oBAAEO,YAAY;oBAAUkC,WAAW;gBAAS;;kCACjE,KAAC7C;wBAAUC,QAAQA;kCAChBsB,qBACC,KAAClE;4BAAiByF,MAAK;4BAAM9B,OAAOf;4BAAQ8C,cAAY,GAAG1B,MAAM,CAAC,CAAC;2CAEnE,KAAC1E;4BAAQqG,MAAM7B;4BAAM8B,aAAW7B;4BAAQjB,aAAW;;;kCAGvD,KAAChC;wBAAWsD,IAAI,GAAGA,GAAG,MAAM,CAAC;wBAAEC,SAAQ;wBAAKwB,WAAU;kCACnD7B;;kCAEH,KAAClD;wBAAWsD,IAAI,GAAGA,GAAG,YAAY,CAAC;wBAAEC,SAAQ;wBAAQV,OAAM;kCACxDM;;oBAEFpB;;;;;AAKX;AAEA,8CAA8C,GAC9C,SAASiD,aAAa,EAAEjD,QAAQ,EAA2B;IACzD,qBACE,KAAC/B;QAAWuD,SAAQ;QAAWV,OAAM;QAAiBkC,WAAU;QAAK9C,IAAI;YAAEM,SAAS;QAAQ;kBACzFR;;AAGP;AAEA,OAAO,SAASkD,gBAAgB,EAC9BC,MAAM,EACNC,KAAK,EACLC,OAAO,EACPC,IAAI,EACJC,UAAU,EACVC,KAAK,EACwB;;IAC7B,MAAM,EAAEC,MAAMC,IAAI,EAAE,GAAG/G;IACvB,MAAMgH,SAASxF;IACf,2EAA2E;IAC3E,2BAA2B;IAC3B,MAAMyF,UAAUrF,OAAOmF;IACvBE,QAAQC,OAAO,GAAGH;IAClB,MAAMI,cAAMJ,wBAAAA,KAAMI,GAAG,mBAAI;IACzB,MAAM,CAACC,SAASC,WAAW,GAAGxF,SAAkB;IAChD,MAAM,CAACyF,MAAMC,QAAQ,GAAG1F,SAAe;IACvC,MAAM,CAAC2F,SAASC,WAAW,GAAG5F,SAA6BS;IAC3D,MAAM,CAACoC,MAAMgD,QAAQ,GAAG7F,SAAS;IACjC,wEAAwE;IACxE,MAAM,CAAC8F,iBAAiBC,mBAAmB,GAAG/F,SAAS;IACvD,MAAM,CAACgG,QAAQC,UAAU,GAAGjG,SAAwB;IACpD,8EAA8E,GAC9E,MAAM,CAACkG,SAASC,WAAW,GAAGnG,SAA8B;IAC5D,uEAAuE;IACvE,MAAM,CAACoG,WAAWC,aAAa,GAAGrG,SAAS;IAE3CH,UAAU;QACR,IAAI,CAAC+E,SAAS,CAACU,KAAK;QACpB,IAAIgB,SAAS;QACb,KAAK,AAAC,CAAA;YACJ,IAAI;gBACF,MAAMC,WAAW,MAAMrI,gBACrBkH,QAAQC,OAAO,EACf,CAAC,mBAAmB,EAAEmB,mBAAmB5B,OAAO,QAAQ,CAAC;gBAE3D,MAAM6B,UAAUF,SAASG,EAAE,GAAG,MAAMH,SAASI,IAAI,GAAGC,KAAK,CAAC,IAAM,QAAQ;gBACxE,IAAIN,QAAQ;oBACV,IAAIG,CAAAA,2BAAAA,QAASL,SAAS,MAAK,MAAM;wBAC/BC,aAAa;wBACbT,WAAW,CAACP,UAAa,aAAKA;gCAASwB,OAAO3G,mBAAmB4G,GAAG;gCAAEC,cAAc;;oBACtF;oBACAvB,WAAWe,SAASS,MAAM,KAAK,OAAOT,SAASS,MAAM,KAAK,MAAM,WAAW;gBAC7E;YACF,EAAE,eAAM;gBACN,IAAIV,QAAQd,WAAW;YACzB;QACF,CAAA;QACA,OAAO;YACLc,SAAS;QACX;IACF,GAAG;QAAC1B;QAAOU;KAAI;IAEf,MAAM2B,SAASrH,YACb,CAACsH,QACCtB,WAAW,CAACP,UAAa,aAAKA,SAAY6B,SAC5C,EAAE;IAGJ,MAAMC,UAAUrG,mBAAmB6E,SAAS;QAAES;IAAU;IACxD,MAAMgB,OAAO7G,gBAAgB6F;IAE7B,MAAMiB,OAAOzH,YAAY;QACvB,IAAI,CAACgF,SAAS9D,mBAAmB6E,SAAS;YAAES;QAAU,IAAI;QAC1DP,QAAQ;QACRI,UAAU;QACV,IAAI;;YACF,MAAMM,WAAW,MAAMrI,gBAAgBkH,QAAQC,OAAO,EAAE,gBAAgB;gBACtEiC,QAAQ;gBACRC,SAAS;oBAAE,gBAAgB;gBAAmB;gBAC9CC,MAAMC,KAAKC,SAAS,CAAC;oBACnB9C;oBACAD;oBACAgD,MAAM;oBACNC,OAAOhH,iBAAiB+E;oBACxB,+DAA+D;oBAC/D,6CAA6C;oBAC7CkC,QAAQ,aAAKhH,kBAAkB8E;wBAAU,CAAC1F,0BAA0B,EAAE;;gBACxE;YACF;YACA,MAAMwG,UAAU,MAAMF,SAASI,IAAI,GAAGC,KAAK,CAAC,IAAM;YAClD,IAAI,CAACL,SAASG,EAAE,EAAE;;gBAChB,MAAMoB,SAASrK,qBAAqB8I,SAASS,MAAM,EAAEP;gBACrDR,UACE6B,SACItK,oBAAoBsK,UACpBC,gBAAOtB,2BAAAA,QAASuB,KAAK,oBAAI;gBAE/B;YACF;YACA,MAAMC,kBAAWxB,2BAAAA,QAASyB,GAAG,mBAAiC;YAC9D,IAAI,CAACD,SAAS;gBACZhC,UAAU;gBACV;YACF;YACA,qEAAqE;YACrEhF,aAAagH;YACb,qEAAqE;YACrE,uEAAuE;YACvE,2CAA2C;YAC3C,MAAME,OAAOnH,gBAAgB6D,SAASC,MAAMmD,QAAQlF,EAAE;YACtD,IAAIoF,MAAM;;gBACP,CAACnD,gBAAAA,QAAU,IAAMjB;gBAClBoB,OAAOiD,IAAI,CAACD;gBACZ;YACF;YACAhC,WAAW8B;QACb,EAAE,eAAM;YACNhC,UAAU;QACZ,SAAU;YACRJ,QAAQ;QACV;IACF,GAAG;QAACjB;QAAOD;QAAQgB;QAASS;QAAWvB;QAASC;QAAME;QAAOG;KAAO;IAEpE,MAAMkD,gBAAgBzI,YAAY;QAChCmG,mBAAmB;QACnBpI,WAAW,qBAAqB;YAAE2K,QAAQ;QAAU;QACpDvD;IACF,GAAG;QAACA;KAAW;IAEf,MAAMwD,WAAW3I,YAAY;QAC3BjC,WAAW,qBAAqB;YAAE2K,QAAQ;QAAK;QAC/C5C,QAAQ;IACV,GAAG,EAAE;IAEL,IAAIH,YAAY,SAAS,OAAO;IAEhC,4EAA4E;IAC5E,uEAAuE;IACvE,MAAMiD,OAAOtC,UAAWlB,gBAAAA,QAASD,aAAcA;IAE/C,MAAM0D,WAAWrC,YACb/F,yBAAyBsF,QAAQkB,KAAK,IACtCvG,qBAAqBqF,QAAQkB,KAAK,EAAE;QAClCE,cAAcpB,QAAQoB,YAAY;IACpC;IACJ,MAAM2B,eAAetC,YACjB,CAAC,YAAY,EAAEqC,SAASE,cAAc,CAAC,SAAS,QAAQ,EAAEnI,gCAAgC,8CAA8C,CAAC,GACzI,CAAC,MAAM,EAAEiI,SAASE,cAAc,CAAC,SAAS,mBAAmB,CAAC;IAElE,MAAMC,WAAWnD,SAAS,YAAY,CAACS;IAEvC,qBACE,MAACrH;QACCgK,IAAI;QACJC,UAAU;QACVC,SAASP;QACT5E,mBAAiB1C;QACjB,uEAAuE;QACvE,wEAAwE;QACxE,gEAAgE;QAChE,sEAAsE;QACtE,0CAA0C;QAC1C8H,WAAW;YAAEC,OAAO;gBAAEC,WAAW;gBAAGxH,IAAIP;YAAyB;QAAE;;0BAOnE,KAAC9C;gBACC8K,UAAS;gBACT7G,OAAM;gBACN4G,WAAW;gBACXE,iBAAiB;gBACjB1H,IAAI,aAAKP;oBAA0BkI,cAAc;oBAAG/F,aAAa;;0BAEjE,cAAA,MAAC/D;oBAAQyD,SAAQ;oBAAQtB,IAAI;wBAAE4H,KAAK;oBAAE;;sCACpC,KAACtK;4BACCuK,MAAK;4BACLjH,OAAM;4BACNoB,SAAS8E;4BACTnE,cAAW;sCAEX,cAAA,KAACpG;gCAAQqG,MAAM1G,mBAAmB0G,IAAI;;;sCAExC,KAAC7E;4BACCsD,IAAI7B;4BACJ8B,SAAQ;4BACRwB,WAAU;4BACVgF,MAAM;4BACN9H,IAAI;gCAAE+H,cAAc;gCAAYC,MAAM;4BAAE;sCAEvC;;sCAEH,KAACnL;4BAAO+D,OAAM;4BAAUoB,SAAS8E;4BAAMnE,cAAY6B,UAAU,UAAU;sCACpEA,UAAU,UAAU;;;;;0BAI3B,KAACnH;gBAAc2C,IAAI;oBAAEiI,IAAI;wBAAE1F,IAAI;wBAAGC,IAAI;oBAAE;gBAAE;0BACxC,cAAA,KAACtF;oBAAUgL,UAAUhB,WAAW,OAAO;oBAAMiB,cAAc;oBAACnI,IAAI;wBAAEoI,IAAI;4BAAE7F,IAAI;4BAAGC,IAAI;wBAAE;oBAAE;8BACrF,cAAA,MAAChF;wBAAM2C,SAAS;;0CACd,KAACxC;gCACC0K,YAAYnB,WAAW,IAAI;gCAC3BvE,cAAYuE,WAAW,gBAAgB;gCACvClH,IAAI;oCAAEkI,UAAU,CAACjI,QAAiBA,MAAME,OAAO,CAAC;oCAAKD,OAAO;oCAAQoI,IAAI;gCAAO;0CAE9E3I,YAAY4I,GAAG,CAAC,CAACC,sBAChB,KAAC/K;kDACC,cAAA,KAACC;sDAAW8K;;uCADHA;;0CAKf,MAAChL;gCAAM2C,SAAS;gCAAGH,IAAI;oCAAEyC,WAAWyE,WAAW,WAAW;gCAAO;;kDAC/D,KAACnJ;wCAAWuD,SAAQ;wCAAKwB,WAAU;kDAChCoE,WAAW,8BAA8B;;kDAE5C,KAACnJ;wCAAWuD,SAAQ;wCAAQV,OAAM;kDAC/BsG,WACG,qCACA,CAAC,kBAAkB,EAAElL,oBAAoB,0DAA0D,CAAC;;;;4BAG3GsI,wBAAU,KAAC5H;gCAAM+L,UAAS;0CAAQnE;;4BAClC4C,yBACC,MAACtK;gCACCoD,IAAI;oCACFM,SAAS;oCACToI,qBAAqB;wCAAEnG,IAAI;wCAAOC,IAAI;oCAAU;oCAChDoF,KAAK;gCACP;;kDAEA,KAAC9G;wCACCjB,QAAO;wCACPkB,MAAMzE,0BAA0BsG,IAAI;wCACpC5B,QAAO;wCACPC,OAAM;wCACNC,aAAY;wCACZC,MAAMiD;wCACNhD,UAAUuF;;kDAEZ,MAAC7F;wCACCjB,QAAO;wCACPkB,MAAM3E,YAAYwG,IAAI;wCACtB5B,QAAO;wCACPC,OAAM;wCACNC,aAAa,CAAC,2BAA2B,EAAElF,oBAAoB,qBAAqB,CAAC;wCACrFoF,UAAUyF;;0DAEV,KAAC7J;gDAAK0F,MAAK;gDAAQ9B,OAAM;gDAAU4H,OAAM;;4CACxC9D,2BACC,KAAC3G;gDAAWuD,SAAQ;gDAAUV,OAAM;0DACjC,CAAC,MAAM,EAAEpC,mBAAmB4G,GAAG,CAAC,uBAAuB,CAAC;;;;;iCAK/DZ,WAAWtB,sBACb,KAACpG;gCAAKwE,SAAQ;gCAAWtB,IAAI;oCAAEK,cAAc;oCAAGiC,GAAG;wCAAEC,IAAI;wCAAGC,IAAI;oCAAE;gCAAE;0CAClE,cAAA,KAACnD;oCACCmH,KAAKhC;oCACLtB,OAAOA;oCACPC,SAASA;oCACTK,MAAMA;oCACNmF,OACE,iFACA;oCAEF,8DAA8D;oCAC9DC,YAAY9B;;+CAIhB;;kDACE,MAACtJ;wCAAM2C,SAAS;wCAAG2C,WAAU;wCAAUH,cAAW;;0DAChD,KAACI;0DAAc;;0DACf,KAACnF;gDACCiL,SAAS;gDACTC,QAAQ;gDACRN,OAAM;gDACNO,aAAY;gDACZC,OAAO/E,QAAQgF,QAAQ;gDACvBC,UAAU,CAACC,QAAU5D,OAAO;wDAAE0D,UAAUE,MAAMC,MAAM,CAACJ,KAAK;oDAAC;gDAC3DK,YAAW;;0DAEb,KAACzM;gDAAIoD,IAAI;oDAAEM,SAAS;oDAAQgJ,UAAU;oDAAQ1B,KAAK;gDAAE;0DAClD3I,oBAAoBsJ,GAAG,CAAC,CAACgB,qBACxB,KAACvM;wDAECwL,OAAOe;wDACP7G,MAAK;wDACL9B,OAAOqD,QAAQgF,QAAQ,KAAKM,OAAO,YAAY;wDAC/CjI,SAAS2C,QAAQgF,QAAQ,KAAKM,OAAO,WAAW;wDAChDvH,SAAS,IAAMuD,OAAO;gEAAE0D,UAAUM;4DAAK;uDALlCA;;0DASX,KAAC3L;gDACCiL,SAAS;gDACTL,OAAM;gDACNO,aAAY;gDACZC,OAAO/E,QAAQuF,QAAQ;gDACvBN,UAAU,CAACC,QAAU5D,OAAO;wDAAEiE,UAAUL,MAAMC,MAAM,CAACJ,KAAK;oDAAC;gDAC3DK,YAAW;;;;kDAGf,MAAC7L;wCAAM2C,SAAS;wCAAG2C,WAAU;wCAAUH,cAAW;;0DAChD,KAACI;0DAAc;;0DACf,KAAChF;gDAAWuD,SAAQ;gDAAQV,OAAM;0DAC/B;;0DAEH,KAAChE;gDACCoD,IAAI;oDACFM,SAAS;oDACToI,qBAAqB;wDAAEnG,IAAI;wDAAOC,IAAI;oDAAU;oDAChDoF,KAAK;gDACP;0DAEC5I,uBAAuBuJ,GAAG,CAAC,CAACkB;oDAC3B,MAAMC,WAAWzF,QAAQwF,OAAO,KAAKA,QAAQpI,EAAE;oDAC/C,qBACE,KAACvE;wDAECwE,SAAQ;wDACRtB,IAAI,CAACC,QAAkB,CAAA;gEACrBI,cAAc;gEACduB,aAAa8H,WAAW,iBAAiB;gEACzChK,SAASgK,WAAW1L,MAAMiC,MAAMQ,OAAO,CAACkJ,OAAO,CAACjJ,IAAI,EAAE,QAAQ;4DAChE,CAAA;kEAEA,cAAA,KAAC3D;4DACC6M,gBAAcF;4DACd/G,cAAY,GAAG8G,QAAQjB,KAAK,CAAC,GAAG,EAAEiB,QAAQI,KAAK,EAAE;4DACjD7H,SAAS,IAAMuD,OAAO;oEAAEkE,SAASC,WAAW,OAAOD,QAAQpI,EAAE;gEAAC;4DAC9DrB,IAAI;gEAAEsC,GAAG;gEAAGlC,QAAQ;4DAAO;sEAE3B,cAAA,MAAC5C;gEAAMsM,WAAU;gEAAM3J,SAAS;gEAAKH,IAAI;oEAAEO,YAAY;gEAAa;;kFAClE,MAAC3D;wEAAIoD,IAAI;4EAAEgI,MAAM;4EAAG+B,UAAU;wEAAE;;0FAC9B,KAAChM;gFAAWuD,SAAQ;0FAAamI,QAAQjB,KAAK;;0FAC9C,KAACzK;gFAAWuD,SAAQ;gFAAQV,OAAM;0FAC/B6I,QAAQI,KAAK;;;;oEAGjBH,0BACC,KAAC9M;wEAAIoD,IAAI;4EAAEY,OAAO;4EAAgBN,SAAS;wEAAO;wEAAGP,aAAW;kFAC9D,cAAA,KAACxD;4EAAQqG,MAAMzG,eAAeyG,IAAI;;;;;;uDAvBrC6G,QAAQpI,EAAE;gDA8BrB;;;;kDAGJ,MAAC7D;wCAAM2C,SAAS;wCAAG2C,WAAU;wCAAUH,cAAW;;0DAChD,KAACI;0DAAc;;0DAMf,KAACnF;gDACCoM,MAAM;gDACNnB,SAAS;gDACTL,OAAM;gDACNQ,OAAO/E,QAAQgG,WAAW;gDAC1Bf,UAAU,CAACC,QACT5D,OAAO;wDAAE0E,aAAad,MAAMC,MAAM,CAACJ,KAAK;oDAAsB;gDAEhEK,YAAW;0DAEV3K,2BAA2B6J,GAAG,CAAC,CAAC2B,uBAC/B,KAAC3M;wDAAyByL,OAAOkB,OAAO7I,EAAE;kEACvC,GAAG6I,OAAO1B,KAAK,CAAC,GAAG,EAAE0B,OAAOL,KAAK,EAAE;uDADvBK,OAAO7I,EAAE;;0DAK5B,MAAC7D;gDAAMsM,WAAW;oDAAEvH,IAAI;oDAAUC,IAAI;gDAAM;gDAAGrC,SAAS;;kEACtD,KAACvC;wDACCoM,MAAM;wDACNnB,SAAS;wDACTL,OAAM;wDACNQ,OAAO/E,QAAQkB,KAAK;wDACpB+D,UAAU,CAACC,QAAU5D,OAAO;gEAAEJ,OAAOgF,OAAOhB,MAAMC,MAAM,CAACJ,KAAK;4DAAE;wDAChEK,YAAY3E,YAAYjG,0BAA0B4D;kEAEjD+H,MAAMC,IAAI,CACT;4DAAEC,QAAQ5E,KAAKN,GAAG,GAAGM,KAAK6E,GAAG,GAAG;wDAAE,GAClC,CAACC,GAAGC,QAAU/E,KAAK6E,GAAG,GAAGE,OACzBlC,GAAG,CAAC,CAACmC,sBACL,KAACnN;gEAAqByL,OAAO0B;0EAC1BA;+DADYA;;oDAKlB,CAAChG,2BACA,MAAC9G;wDACCoM,MAAM;wDACNnB,SAAS;wDACTL,OAAM;wDACNQ,OAAO/E,QAAQoB,YAAY,GAAG,QAAQ;wDACtC6D,UAAU,CAACC,QAAU5D,OAAO;gEAAEF,cAAc8D,MAAMC,MAAM,CAACJ,KAAK,KAAK;4DAAM;;0EAEzE,KAACzL;gEAASyL,OAAM;0EAAO;;0EACvB,KAACzL;gEAASyL,OAAM;0EAAM;;;;;;;;;;;;;;YAUvCjF,SAAS,cAAc,CAACS,WACvB;4EACoE,iBACpE,MAACpH;gBACC4C,IAAI;oBACFiI,IAAI;wBAAE1F,IAAI;wBAAGC,IAAI;oBAAE;oBACnB4F,IAAI;oBACJkB,UAAU;oBACVqB,QAAQ;oBACRC,WAAW;oBACXC,WAAW;oBACXjJ,aAAa;mBACVnC;;kCAGL,MAACjC;wBAAMsM,WAAU;wBAAM3J,SAAS;wBAAKH,IAAI;4BAAEO,YAAY;4BAAUuK,IAAI;4BAAQf,UAAU;wBAAE;;0CACvF,KAAChM;gCAAWuD,SAAQ;gCAAQV,OAAM;0CAC/B,GAAGoG,aAAa,CAAC,CAAC;;0CAErB,KAAClJ;gCAAQmD,OAAM;0CACb,cAAA,KAACrE;oCACCkG,WAAU;oCACViI,UAAU;oCACVpI,cAAW;oCACX3C,IAAI;wCAAEM,SAAS;wCAAeM,OAAO;oCAAiB;8CAEtD,cAAA,KAACrE;wCAAQqG,MAAMvG,sBAAsBuG,IAAI;wCAAE/B,UAAS;;;;;;oBAIzD4E,yBACC,KAAC1H;wBAAWuD,SAAQ;wBAAQV,OAAM;kCAC/B6E;;kCAGL,KAAC5I;wBAAOmF,SAAS,IAAMgC,QAAQ;kCAAY;;kCAC3C,KAACnH;wBACCyE,SAAQ;wBACRoB,MAAK;wBACLT,UAAUd,QAAQ6J,QAAQvF;wBAC1BzD,SAAS2D;wBACTsF,yBAAW,KAAC1O;4BAAQqG,MAAMxG,YAAYwG,IAAI;;kCAEzCzB,OAAO,cAAc;;;;;;AAMlC;AAEA,eAAe6B,gBAAe"}
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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"}
@@ -22,6 +22,17 @@ import { type AiJobsOpenRequest } from './ai-jobs-store';
22
22
  import { aiJobOutputHref, aiJobPrimaryLink } from './ai-job-links';
23
23
  import { readEventFrames } from './ai-job-events';
24
24
  export { aiJobOutputHref, aiJobPrimaryLink, readEventFrames };
25
+ /**
26
+ * Where a guided start that ended unbuilt is tried again (AGL-3596): its
27
+ * "Building your site" page, opened on its own answers (`?retry=1`). Only for
28
+ * a job of the site the console is on, whose subdomain the address names;
29
+ * `null` otherwise.
30
+ */
31
+ export declare function aiJobRestartHref(job: Pick<AiJobSummary, 'id' | 'kind' | 'status' | 'hostId' | 'siteInputs'>, input: {
32
+ orgSlug: string;
33
+ hostId?: string | null;
34
+ pathname: string;
35
+ }): string | null;
25
36
  /**
26
37
  * The navigation entry a page job proposes for the page it built (AGL-2907),
27
38
  * or `null`. The job writes no menu: the member adds the entry once the page
@@ -29,7 +29,8 @@ import { publishAiJob } from "./ai-jobs-store.js";
29
29
  import { AiPageBriefDialog } from "./ai-page-brief-dialog.component.js";
30
30
  import { AiInsightDialog } from "./ai-insight-dialog.component.js";
31
31
  import { AiJobPlan } from "./ai-job-plan.component.js";
32
- import { aiJobOutputHref, aiJobPrimaryLink } from "./ai-job-links.js";
32
+ import { aiJobOutputHref, aiJobPrimaryLink, aiSiteBuildHref } from "./ai-job-links.js";
33
+ import { aiJobRefundCopy } from "../model/ai-job-failure-copy.js";
33
34
  import { readEventFrames } from "./ai-job-events.js";
34
35
  // Where an output opens, and the stream reader, live beside the dialogs that
35
36
  // share them (AGL-3593); this module has always exported them.
@@ -77,6 +78,20 @@ export { aiJobOutputHref, aiJobPrimaryLink, readEventFrames };
77
78
  running: 'primary'
78
79
  };
79
80
  /** How long a job AI jobs was opened on stays highlighted. */ const HIGHLIGHT_MS = 2500;
81
+ /**
82
+ * Where a guided start that ended unbuilt is tried again (AGL-3596): its
83
+ * "Building your site" page, opened on its own answers (`?retry=1`). Only for
84
+ * a job of the site the console is on, whose subdomain the address names;
85
+ * `null` otherwise.
86
+ */ export function aiJobRestartHref(job, input) {
87
+ var _ref;
88
+ var _exec;
89
+ if (job.kind !== 'site' || job.status !== 'failed' && job.status !== 'canceled') return null;
90
+ if (!job.siteInputs || !job.hostId || job.hostId !== input.hostId) return null;
91
+ const subdomain = (_ref = (_exec = /^\/[^/]+\/hosts\/([^/?#]+)/.exec(input.pathname)) == null ? void 0 : _exec[1]) != null ? _ref : null;
92
+ const href = aiSiteBuildHref(input.orgSlug, subdomain, job.id);
93
+ return href ? `${href}?retry=1` : null;
94
+ }
80
95
  /** What a job cost the person: what it spent, less what we refunded. */ function netCredits(job) {
81
96
  var _job_creditsSpent, _job_refundedCredits;
82
97
  return Math.max(0, ((_job_creditsSpent = job.creditsSpent) != null ? _job_creditsSpent : 0) - ((_job_refundedCredits = job.refundedCredits) != null ? _job_refundedCredits : 0));
@@ -414,6 +429,11 @@ export function AssistJobsDrawer({ orgId, org, orgReady, orgSlug, user, visible,
414
429
  role: "list",
415
430
  "aria-label": "AI jobs",
416
431
  children: jobs.map((job)=>{
432
+ const restartHref = (row)=>aiJobRestartHref(row, {
433
+ orgSlug,
434
+ hostId,
435
+ pathname: typeof window === 'undefined' ? '' : window.location.pathname
436
+ });
417
437
  const stepsDone = job.steps.filter((step)=>step.status === 'done').length;
418
438
  const current = job.steps.find((step)=>step.status === 'running');
419
439
  const terminal = AI_JOB_TERMINAL_STATUSES.includes(job.status);
@@ -492,6 +512,22 @@ export function AssistJobsDrawer({ orgId, org, orgReady, orgSlug, user, visible,
492
512
  component: "div",
493
513
  children: job.error
494
514
  }),
515
+ aiJobRefundCopy(job) && /*#__PURE__*/ _jsx(Typography, {
516
+ variant: "caption",
517
+ color: "text.secondary",
518
+ component: "div",
519
+ children: aiJobRefundCopy(job)
520
+ }),
521
+ restartHref(job) ? /*#__PURE__*/ _jsx(Button, {
522
+ size: "small",
523
+ variant: "contained",
524
+ component: AppLink,
525
+ href: restartHref(job),
526
+ sx: {
527
+ mt: 0.5
528
+ },
529
+ children: 'Try again'
530
+ }) : null,
495
531
  primary ? /*#__PURE__*/ _jsx(Button, {
496
532
  size: "small",
497
533
  variant: "contained",
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../../../libs/plugins/ai/src/lib/components/assist-jobs-drawer.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\nimport { checkEntitlement } from '@aglyn/aglyn'\nimport { trackEvent } from '@aglyn/aglyn/app-utils/analytics-events'\nimport { formatBytes } from '@aglyn/aglyn/app-utils/measure-node-map'\nimport {\n AI_JOB_TERMINAL_STATUSES,\n type AiJobOutput,\n type AiJobSummary,\n} from '../model/ai-jobs.types'\nimport type { AglynOrgBilling } from '@aglyn/aglyn/foundation/definitions/org-billing.types'\nimport { mdiChevronDown, mdiChevronUp } from '@aglyn/shared-data-mdi'\nimport { AppLink, MdiIcon } from '@aglyn/shared-ui-jsx'\nimport { authorizedFetch } from '@aglyn/shared-util-http/authorized-token'\nimport {\n Box,\n Button,\n Chip,\n CircularProgress,\n Collapse,\n IconButton,\n Stack,\n Typography,\n} from '@mui/material'\nimport { useCallback, useEffect, useRef, useState } from 'react'\nimport {\n AI_JOB_PHASE_LABELS,\n aiJobActivityCounts,\n aiJobPhase,\n aiJobsHeaderChips,\n type AiJobActivityState,\n type AiJobPhase,\n} from '../model/ai-job-activity'\nimport type { AiInsightSurface } from '../model/ai-insight'\nimport { cancelAiJobRequest, resumeAiJobRequest } from './ai-job-requests'\nimport { publishAiJob, type AiJobsOpenRequest } from './ai-jobs-store'\nimport { AiPageBriefDialog } from './ai-page-brief-dialog.component'\nimport { AiInsightDialog } from './ai-insight-dialog.component'\nimport { AiJobPlan } from './ai-job-plan.component'\nimport { aiJobOutputHref, aiJobPrimaryLink } from './ai-job-links'\nimport { readEventFrames } from './ai-job-events'\n\n// Where an output opens, and the stream reader, live beside the dialogs that\n// share them (AGL-3593); this module has always exported them.\nexport { aiJobOutputHref, aiJobPrimaryLink, readEventFrames }\n\n/**\n * The AI jobs drawer inside the Assist panel (AGL-2904): the workspace's\n * running and recent generation jobs, each step's progress, an \"open\n * draft\" link per output, and cancel.\n *\n * Reads through the routes, never Firestore directly, so the same\n * membership, flag and entitlement rungs answer every read; progress comes\n * from the events route's server-sent stream, re-opened when the server\n * says `reconnect`. Everything loads on EXPAND rather than on mount: the\n * panel opens on every console page, and a list nobody asked for is a read\n * on every page view.\n *\n * It opens EXPANDED while any of the workspace's jobs is moving or waiting\n * for the person (AGL-3593) — the shared list the top-bar indicator reads\n * says so — because a plan waiting behind a collapsed row is a site that\n * never gets built. An \"Open AI jobs\" anywhere in the console expands it,\n * scrolls to the job it names and highlights it for a moment.\n *\n * Hidden — not disabled — unless the flag shows it AND the plan carries\n * `aiGenerative`: a released-off feature does not exist, and a plan without\n * it is sold the add-on on the Billing page, not here.\n */\n\n/** Jobs the drawer lists; the route caps higher, the drawer is a glance. */\nconst LIST_LIMIT = 10\n\n/** How much of a brief a row shows. */\nconst BRIEF_PREVIEW_CHARS = 90\n\n/**\n * A row's chip says where the job stands in the words every AI surface uses\n * (AGL-3593): a plan waiting to be confirmed is \"Plan ready\", never \"Running\"\n * and never the machine's `needs_review`.\n */\nconst PHASE_COLOR: Record<AiJobPhase, 'default' | 'primary' | 'success' | 'error' | 'warning'> = {\n queued: 'default',\n planning: 'primary',\n 'plan-ready': 'warning',\n building: 'primary',\n attention: 'warning',\n done: 'success',\n failed: 'error',\n canceled: 'default',\n}\n\n/** The header's count chips, colored as the rows they count. */\nconst STATE_COLOR: Record<AiJobActivityState, 'primary' | 'warning'> = {\n 'needs-you': 'warning',\n attention: 'warning',\n running: 'primary',\n}\n\n/** How long a job AI jobs was opened on stays highlighted. */\nconst HIGHLIGHT_MS = 2_500\n\n/** What a job cost the person: what it spent, less what we refunded. */\nfunction netCredits(job: Pick<AiJobSummary, 'creditsSpent' | 'refundedCredits'>): number {\n return Math.max(0, (job.creditsSpent ?? 0) - (job.refundedCredits ?? 0))\n}\n\n/**\n * The navigation entry a page job proposes for the page it built (AGL-2907),\n * or `null`. The job writes no menu: the member adds the entry once the page\n * is live.\n */\nexport function aiJobNavigationProposal(output: AiJobOutput): string | null {\n if (output.resource !== 'screen') return null\n const navigation = output.proposal?.['navigation']\n if (!navigation || typeof navigation !== 'object') return null\n const label = (navigation as Record<string, unknown>)['label']\n return typeof label === 'string' && label.trim() ? label.trim() : null\n}\n\n\nexport interface AssistJobsDrawerProps {\n /** The org the panel is scoped to — `undefined` where the page named none. */\n orgId: string | undefined\n org: Partial<AglynOrgBilling> | undefined\n orgReady: boolean\n orgSlug: string\n user: Parameters<typeof authorizedFetch>[0]\n /** The `release_ai_generative` verdict, staff bypass applied (the shell's). */\n visible: boolean\n /**\n * The viewer is staff (AGL-3078): a job that stopped for a broken rule shows\n * them where the refused answer broke it. Who may read a job is unchanged.\n */\n isStaff?: boolean\n /** The site the console page is on, when it is on one: a page is described for a site. */\n hostId?: string | null\n /**\n * The page's insight surface (AGL-2915) — a site's Analytics, Data or CRM\n * Reports page, or the workspace's Data page — with the site's subdomain;\n * `null` elsewhere, where no question about the figures is offered.\n */\n insight?: { surface: Exclude<AiInsightSurface, 'digest'>; host: string | null } | null\n /**\n * The workspace's jobs that are not yet settled, from the shared store the\n * top-bar indicator reads (AGL-3593). The header counts them, and the\n * drawer opens expanded while there is any. Absent, the drawer counts what\n * it loaded itself.\n */\n inFlight?: readonly AiJobSummary[]\n /**\n * The latest request to open AI jobs (AGL-3593): a new `seq` expands the\n * drawer, and a named job is scrolled to and highlighted.\n */\n focus?: AiJobsOpenRequest | null\n}\n\nexport function AssistJobsDrawer({\n orgId,\n org,\n orgReady,\n orgSlug,\n user,\n visible,\n isStaff = false,\n hostId,\n insight,\n inFlight,\n focus,\n}: AssistJobsDrawerProps): JSX.Element | null {\n const entitled = orgReady && checkEntitlement(org as never, 'aiGenerative')\n const [expanded, setExpanded] = useState(false)\n /**\n * The person opened or closed the list themselves: from then on the\n * expanded-by-default rule leaves their choice alone until the workspace\n * changes.\n */\n const toggledRef = useRef(false)\n /** The job AI jobs was opened on, highlighted for a moment once it is listed. */\n const [highlight, setHighlight] = useState<string | null>(null)\n const listRef = useRef<HTMLDivElement | null>(null)\n const [jobs, setJobs] = useState<AiJobSummary[]>([])\n const [loading, setLoading] = useState(false)\n const [notice, setNotice] = useState<string | null>(null)\n /** Whether the page brief dialog is open (AGL-2907). */\n const [describing, setDescribing] = useState(false)\n /**\n * The insight dialog (AGL-2915): `'ask'` for a new question, a job id for an\n * answer a job already wrote, `null` when closed.\n */\n const [insightOpen, setInsightOpen] = useState<string | null>(null)\n /** Job ids whose terminal event has been tracked, so a re-read does not count twice. */\n const trackedRef = useRef(new Set<string>())\n /** The job whose stream is open, so a re-render does not open a second. */\n const watchingRef = useRef<string | null>(null)\n\n const patchJob = useCallback((next: AiJobSummary) => {\n // Every counting surface moves with the row (AGL-3593).\n publishAiJob(next)\n setJobs((prior) => {\n const index = prior.findIndex((job) => job.id === next.id)\n if (index === -1) return [next, ...prior].slice(0, LIST_LIMIT)\n const copy = [...prior]\n copy[index] = next\n return copy\n })\n if (\n AI_JOB_TERMINAL_STATUSES.includes(next.status) &&\n !trackedRef.current.has(next.id)\n ) {\n trackedRef.current.add(next.id)\n if (next.status === 'done') {\n trackEvent('ai_job_completed', { kind: next.kind, credits: next.creditsSpent })\n } else if (next.status === 'failed') {\n trackEvent('ai_job_failed', { kind: next.kind })\n }\n }\n }, [])\n\n const load = useCallback(async () => {\n if (!orgId) return\n setLoading(true)\n setNotice(null)\n try {\n const response = await authorizedFetch(\n user,\n `/api/ai/jobs?orgId=${encodeURIComponent(orgId)}&limit=${LIST_LIMIT}`,\n )\n if (!response.ok) {\n const payload = await response.json().catch(() => null)\n setNotice(String(payload?.error ?? 'The AI jobs could not be loaded — try again.'))\n return\n }\n const payload = (await response.json()) as { jobs: AiJobSummary[] }\n // Every job that arrives already terminal is one the drawer did not\n // watch finish, so its outcome is not this session's to count.\n for (const job of payload.jobs) {\n if (AI_JOB_TERMINAL_STATUSES.includes(job.status)) trackedRef.current.add(job.id)\n // A job the indicator still counts that has settled since leaves it.\n publishAiJob(job)\n }\n setJobs(payload.jobs)\n } catch {\n setNotice('The AI jobs could not be loaded — try again.')\n } finally {\n setLoading(false)\n }\n }, [orgId, user])\n\n useEffect(() => {\n if (expanded) void load()\n }, [expanded, load])\n\n // Reset when the panel's org changes: a list from one workspace must not\n // show under another's key while the new one loads.\n useEffect(() => {\n setJobs([])\n setExpanded(false)\n toggledRef.current = false\n watchingRef.current = null\n }, [orgId])\n\n // Expanded by default while anything is moving or waiting (AGL-3593): a\n // plan waiting to be confirmed behind a collapsed row is a site that never\n // gets built. Otherwise collapsed, which reads nothing until asked.\n const anyInFlight = (inFlight?.length ?? 0) > 0\n useEffect(() => {\n if (anyInFlight && !toggledRef.current) setExpanded(true)\n }, [anyInFlight])\n\n // A request to open AI jobs (AGL-3593): expand, read the list again so a\n // job created a moment ago is in it, and highlight the job named.\n const focusSeq = focus?.seq ?? 0\n const focusJobId = focus?.jobId ?? null\n const expandedRef = useRef(expanded)\n expandedRef.current = expanded\n useEffect(() => {\n if (!focusSeq) return\n toggledRef.current = true\n setHighlight(focusJobId)\n // An open list does not re-run the expand effect's read, so it reads here.\n if (expandedRef.current) void load()\n else setExpanded(true)\n // Only a new request runs this; `load` and the job are read as they stand.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [focusSeq])\n\n // Scroll to the highlighted job once it is listed, then let it fade.\n const highlightListed = highlight !== null && jobs.some((job) => job.id === highlight)\n useEffect(() => {\n if (!highlight || !highlightListed) return undefined\n const row = Array.from(\n listRef.current?.querySelectorAll<HTMLElement>('[data-ai-job-id]') ?? [],\n ).find((element) => element.dataset['aiJobId'] === highlight)\n row?.scrollIntoView?.({ block: 'nearest', behavior: 'smooth' })\n const timer = setTimeout(() => setHighlight(null), HIGHLIGHT_MS)\n return () => clearTimeout(timer)\n }, [highlight, highlightListed])\n\n // Watch the most recent job that is still moving. One stream at a time:\n // the route re-reads a document every two seconds per open stream, and a\n // drawer with three running jobs does not need three of them.\n const watched = jobs.find((job) => !AI_JOB_TERMINAL_STATUSES.includes(job.status))\n const watchedId = watched?.id ?? null\n useEffect(() => {\n if (!expanded || !orgId || !watchedId || watchingRef.current === watchedId) return\n watchingRef.current = watchedId\n const controller = new AbortController()\n const watch = async () => {\n // The server closes a stream at its deadline with `reconnect`; the\n // loop here re-opens it until the job settles or the drawer unmounts.\n let again = true\n while (again && !controller.signal.aborted) {\n again = false\n try {\n const response = await authorizedFetch(\n user,\n `/api/ai/jobs/${encodeURIComponent(watchedId)}/events?orgId=${encodeURIComponent(orgId)}`,\n { signal: controller.signal },\n )\n if (!response.ok || !response.body) return\n await readEventFrames(response.body, (event) => {\n if (event['type'] === 'state') patchJob(event['job'] as AiJobSummary)\n else if (event['type'] === 'reconnect') again = true\n else if (event['type'] === 'gone') {\n setJobs((prior) => prior.filter((job) => job.id !== watchedId))\n }\n })\n } catch {\n // The stream ended without a terminal state — a network blip or\n // the drawer closing. The next expand reloads the list.\n return\n }\n }\n }\n void watch().finally(() => {\n if (watchingRef.current === watchedId) watchingRef.current = null\n })\n return () => {\n controller.abort()\n if (watchingRef.current === watchedId) watchingRef.current = null\n }\n }, [expanded, orgId, watchedId, user, patchJob])\n\n // The same door the dialog that started the job cancels through (AGL-3593).\n const cancel = useCallback(\n async (jobId: string) => {\n if (!orgId) return\n const { job, error } = await cancelAiJobRequest(user, orgId, jobId)\n if (error) {\n setNotice(error)\n return\n }\n if (job) patchJob(job)\n },\n [orgId, user, patchJob],\n )\n\n /** The job whose resume is in flight, so its button cannot send twice. */\n const [resuming, setResuming] = useState<string | null>(null)\n\n // Confirms a plan, or tries again a step whose answer broke a building\n // rule (AGL-2935). The door runs the next step inline and answers with the\n // job, so the row moves on without waiting for the stream.\n const resume = useCallback(\n async (job: AiJobSummary) => {\n if (!orgId) return\n setResuming(job.id)\n setNotice(null)\n // The same door the dialog that started the job confirms through (AGL-3593).\n const { job: next, error } = await resumeAiJobRequest(user, orgId, job)\n if (next) patchJob(next)\n if (error) setNotice(error)\n setResuming(null)\n },\n [orgId, user, patchJob],\n )\n\n if (!visible || !orgId || !entitled) return null\n\n // Counted by state, never as one \"running\" figure (AGL-3593): a plan waiting\n // to be confirmed needs the person, and a stopped job is not moving.\n const chips = aiJobsHeaderChips(aiJobActivityCounts(inFlight ?? jobs))\n\n return (\n <Box sx={{ mb: 2, borderBottom: 1, borderColor: 'divider', pb: 1 }}>\n <Stack direction=\"row\" spacing={1} sx={{ alignItems: 'center' }}>\n <Typography variant=\"subtitle2\" sx={{ flexGrow: 1 }}>\n AI jobs\n {chips.map((chip) => (\n <Chip\n key={chip.state}\n size=\"small\"\n color={STATE_COLOR[chip.state]}\n label={chip.label}\n sx={{ ml: 1 }}\n />\n ))}\n </Typography>\n {/* A question about the page's figures (AGL-2915). */}\n {insight && (\n <Button size=\"small\" onClick={() => setInsightOpen('ask')}>\n Ask about your numbers\n </Button>\n )}\n {/* A page from a brief (AGL-2907), on a site's own routes. */}\n {hostId && (\n <Button size=\"small\" onClick={() => setDescribing(true)}>\n Describe a page\n </Button>\n )}\n <IconButton\n size=\"small\"\n aria-label={expanded ? 'Hide AI jobs' : 'Show AI jobs'}\n aria-expanded={expanded}\n onClick={() => {\n toggledRef.current = true\n setExpanded((prior) => !prior)\n }}\n >\n <MdiIcon\n path={expanded ? mdiChevronUp.path : mdiChevronDown.path}\n sx={{ fontSize: 18 }}\n />\n </IconButton>\n </Stack>\n <Collapse in={expanded} unmountOnExit>\n {notice && (\n <Typography variant=\"caption\" color=\"error\" component=\"div\" sx={{ mt: 0.5 }}>\n {notice}\n </Typography>\n )}\n {loading && !jobs.length && (\n <CircularProgress size={16} sx={{ mt: 1 }} aria-label=\"Loading AI jobs\" />\n )}\n {!loading && !jobs.length && !notice && (\n <Typography variant=\"caption\" color=\"text.secondary\" component=\"div\" sx={{ mt: 0.5 }}>\n No AI jobs yet.\n </Typography>\n )}\n <Stack ref={listRef} spacing={1} sx={{ mt: 1 }} role=\"list\" aria-label=\"AI jobs\">\n {jobs.map((job) => {\n const stepsDone = job.steps.filter((step) => step.status === 'done').length\n const current = job.steps.find((step) => step.status === 'running')\n const terminal = AI_JOB_TERMINAL_STATUSES.includes(job.status)\n const phase = aiJobPhase(job)\n const primary = aiJobPrimaryLink(job, orgSlug)\n const highlighted = highlight === job.id\n return (\n <Box\n key={job.id}\n role=\"listitem\"\n data-ai-job-id={job.id}\n aria-current={highlighted ? 'true' : undefined}\n sx={{\n borderRadius: 1,\n bgcolor: highlighted ? 'action.selected' : 'action.hover',\n outline: 2,\n outlineColor: highlighted ? 'primary.main' : 'transparent',\n transition: (theme) =>\n theme.transitions.create(['background-color', 'outline-color'], {\n duration: theme.transitions.duration.standard,\n }),\n px: 1.5,\n py: 1,\n }}\n >\n <Stack direction=\"row\" spacing={1} sx={{ alignItems: 'center' }}>\n <Chip size=\"small\" variant=\"outlined\" label={job.kind} />\n <Chip size=\"small\" color={PHASE_COLOR[phase]} label={AI_JOB_PHASE_LABELS[phase]} />\n <Typography variant=\"caption\" color=\"text.secondary\" sx={{ flexGrow: 1 }}>\n {stepsDone}/{job.steps.length} steps\n {current ? ` — ${current.name}` : ''}\n {/* Net of what a failure on our side gave back (AGL-3594). */}\n {netCredits(job) > 0 ? ` · ${netCredits(job)} credits` : ''}\n </Typography>\n {!terminal && (\n <Button size=\"small\" onClick={() => void cancel(job.id)}>\n Cancel\n </Button>\n )}\n </Stack>\n <Typography variant=\"body2\" sx={{ mt: 0.5, wordBreak: 'break-word' }}>\n {job.brief.length > BRIEF_PREVIEW_CHARS\n ? `${job.brief.slice(0, BRIEF_PREVIEW_CHARS)}…`\n : job.brief}\n </Typography>\n {job.error && (\n <Typography variant=\"caption\" color={job.status === 'failed' ? 'error' : 'warning.main'} component=\"div\">\n {job.error}\n </Typography>\n )}\n {/* What a finished job built, first (AGL-3593). */}\n {primary ? (\n <Button\n size=\"small\"\n variant=\"contained\"\n component={AppLink}\n href={primary.href}\n sx={{ mt: 0.5 }}\n >\n {primary.label}\n </Button>\n ) : null}\n {job.outputs.map((output, index) => {\n const href = aiJobOutputHref(output, orgSlug)\n const navigation = aiJobNavigationProposal(output)\n return (\n <Box key={`${output.resource}:${output.id}:${index}`} sx={{ mt: 0.5 }}>\n {output.resource === 'insight' ? (\n <Button size=\"small\" onClick={() => setInsightOpen(output.id)}>\n View answer\n </Button>\n ) : href ? (\n <AppLink componentVariant=\"naked\" href={href}>\n Open draft — {output.label}\n </AppLink>\n ) : output.text ? (\n <Typography\n variant=\"body2\"\n component=\"pre\"\n sx={{ whiteSpace: 'pre-wrap', fontFamily: 'inherit', m: 0 }}\n >\n {output.text}\n </Typography>\n ) : (\n <Typography variant=\"caption\" color=\"text.secondary\">\n {output.label}\n </Typography>\n )}\n {output.load ? (\n <Typography variant=\"caption\" color=\"text.secondary\" component=\"div\">\n About {formatBytes(output.load.totalBytes)} on a first visit\n </Typography>\n ) : null}\n {output.note ? (\n <Typography variant=\"caption\" color=\"text.secondary\" component=\"div\">\n {output.note}\n </Typography>\n ) : null}\n {navigation ? (\n <Typography variant=\"caption\" color=\"text.secondary\" component=\"div\">\n Add “{navigation}” to your navigation once the page is live.\n </Typography>\n ) : null}\n </Box>\n )\n })}\n <AiJobPlan\n job={job}\n onResume={(target) => void resume(target)}\n busy={resuming === job.id}\n staff={isStaff}\n user={user}\n />\n </Box>\n )\n })}\n </Stack>\n </Collapse>\n {/*\n The brief dialog (AGL-2907). It starts a job and closes; the list\n below it is the only place the job is watched, so an open list reads\n the new job back as soon as the dialog hands it over.\n */}\n {insightOpen !== null && (\n <AiInsightDialog\n open\n onClose={() => {\n setInsightOpen(null)\n if (expanded) void load()\n }}\n orgId={orgId}\n orgSlug={orgSlug}\n hostId={insight?.host ? (hostId ?? null) : null}\n host={insight?.host ?? null}\n surface={insight?.surface ?? 'analytics'}\n user={user}\n uid={(user as { uid?: string } | null | undefined)?.uid ?? null}\n jobId={insightOpen === 'ask' ? null : insightOpen}\n />\n )}\n {hostId && (\n <AiPageBriefDialog\n open={describing}\n onClose={() => {\n setDescribing(false)\n if (expanded) void load()\n }}\n orgId={orgId}\n hostId={hostId}\n user={user}\n orgSlug={orgSlug}\n isStaff={isStaff}\n />\n )}\n </Box>\n )\n}\n\nexport default AssistJobsDrawer\n"],"names":["checkEntitlement","trackEvent","formatBytes","AI_JOB_TERMINAL_STATUSES","mdiChevronDown","mdiChevronUp","AppLink","MdiIcon","authorizedFetch","Box","Button","Chip","CircularProgress","Collapse","IconButton","Stack","Typography","useCallback","useEffect","useRef","useState","AI_JOB_PHASE_LABELS","aiJobActivityCounts","aiJobPhase","aiJobsHeaderChips","cancelAiJobRequest","resumeAiJobRequest","publishAiJob","AiPageBriefDialog","AiInsightDialog","AiJobPlan","aiJobOutputHref","aiJobPrimaryLink","readEventFrames","LIST_LIMIT","BRIEF_PREVIEW_CHARS","PHASE_COLOR","queued","planning","building","attention","done","failed","canceled","STATE_COLOR","running","HIGHLIGHT_MS","netCredits","job","Math","max","creditsSpent","refundedCredits","aiJobNavigationProposal","output","resource","navigation","proposal","label","trim","AssistJobsDrawer","orgId","org","orgReady","orgSlug","user","visible","isStaff","hostId","insight","inFlight","focus","entitled","expanded","setExpanded","toggledRef","highlight","setHighlight","listRef","jobs","setJobs","loading","setLoading","notice","setNotice","describing","setDescribing","insightOpen","setInsightOpen","trackedRef","Set","watchingRef","patchJob","next","prior","index","findIndex","id","slice","copy","includes","status","current","has","add","kind","credits","load","response","encodeURIComponent","ok","payload","json","catch","String","error","anyInFlight","length","focusSeq","seq","focusJobId","jobId","expandedRef","highlightListed","some","row","undefined","Array","from","querySelectorAll","find","element","dataset","scrollIntoView","block","behavior","timer","setTimeout","clearTimeout","watched","watchedId","controller","AbortController","watch","again","signal","aborted","body","event","filter","finally","abort","cancel","resuming","setResuming","resume","chips","sx","mb","borderBottom","borderColor","pb","direction","spacing","alignItems","variant","flexGrow","map","chip","size","color","state","ml","onClick","aria-label","aria-expanded","path","fontSize","in","unmountOnExit","component","mt","ref","role","stepsDone","steps","step","terminal","phase","primary","highlighted","data-ai-job-id","aria-current","borderRadius","bgcolor","outline","outlineColor","transition","theme","transitions","create","duration","standard","px","py","name","wordBreak","brief","href","outputs","componentVariant","text","whiteSpace","fontFamily","m","totalBytes","note","onResume","target","busy","staff","open","onClose","host","surface","uid"],"mappings":"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"}
1
+ {"version":3,"sources":["../../../../../../../libs/plugins/ai/src/lib/components/assist-jobs-drawer.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\nimport { checkEntitlement } from '@aglyn/aglyn'\nimport { trackEvent } from '@aglyn/aglyn/app-utils/analytics-events'\nimport { formatBytes } from '@aglyn/aglyn/app-utils/measure-node-map'\nimport {\n AI_JOB_TERMINAL_STATUSES,\n type AiJobOutput,\n type AiJobSummary,\n} from '../model/ai-jobs.types'\nimport type { AglynOrgBilling } from '@aglyn/aglyn/foundation/definitions/org-billing.types'\nimport { mdiChevronDown, mdiChevronUp } from '@aglyn/shared-data-mdi'\nimport { AppLink, MdiIcon } from '@aglyn/shared-ui-jsx'\nimport { authorizedFetch } from '@aglyn/shared-util-http/authorized-token'\nimport {\n Box,\n Button,\n Chip,\n CircularProgress,\n Collapse,\n IconButton,\n Stack,\n Typography,\n} from '@mui/material'\nimport { useCallback, useEffect, useRef, useState } from 'react'\nimport {\n AI_JOB_PHASE_LABELS,\n aiJobActivityCounts,\n aiJobPhase,\n aiJobsHeaderChips,\n type AiJobActivityState,\n type AiJobPhase,\n} from '../model/ai-job-activity'\nimport type { AiInsightSurface } from '../model/ai-insight'\nimport { cancelAiJobRequest, resumeAiJobRequest } from './ai-job-requests'\nimport { publishAiJob, type AiJobsOpenRequest } from './ai-jobs-store'\nimport { AiPageBriefDialog } from './ai-page-brief-dialog.component'\nimport { AiInsightDialog } from './ai-insight-dialog.component'\nimport { AiJobPlan } from './ai-job-plan.component'\nimport { aiJobOutputHref, aiJobPrimaryLink, aiSiteBuildHref } from './ai-job-links'\nimport { aiJobRefundCopy } from '../model/ai-job-failure-copy'\nimport { readEventFrames } from './ai-job-events'\n\n// Where an output opens, and the stream reader, live beside the dialogs that\n// share them (AGL-3593); this module has always exported them.\nexport { aiJobOutputHref, aiJobPrimaryLink, readEventFrames }\n\n/**\n * The AI jobs drawer inside the Assist panel (AGL-2904): the workspace's\n * running and recent generation jobs, each step's progress, an \"open\n * draft\" link per output, and cancel.\n *\n * Reads through the routes, never Firestore directly, so the same\n * membership, flag and entitlement rungs answer every read; progress comes\n * from the events route's server-sent stream, re-opened when the server\n * says `reconnect`. Everything loads on EXPAND rather than on mount: the\n * panel opens on every console page, and a list nobody asked for is a read\n * on every page view.\n *\n * It opens EXPANDED while any of the workspace's jobs is moving or waiting\n * for the person (AGL-3593) — the shared list the top-bar indicator reads\n * says so — because a plan waiting behind a collapsed row is a site that\n * never gets built. An \"Open AI jobs\" anywhere in the console expands it,\n * scrolls to the job it names and highlights it for a moment.\n *\n * Hidden — not disabled — unless the flag shows it AND the plan carries\n * `aiGenerative`: a released-off feature does not exist, and a plan without\n * it is sold the add-on on the Billing page, not here.\n */\n\n/** Jobs the drawer lists; the route caps higher, the drawer is a glance. */\nconst LIST_LIMIT = 10\n\n/** How much of a brief a row shows. */\nconst BRIEF_PREVIEW_CHARS = 90\n\n/**\n * A row's chip says where the job stands in the words every AI surface uses\n * (AGL-3593): a plan waiting to be confirmed is \"Plan ready\", never \"Running\"\n * and never the machine's `needs_review`.\n */\nconst PHASE_COLOR: Record<AiJobPhase, 'default' | 'primary' | 'success' | 'error' | 'warning'> = {\n queued: 'default',\n planning: 'primary',\n 'plan-ready': 'warning',\n building: 'primary',\n attention: 'warning',\n done: 'success',\n failed: 'error',\n canceled: 'default',\n}\n\n/** The header's count chips, colored as the rows they count. */\nconst STATE_COLOR: Record<AiJobActivityState, 'primary' | 'warning'> = {\n 'needs-you': 'warning',\n attention: 'warning',\n running: 'primary',\n}\n\n/** How long a job AI jobs was opened on stays highlighted. */\nconst HIGHLIGHT_MS = 2_500\n\n/**\n * Where a guided start that ended unbuilt is tried again (AGL-3596): its\n * \"Building your site\" page, opened on its own answers (`?retry=1`). Only for\n * a job of the site the console is on, whose subdomain the address names;\n * `null` otherwise.\n */\nexport function aiJobRestartHref(\n job: Pick<AiJobSummary, 'id' | 'kind' | 'status' | 'hostId' | 'siteInputs'>,\n input: { orgSlug: string; hostId?: string | null; pathname: string },\n): string | null {\n if (job.kind !== 'site' || (job.status !== 'failed' && job.status !== 'canceled')) return null\n if (!job.siteInputs || !job.hostId || job.hostId !== input.hostId) return null\n const subdomain = /^\\/[^/]+\\/hosts\\/([^/?#]+)/.exec(input.pathname)?.[1] ?? null\n const href = aiSiteBuildHref(input.orgSlug, subdomain, job.id)\n return href ? `${href}?retry=1` : null\n}\n\n/** What a job cost the person: what it spent, less what we refunded. */\nfunction netCredits(job: Pick<AiJobSummary, 'creditsSpent' | 'refundedCredits'>): number {\n return Math.max(0, (job.creditsSpent ?? 0) - (job.refundedCredits ?? 0))\n}\n\n/**\n * The navigation entry a page job proposes for the page it built (AGL-2907),\n * or `null`. The job writes no menu: the member adds the entry once the page\n * is live.\n */\nexport function aiJobNavigationProposal(output: AiJobOutput): string | null {\n if (output.resource !== 'screen') return null\n const navigation = output.proposal?.['navigation']\n if (!navigation || typeof navigation !== 'object') return null\n const label = (navigation as Record<string, unknown>)['label']\n return typeof label === 'string' && label.trim() ? label.trim() : null\n}\n\n\nexport interface AssistJobsDrawerProps {\n /** The org the panel is scoped to — `undefined` where the page named none. */\n orgId: string | undefined\n org: Partial<AglynOrgBilling> | undefined\n orgReady: boolean\n orgSlug: string\n user: Parameters<typeof authorizedFetch>[0]\n /** The `release_ai_generative` verdict, staff bypass applied (the shell's). */\n visible: boolean\n /**\n * The viewer is staff (AGL-3078): a job that stopped for a broken rule shows\n * them where the refused answer broke it. Who may read a job is unchanged.\n */\n isStaff?: boolean\n /** The site the console page is on, when it is on one: a page is described for a site. */\n hostId?: string | null\n /**\n * The page's insight surface (AGL-2915) — a site's Analytics, Data or CRM\n * Reports page, or the workspace's Data page — with the site's subdomain;\n * `null` elsewhere, where no question about the figures is offered.\n */\n insight?: { surface: Exclude<AiInsightSurface, 'digest'>; host: string | null } | null\n /**\n * The workspace's jobs that are not yet settled, from the shared store the\n * top-bar indicator reads (AGL-3593). The header counts them, and the\n * drawer opens expanded while there is any. Absent, the drawer counts what\n * it loaded itself.\n */\n inFlight?: readonly AiJobSummary[]\n /**\n * The latest request to open AI jobs (AGL-3593): a new `seq` expands the\n * drawer, and a named job is scrolled to and highlighted.\n */\n focus?: AiJobsOpenRequest | null\n}\n\nexport function AssistJobsDrawer({\n orgId,\n org,\n orgReady,\n orgSlug,\n user,\n visible,\n isStaff = false,\n hostId,\n insight,\n inFlight,\n focus,\n}: AssistJobsDrawerProps): JSX.Element | null {\n const entitled = orgReady && checkEntitlement(org as never, 'aiGenerative')\n const [expanded, setExpanded] = useState(false)\n /**\n * The person opened or closed the list themselves: from then on the\n * expanded-by-default rule leaves their choice alone until the workspace\n * changes.\n */\n const toggledRef = useRef(false)\n /** The job AI jobs was opened on, highlighted for a moment once it is listed. */\n const [highlight, setHighlight] = useState<string | null>(null)\n const listRef = useRef<HTMLDivElement | null>(null)\n const [jobs, setJobs] = useState<AiJobSummary[]>([])\n const [loading, setLoading] = useState(false)\n const [notice, setNotice] = useState<string | null>(null)\n /** Whether the page brief dialog is open (AGL-2907). */\n const [describing, setDescribing] = useState(false)\n /**\n * The insight dialog (AGL-2915): `'ask'` for a new question, a job id for an\n * answer a job already wrote, `null` when closed.\n */\n const [insightOpen, setInsightOpen] = useState<string | null>(null)\n /** Job ids whose terminal event has been tracked, so a re-read does not count twice. */\n const trackedRef = useRef(new Set<string>())\n /** The job whose stream is open, so a re-render does not open a second. */\n const watchingRef = useRef<string | null>(null)\n\n const patchJob = useCallback((next: AiJobSummary) => {\n // Every counting surface moves with the row (AGL-3593).\n publishAiJob(next)\n setJobs((prior) => {\n const index = prior.findIndex((job) => job.id === next.id)\n if (index === -1) return [next, ...prior].slice(0, LIST_LIMIT)\n const copy = [...prior]\n copy[index] = next\n return copy\n })\n if (\n AI_JOB_TERMINAL_STATUSES.includes(next.status) &&\n !trackedRef.current.has(next.id)\n ) {\n trackedRef.current.add(next.id)\n if (next.status === 'done') {\n trackEvent('ai_job_completed', { kind: next.kind, credits: next.creditsSpent })\n } else if (next.status === 'failed') {\n trackEvent('ai_job_failed', { kind: next.kind })\n }\n }\n }, [])\n\n const load = useCallback(async () => {\n if (!orgId) return\n setLoading(true)\n setNotice(null)\n try {\n const response = await authorizedFetch(\n user,\n `/api/ai/jobs?orgId=${encodeURIComponent(orgId)}&limit=${LIST_LIMIT}`,\n )\n if (!response.ok) {\n const payload = await response.json().catch(() => null)\n setNotice(String(payload?.error ?? 'The AI jobs could not be loaded — try again.'))\n return\n }\n const payload = (await response.json()) as { jobs: AiJobSummary[] }\n // Every job that arrives already terminal is one the drawer did not\n // watch finish, so its outcome is not this session's to count.\n for (const job of payload.jobs) {\n if (AI_JOB_TERMINAL_STATUSES.includes(job.status)) trackedRef.current.add(job.id)\n // A job the indicator still counts that has settled since leaves it.\n publishAiJob(job)\n }\n setJobs(payload.jobs)\n } catch {\n setNotice('The AI jobs could not be loaded — try again.')\n } finally {\n setLoading(false)\n }\n }, [orgId, user])\n\n useEffect(() => {\n if (expanded) void load()\n }, [expanded, load])\n\n // Reset when the panel's org changes: a list from one workspace must not\n // show under another's key while the new one loads.\n useEffect(() => {\n setJobs([])\n setExpanded(false)\n toggledRef.current = false\n watchingRef.current = null\n }, [orgId])\n\n // Expanded by default while anything is moving or waiting (AGL-3593): a\n // plan waiting to be confirmed behind a collapsed row is a site that never\n // gets built. Otherwise collapsed, which reads nothing until asked.\n const anyInFlight = (inFlight?.length ?? 0) > 0\n useEffect(() => {\n if (anyInFlight && !toggledRef.current) setExpanded(true)\n }, [anyInFlight])\n\n // A request to open AI jobs (AGL-3593): expand, read the list again so a\n // job created a moment ago is in it, and highlight the job named.\n const focusSeq = focus?.seq ?? 0\n const focusJobId = focus?.jobId ?? null\n const expandedRef = useRef(expanded)\n expandedRef.current = expanded\n useEffect(() => {\n if (!focusSeq) return\n toggledRef.current = true\n setHighlight(focusJobId)\n // An open list does not re-run the expand effect's read, so it reads here.\n if (expandedRef.current) void load()\n else setExpanded(true)\n // Only a new request runs this; `load` and the job are read as they stand.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [focusSeq])\n\n // Scroll to the highlighted job once it is listed, then let it fade.\n const highlightListed = highlight !== null && jobs.some((job) => job.id === highlight)\n useEffect(() => {\n if (!highlight || !highlightListed) return undefined\n const row = Array.from(\n listRef.current?.querySelectorAll<HTMLElement>('[data-ai-job-id]') ?? [],\n ).find((element) => element.dataset['aiJobId'] === highlight)\n row?.scrollIntoView?.({ block: 'nearest', behavior: 'smooth' })\n const timer = setTimeout(() => setHighlight(null), HIGHLIGHT_MS)\n return () => clearTimeout(timer)\n }, [highlight, highlightListed])\n\n // Watch the most recent job that is still moving. One stream at a time:\n // the route re-reads a document every two seconds per open stream, and a\n // drawer with three running jobs does not need three of them.\n const watched = jobs.find((job) => !AI_JOB_TERMINAL_STATUSES.includes(job.status))\n const watchedId = watched?.id ?? null\n useEffect(() => {\n if (!expanded || !orgId || !watchedId || watchingRef.current === watchedId) return\n watchingRef.current = watchedId\n const controller = new AbortController()\n const watch = async () => {\n // The server closes a stream at its deadline with `reconnect`; the\n // loop here re-opens it until the job settles or the drawer unmounts.\n let again = true\n while (again && !controller.signal.aborted) {\n again = false\n try {\n const response = await authorizedFetch(\n user,\n `/api/ai/jobs/${encodeURIComponent(watchedId)}/events?orgId=${encodeURIComponent(orgId)}`,\n { signal: controller.signal },\n )\n if (!response.ok || !response.body) return\n await readEventFrames(response.body, (event) => {\n if (event['type'] === 'state') patchJob(event['job'] as AiJobSummary)\n else if (event['type'] === 'reconnect') again = true\n else if (event['type'] === 'gone') {\n setJobs((prior) => prior.filter((job) => job.id !== watchedId))\n }\n })\n } catch {\n // The stream ended without a terminal state — a network blip or\n // the drawer closing. The next expand reloads the list.\n return\n }\n }\n }\n void watch().finally(() => {\n if (watchingRef.current === watchedId) watchingRef.current = null\n })\n return () => {\n controller.abort()\n if (watchingRef.current === watchedId) watchingRef.current = null\n }\n }, [expanded, orgId, watchedId, user, patchJob])\n\n // The same door the dialog that started the job cancels through (AGL-3593).\n const cancel = useCallback(\n async (jobId: string) => {\n if (!orgId) return\n const { job, error } = await cancelAiJobRequest(user, orgId, jobId)\n if (error) {\n setNotice(error)\n return\n }\n if (job) patchJob(job)\n },\n [orgId, user, patchJob],\n )\n\n /** The job whose resume is in flight, so its button cannot send twice. */\n const [resuming, setResuming] = useState<string | null>(null)\n\n // Confirms a plan, or tries again a step whose answer broke a building\n // rule (AGL-2935). The door runs the next step inline and answers with the\n // job, so the row moves on without waiting for the stream.\n const resume = useCallback(\n async (job: AiJobSummary) => {\n if (!orgId) return\n setResuming(job.id)\n setNotice(null)\n // The same door the dialog that started the job confirms through (AGL-3593).\n const { job: next, error } = await resumeAiJobRequest(user, orgId, job)\n if (next) patchJob(next)\n if (error) setNotice(error)\n setResuming(null)\n },\n [orgId, user, patchJob],\n )\n\n if (!visible || !orgId || !entitled) return null\n\n // Counted by state, never as one \"running\" figure (AGL-3593): a plan waiting\n // to be confirmed needs the person, and a stopped job is not moving.\n const chips = aiJobsHeaderChips(aiJobActivityCounts(inFlight ?? jobs))\n\n return (\n <Box sx={{ mb: 2, borderBottom: 1, borderColor: 'divider', pb: 1 }}>\n <Stack direction=\"row\" spacing={1} sx={{ alignItems: 'center' }}>\n <Typography variant=\"subtitle2\" sx={{ flexGrow: 1 }}>\n AI jobs\n {chips.map((chip) => (\n <Chip\n key={chip.state}\n size=\"small\"\n color={STATE_COLOR[chip.state]}\n label={chip.label}\n sx={{ ml: 1 }}\n />\n ))}\n </Typography>\n {/* A question about the page's figures (AGL-2915). */}\n {insight && (\n <Button size=\"small\" onClick={() => setInsightOpen('ask')}>\n Ask about your numbers\n </Button>\n )}\n {/* A page from a brief (AGL-2907), on a site's own routes. */}\n {hostId && (\n <Button size=\"small\" onClick={() => setDescribing(true)}>\n Describe a page\n </Button>\n )}\n <IconButton\n size=\"small\"\n aria-label={expanded ? 'Hide AI jobs' : 'Show AI jobs'}\n aria-expanded={expanded}\n onClick={() => {\n toggledRef.current = true\n setExpanded((prior) => !prior)\n }}\n >\n <MdiIcon\n path={expanded ? mdiChevronUp.path : mdiChevronDown.path}\n sx={{ fontSize: 18 }}\n />\n </IconButton>\n </Stack>\n <Collapse in={expanded} unmountOnExit>\n {notice && (\n <Typography variant=\"caption\" color=\"error\" component=\"div\" sx={{ mt: 0.5 }}>\n {notice}\n </Typography>\n )}\n {loading && !jobs.length && (\n <CircularProgress size={16} sx={{ mt: 1 }} aria-label=\"Loading AI jobs\" />\n )}\n {!loading && !jobs.length && !notice && (\n <Typography variant=\"caption\" color=\"text.secondary\" component=\"div\" sx={{ mt: 0.5 }}>\n No AI jobs yet.\n </Typography>\n )}\n <Stack ref={listRef} spacing={1} sx={{ mt: 1 }} role=\"list\" aria-label=\"AI jobs\">\n {jobs.map((job) => {\n const restartHref = (row: AiJobSummary) =>\n aiJobRestartHref(row, {\n orgSlug,\n hostId,\n pathname: typeof window === 'undefined' ? '' : window.location.pathname,\n })\n const stepsDone = job.steps.filter((step) => step.status === 'done').length\n const current = job.steps.find((step) => step.status === 'running')\n const terminal = AI_JOB_TERMINAL_STATUSES.includes(job.status)\n const phase = aiJobPhase(job)\n const primary = aiJobPrimaryLink(job, orgSlug)\n const highlighted = highlight === job.id\n return (\n <Box\n key={job.id}\n role=\"listitem\"\n data-ai-job-id={job.id}\n aria-current={highlighted ? 'true' : undefined}\n sx={{\n borderRadius: 1,\n bgcolor: highlighted ? 'action.selected' : 'action.hover',\n outline: 2,\n outlineColor: highlighted ? 'primary.main' : 'transparent',\n transition: (theme) =>\n theme.transitions.create(['background-color', 'outline-color'], {\n duration: theme.transitions.duration.standard,\n }),\n px: 1.5,\n py: 1,\n }}\n >\n <Stack direction=\"row\" spacing={1} sx={{ alignItems: 'center' }}>\n <Chip size=\"small\" variant=\"outlined\" label={job.kind} />\n <Chip size=\"small\" color={PHASE_COLOR[phase]} label={AI_JOB_PHASE_LABELS[phase]} />\n <Typography variant=\"caption\" color=\"text.secondary\" sx={{ flexGrow: 1 }}>\n {stepsDone}/{job.steps.length} steps\n {current ? ` — ${current.name}` : ''}\n {/* Net of what a failure on our side gave back (AGL-3594). */}\n {netCredits(job) > 0 ? ` · ${netCredits(job)} credits` : ''}\n </Typography>\n {!terminal && (\n <Button size=\"small\" onClick={() => void cancel(job.id)}>\n Cancel\n </Button>\n )}\n </Stack>\n <Typography variant=\"body2\" sx={{ mt: 0.5, wordBreak: 'break-word' }}>\n {job.brief.length > BRIEF_PREVIEW_CHARS\n ? `${job.brief.slice(0, BRIEF_PREVIEW_CHARS)}…`\n : job.brief}\n </Typography>\n {job.error && (\n <Typography variant=\"caption\" color={job.status === 'failed' ? 'error' : 'warning.main'} component=\"div\">\n {job.error}\n </Typography>\n )}\n {/* What became of its credits, from the job's recorded give-back (AGL-3596). */}\n {aiJobRefundCopy(job) && (\n <Typography variant=\"caption\" color=\"text.secondary\" component=\"div\">\n {aiJobRefundCopy(job)}\n </Typography>\n )}\n {restartHref(job) ? (\n <Button size=\"small\" variant=\"contained\" component={AppLink} href={restartHref(job) as string} sx={{ mt: 0.5 }}>\n {'Try again'}\n </Button>\n ) : null}\n {/* What a finished job built, first (AGL-3593). */}\n {primary ? (\n <Button\n size=\"small\"\n variant=\"contained\"\n component={AppLink}\n href={primary.href}\n sx={{ mt: 0.5 }}\n >\n {primary.label}\n </Button>\n ) : null}\n {job.outputs.map((output, index) => {\n const href = aiJobOutputHref(output, orgSlug)\n const navigation = aiJobNavigationProposal(output)\n return (\n <Box key={`${output.resource}:${output.id}:${index}`} sx={{ mt: 0.5 }}>\n {output.resource === 'insight' ? (\n <Button size=\"small\" onClick={() => setInsightOpen(output.id)}>\n View answer\n </Button>\n ) : href ? (\n <AppLink componentVariant=\"naked\" href={href}>\n Open draft — {output.label}\n </AppLink>\n ) : output.text ? (\n <Typography\n variant=\"body2\"\n component=\"pre\"\n sx={{ whiteSpace: 'pre-wrap', fontFamily: 'inherit', m: 0 }}\n >\n {output.text}\n </Typography>\n ) : (\n <Typography variant=\"caption\" color=\"text.secondary\">\n {output.label}\n </Typography>\n )}\n {output.load ? (\n <Typography variant=\"caption\" color=\"text.secondary\" component=\"div\">\n About {formatBytes(output.load.totalBytes)} on a first visit\n </Typography>\n ) : null}\n {output.note ? (\n <Typography variant=\"caption\" color=\"text.secondary\" component=\"div\">\n {output.note}\n </Typography>\n ) : null}\n {navigation ? (\n <Typography variant=\"caption\" color=\"text.secondary\" component=\"div\">\n Add “{navigation}” to your navigation once the page is live.\n </Typography>\n ) : null}\n </Box>\n )\n })}\n <AiJobPlan\n job={job}\n onResume={(target) => void resume(target)}\n busy={resuming === job.id}\n staff={isStaff}\n user={user}\n />\n </Box>\n )\n })}\n </Stack>\n </Collapse>\n {/*\n The brief dialog (AGL-2907). It starts a job and closes; the list\n below it is the only place the job is watched, so an open list reads\n the new job back as soon as the dialog hands it over.\n */}\n {insightOpen !== null && (\n <AiInsightDialog\n open\n onClose={() => {\n setInsightOpen(null)\n if (expanded) void load()\n }}\n orgId={orgId}\n orgSlug={orgSlug}\n hostId={insight?.host ? (hostId ?? null) : null}\n host={insight?.host ?? null}\n surface={insight?.surface ?? 'analytics'}\n user={user}\n uid={(user as { uid?: string } | null | undefined)?.uid ?? null}\n jobId={insightOpen === 'ask' ? null : insightOpen}\n />\n )}\n {hostId && (\n <AiPageBriefDialog\n open={describing}\n onClose={() => {\n setDescribing(false)\n if (expanded) void load()\n }}\n orgId={orgId}\n hostId={hostId}\n user={user}\n orgSlug={orgSlug}\n isStaff={isStaff}\n />\n )}\n </Box>\n )\n}\n\nexport default AssistJobsDrawer\n"],"names":["checkEntitlement","trackEvent","formatBytes","AI_JOB_TERMINAL_STATUSES","mdiChevronDown","mdiChevronUp","AppLink","MdiIcon","authorizedFetch","Box","Button","Chip","CircularProgress","Collapse","IconButton","Stack","Typography","useCallback","useEffect","useRef","useState","AI_JOB_PHASE_LABELS","aiJobActivityCounts","aiJobPhase","aiJobsHeaderChips","cancelAiJobRequest","resumeAiJobRequest","publishAiJob","AiPageBriefDialog","AiInsightDialog","AiJobPlan","aiJobOutputHref","aiJobPrimaryLink","aiSiteBuildHref","aiJobRefundCopy","readEventFrames","LIST_LIMIT","BRIEF_PREVIEW_CHARS","PHASE_COLOR","queued","planning","building","attention","done","failed","canceled","STATE_COLOR","running","HIGHLIGHT_MS","aiJobRestartHref","job","input","kind","status","siteInputs","hostId","subdomain","exec","pathname","href","orgSlug","id","netCredits","Math","max","creditsSpent","refundedCredits","aiJobNavigationProposal","output","resource","navigation","proposal","label","trim","AssistJobsDrawer","orgId","org","orgReady","user","visible","isStaff","insight","inFlight","focus","entitled","expanded","setExpanded","toggledRef","highlight","setHighlight","listRef","jobs","setJobs","loading","setLoading","notice","setNotice","describing","setDescribing","insightOpen","setInsightOpen","trackedRef","Set","watchingRef","patchJob","next","prior","index","findIndex","slice","copy","includes","current","has","add","credits","load","response","encodeURIComponent","ok","payload","json","catch","String","error","anyInFlight","length","focusSeq","seq","focusJobId","jobId","expandedRef","highlightListed","some","row","undefined","Array","from","querySelectorAll","find","element","dataset","scrollIntoView","block","behavior","timer","setTimeout","clearTimeout","watched","watchedId","controller","AbortController","watch","again","signal","aborted","body","event","filter","finally","abort","cancel","resuming","setResuming","resume","chips","sx","mb","borderBottom","borderColor","pb","direction","spacing","alignItems","variant","flexGrow","map","chip","size","color","state","ml","onClick","aria-label","aria-expanded","path","fontSize","in","unmountOnExit","component","mt","ref","role","restartHref","window","location","stepsDone","steps","step","terminal","phase","primary","highlighted","data-ai-job-id","aria-current","borderRadius","bgcolor","outline","outlineColor","transition","theme","transitions","create","duration","standard","px","py","name","wordBreak","brief","outputs","componentVariant","text","whiteSpace","fontFamily","m","totalBytes","note","onResume","target","busy","staff","open","onClose","host","surface","uid"],"mappings":"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"}