@aglyn/plugins-ai 1.0.0-beta.260 → 1.0.0-beta.262

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 (81) hide show
  1. package/package.json +17 -17
  2. package/src/lib/components/ai-brief-dialog.component.d.ts +21 -58
  3. package/src/lib/components/ai-brief-dialog.component.js +8 -132
  4. package/src/lib/components/ai-brief-dialog.component.js.map +1 -1
  5. package/src/lib/components/ai-job-follow.component.js +2 -35
  6. package/src/lib/components/ai-job-follow.component.js.map +1 -1
  7. package/src/lib/components/ai-job-plan.component.d.ts +2 -8
  8. package/src/lib/components/ai-job-plan.component.js +13 -74
  9. package/src/lib/components/ai-job-plan.component.js.map +1 -1
  10. package/src/lib/components/ai-site-start-card.component.js +43 -34
  11. package/src/lib/components/ai-site-start-card.component.js.map +1 -1
  12. package/src/lib/components/ai-template-collection-field.component.d.ts +2 -12
  13. package/src/lib/components/ai-template-collection-field.component.js +13 -10
  14. package/src/lib/components/ai-template-collection-field.component.js.map +1 -1
  15. package/src/lib/components/ai-upsell-dialog.component.d.ts +3 -25
  16. package/src/lib/components/ai-upsell-dialog.component.js +9 -66
  17. package/src/lib/components/ai-upsell-dialog.component.js.map +1 -1
  18. package/src/lib/components/use-ai-job-run.d.ts +3 -8
  19. package/src/lib/components/use-ai-job-run.js +4 -15
  20. package/src/lib/components/use-ai-job-run.js.map +1 -1
  21. package/src/lib/insights/ai-figure-readers.js +15 -5
  22. package/src/lib/insights/ai-figure-readers.js.map +1 -1
  23. package/src/lib/insights/ai-figure-summaries.d.ts +27 -0
  24. package/src/lib/insights/ai-figure-summaries.js +79 -0
  25. package/src/lib/insights/ai-figure-summaries.js.map +1 -0
  26. package/src/lib/insights/ai-insight-readers.d.ts +2 -1
  27. package/src/lib/insights/ai-insight-readers.js +11 -26
  28. package/src/lib/insights/ai-insight-readers.js.map +1 -1
  29. package/src/lib/jobs/ai-job-admission.d.ts +6 -0
  30. package/src/lib/jobs/ai-job-admission.js.map +1 -1
  31. package/src/lib/jobs/ai-job-site-step.js +10 -6
  32. package/src/lib/jobs/ai-job-site-step.js.map +1 -1
  33. package/src/lib/jobs/ai-layout-stock-photos.d.ts +43 -11
  34. package/src/lib/jobs/ai-layout-stock-photos.js +329 -32
  35. package/src/lib/jobs/ai-layout-stock-photos.js.map +1 -1
  36. package/src/lib/jobs/ai-stock-photo-picker.js +13 -7
  37. package/src/lib/jobs/ai-stock-photo-picker.js.map +1 -1
  38. package/src/lib/jobs/fixtures/ai-stock-photo-agl3856-recordings.d.ts +35 -0
  39. package/src/lib/jobs/fixtures/ai-stock-photo-agl3856-recordings.js +404 -0
  40. package/src/lib/jobs/fixtures/ai-stock-photo-agl3856-recordings.js.map +1 -0
  41. package/src/lib/layout-language/ai-layout-motion.d.ts +9 -3
  42. package/src/lib/layout-language/ai-layout-motion.js +9 -3
  43. package/src/lib/layout-language/ai-layout-motion.js.map +1 -1
  44. package/src/lib/layout-language/ai-layout-pictures.d.ts +10 -1
  45. package/src/lib/layout-language/ai-layout-pictures.js +12 -6
  46. package/src/lib/layout-language/ai-layout-pictures.js.map +1 -1
  47. package/src/lib/model/ai-brief-copy.d.ts +85 -0
  48. package/src/lib/model/ai-brief-copy.js +152 -0
  49. package/src/lib/model/ai-brief-copy.js.map +1 -0
  50. package/src/lib/model/ai-create-view.d.ts +200 -0
  51. package/src/lib/model/ai-create-view.js +263 -0
  52. package/src/lib/model/ai-create-view.js.map +1 -0
  53. package/src/lib/model/ai-insight.d.ts +1 -1
  54. package/src/lib/model/ai-insight.js +4 -39
  55. package/src/lib/model/ai-insight.js.map +1 -1
  56. package/src/lib/model/ai-job-activity.d.ts +24 -0
  57. package/src/lib/model/ai-job-activity.js +52 -1
  58. package/src/lib/model/ai-job-activity.js.map +1 -1
  59. package/src/lib/model/ai-job-plan-lines.d.ts +46 -0
  60. package/src/lib/model/ai-job-plan-lines.js +70 -0
  61. package/src/lib/model/ai-job-plan-lines.js.map +1 -0
  62. package/src/lib/model/ai-template-collections.d.ts +28 -0
  63. package/src/lib/model/ai-template-collections.js +28 -0
  64. package/src/lib/model/ai-template-collections.js.map +1 -0
  65. package/src/lib/model/ai-upsell-copy.d.ts +41 -0
  66. package/src/lib/model/ai-upsell-copy.js +85 -0
  67. package/src/lib/model/ai-upsell-copy.js.map +1 -0
  68. package/src/lib/runtime/ai-doctrine-validators.d.ts +40 -0
  69. package/src/lib/runtime/ai-doctrine-validators.js +148 -3
  70. package/src/lib/runtime/ai-doctrine-validators.js.map +1 -1
  71. package/src/lib/runtime/ai-doctrine.js +6 -2
  72. package/src/lib/runtime/ai-doctrine.js.map +1 -1
  73. package/src/lib/runtime/ai-eval-memory-firestore.js +2 -0
  74. package/src/lib/runtime/ai-eval-memory-firestore.js.map +1 -1
  75. package/src/lib/server/ai-create-route.d.ts +32 -0
  76. package/src/lib/server/ai-create-route.js +295 -0
  77. package/src/lib/server/ai-create-route.js.map +1 -0
  78. package/src/lib/server/ai-jobs-route.js +19 -0
  79. package/src/lib/server/ai-jobs-route.js.map +1 -1
  80. package/src/lib/server.js +14 -0
  81. package/src/lib/server.js.map +1 -1
@@ -15,13 +15,11 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
15
15
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
16
  * See the License for the specific language governing permissions and
17
17
  * limitations under the License.
18
- */ import { AI_BUILD_PLAN_CREATION_NOUNS, AI_BUILD_PLAN_EMBED_HOST_NAMES, isAiPlanNewRef } from "../model/ai-build-plan.js";
18
+ */ import { aiJobPlanHeading, aiJobPlanLines, aiPlanEmbedLine } from "../model/ai-job-plan-lines.js";
19
19
  import { aiBuildFreePageCapNote, aiBuildSmaller, aiJobCreditRange } from "../model/ai-build-job.js";
20
20
  import { aiCreditRangeText, aiCreditsPromptFor } from "../model/ai-credit-estimate.js";
21
21
  import { aiFreeCreditsResetLabel } from "../model/ai-site-job.js";
22
22
  import { AiCreditsPromptNotice } from "./ai-credits-prompt.component.js";
23
- import { aiBuildOpNoun } from "../model/ai-build-progress.js";
24
- import { aiBuildStorePagesAdded } from "../model/ai-build-store-pages.js";
25
23
  import { AI_PAGE_BUILDING_JOB_KINDS, AI_SITE_BUILD_IN_FLIGHT_COPY, aiJobConfirmingOwnPlan, aiSiteBuildInFlight } from "../model/ai-job-activity.js";
26
24
  import { aiSiteStarterFallbackOffered } from "../model/ai-job-failure-copy.js";
27
25
  import { useAiJobsInFlightKnown } from "./ai-jobs-store.js";
@@ -62,19 +60,11 @@ import { useState } from "react";
62
60
  }
63
61
  return lines;
64
62
  }
65
- /**
66
- * A third-party player the plan lists, with what it costs the page, read
67
- * before the member confirms it (rule 16, AGL-3433). The cost is the
68
- * platform's sentence, never the model's: the player is framed lazily, so its
69
- * host's code loads when a visitor reaches it, whether or not they press play.
70
- */ export function aiPlanEmbedLine(embed, named) {
71
- const host = AI_BUILD_PLAN_EMBED_HOST_NAMES[embed.host];
72
- const where = isAiPlanNewRef(embed.where) ? `the component ${named(embed.where)}` : embed.where;
73
- const link = embed.url ? ` playing ${embed.url}` : ', its link left for you to paste';
74
- return `Embeds a ${host} player on ${where}${link}, as you asked (“${embed.asked}”). It loads ${host}’s own code when a visitor reaches it, whether or not they press play.`;
75
- }
63
+ // A plan's lines are the model's, which the native apps' follow view sends
64
+ // too (AGL-3854); re-exported for this card's existing readers.
65
+ export { aiPlanEmbedLine };
76
66
  export function AiJobPlan({ job, onResume, busy = false, staff = false, user, orgSlug }) {
77
- var _ref, _plan_items, _plan_embeds;
67
+ var _ref;
78
68
  var _job_review;
79
69
  const [detailsOpen, setDetailsOpen] = useState(false);
80
70
  // Unticked until the person ticks it: a build publishes only when its
@@ -92,10 +82,6 @@ export function AiJobPlan({ job, onResume, busy = false, staff = false, user, or
92
82
  const { plan, review } = job;
93
83
  if (!plan && !review) return null;
94
84
  const details = staff ? aiJobReviewDetails(review) : [];
95
- /** A reference as a person reads it: the record's name, or what the plan creates. */ const named = (ref)=>{
96
- var _ref;
97
- return !ref ? '' : isAiPlanNewRef(ref) ? ref.slice('new:'.length) : (_ref = plan == null ? void 0 : plan.labels[ref]) != null ? _ref : ref;
98
- };
99
85
  // A plan the machine is confirming itself is not one to confirm (AGL-3596).
100
86
  const waiting = job.status === 'needs_review' && review !== null && !aiJobConfirmingOwnPlan(job);
101
87
  // The guard rail (AGL-2911): what the plan is estimated to cost is read
@@ -127,63 +113,16 @@ export function AiJobPlan({ job, onResume, busy = false, staff = false, user, or
127
113
  /*#__PURE__*/ _jsx(Typography, {
128
114
  variant: "caption",
129
115
  color: "text.secondary",
130
- children: plan.status === 'confirmed' ? 'Confirmed plan' : 'Proposed plan'
116
+ children: aiJobPlanHeading(plan)
131
117
  }),
132
- plan.reuse.map((entry, index)=>/*#__PURE__*/ _jsxs(Typography, {
133
- variant: "body2",
134
- role: "listitem",
135
- children: [
136
- "Reuses the ",
137
- entry.kind === 'screen' ? 'page' : entry.kind,
138
- " ",
139
- named(entry.id),
140
- " — ",
141
- entry.purpose
142
- ]
143
- }, `reuse-${index}`)),
144
- plan.create.map((entry, index)=>/*#__PURE__*/ _jsxs(Typography, {
145
- variant: "body2",
146
- role: "listitem",
147
- children: [
148
- "Creates the ",
149
- AI_BUILD_PLAN_CREATION_NOUNS[entry.kind].noun,
150
- " ",
151
- entry.name,
152
- entry.duplicateOf ? `, from a copy of ${named(entry.duplicateOf)}` : '',
153
- ' ',
154
- "— ",
155
- entry.why
156
- ]
157
- }, `create-${index}`)),
158
- plan.screens.map((screen, index)=>/*#__PURE__*/ _jsxs(Typography, {
159
- variant: "body2",
160
- role: "listitem",
161
- children: [
162
- screen.record ? `Builds the record template ${screen.title}, a page per record of ${named(screen.record.dataset)} at /${screen.record.base}/…` : `Builds the page ${screen.title} at ${screen.slug}`,
163
- screen.duplicateOf ? `, from a copy of ${named(screen.duplicateOf)}` : '',
164
- screen.layout ? ` in ${named(screen.layout)}` : '',
165
- screen.sections.length ? `: ${screen.sections.map((section)=>section.name).join(', ')}` : ''
166
- ]
167
- }, `screen-${index}`)),
168
- ((_plan_items = plan.items) != null ? _plan_items : []).map((item)=>/*#__PURE__*/ _jsxs(Typography, {
169
- variant: "body2",
170
- role: "listitem",
171
- children: [
172
- `Makes the ${aiBuildOpNoun(item.op).toLowerCase()} ${item.name}`,
173
- item.why ? ` — ${item.why}` : ''
174
- ]
175
- }, `item-${item.slot}`)),
176
- ((_plan_embeds = plan.embeds) != null ? _plan_embeds : []).map((embed, index)=>/*#__PURE__*/ _jsx(Typography, {
177
- variant: "body2",
178
- role: "listitem",
179
- children: aiPlanEmbedLine(embed, named)
180
- }, `embed-${index}`)),
181
- aiBuildStorePagesAdded(plan).map((page)=>/*#__PURE__*/ _jsx(Typography, {
118
+ aiJobPlanLines(plan).map((line)=>/*#__PURE__*/ _jsx(Typography, _extends({
182
119
  variant: "body2",
183
- role: "listitem",
184
- "data-platform-added": "true",
185
- children: `Adds the page ${page.title} at ${page.href} — added for your store automatically, uses no AI credits`
186
- }, `store-${page.key}`))
120
+ role: "listitem"
121
+ }, line.platformAdded ? {
122
+ 'data-platform-added': 'true'
123
+ } : {}, {
124
+ children: line.text
125
+ }), line.key))
187
126
  ]
188
127
  }),
189
128
  staff && (review == null ? void 0 : review.detail) && /*#__PURE__*/ _jsx(Typography, {
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../../../libs/plugins/ai/src/lib/components/ai-job-plan.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 {\n AI_BUILD_PLAN_CREATION_NOUNS,\n AI_BUILD_PLAN_EMBED_HOST_NAMES,\n isAiPlanNewRef,\n type AiBuildPlanEmbed,\n} from '../model/ai-build-plan'\nimport type { AiJobReview, AiJobSummary } from '../model/ai-jobs.types'\nimport { aiBuildFreePageCapNote, aiBuildSmaller, aiJobCreditRange } from '../model/ai-build-job'\nimport { aiCreditRangeText, aiCreditsPromptFor } from '../model/ai-credit-estimate'\nimport { aiFreeCreditsResetLabel } from '../model/ai-site-job'\nimport { AiCreditsPromptNotice } from './ai-credits-prompt.component'\nimport type { AiJobResumeOptions } from './ai-job-requests'\nimport { aiBuildOpNoun } from '../model/ai-build-progress'\nimport { aiBuildStorePagesAdded } from '../model/ai-build-store-pages'\nimport {\n AI_PAGE_BUILDING_JOB_KINDS,\n AI_SITE_BUILD_IN_FLIGHT_COPY,\n aiJobConfirmingOwnPlan,\n aiSiteBuildInFlight,\n} from '../model/ai-job-activity'\nimport { aiSiteStarterFallbackOffered } from '../model/ai-job-failure-copy'\nimport { useAiJobsInFlightKnown } from './ai-jobs-store'\nimport { AiSiteStarterFallback } from './ai-site-starter-fallback.component'\nimport { Alert, Box, Button, Checkbox, Collapse, FormControlLabel, Stack, Typography } from '@mui/material'\nimport { useState } from 'react'\n\n/**\n * A job's plan and what it waits for (AGL-2935), inside the AI jobs drawer\n * and the dialog that started the job (AGL-3593): what the job reuses from\n * the site, what it creates and why, the screens it builds — and, while the\n * job waits for a person, the one button that confirms the plan or tries a\n * refused step again. Both send the same request (`resumeAiJobRequest`);\n * this renders.\n */\nexport interface AiJobPlanProps {\n job: AiJobSummary\n /**\n * Confirms the plan, or tries the refused step again. A build whose request\n * asked to publish confirms with `publish` when its box is ticked (AGL-3616).\n */\n onResume: (job: AiJobSummary, options?: AiJobResumeOptions) => void\n /** A resume for this job is in flight. */\n busy?: boolean\n /**\n * The viewer is staff (AGL-3078), who can open where a refused answer broke\n * its rules and the outline of those parts, to tell a shape the rules should\n * allow from an answer that ignored its re-ask. A member reads the findings.\n */\n staff?: boolean\n /**\n * The signed-in user, for \"Use the starter site instead\" on a guided start\n * that did not work out (AGL-3594); the action is drawn only when given.\n */\n user?: Parameters<typeof AiSiteStarterFallback>[0]['user']\n /** The workspace's path slug, for the Upgrade a Free build past what is left offers (AGL-3722). */\n orgSlug?: string | null\n}\n\n/**\n * Where a refused answer broke its rules, and the outline of those parts, as\n * lines staff read (AGL-3078): each finding with the nodes or plan entries it\n * names, then each outlined node indented by its depth, with its element, a\n * Grid's layout as written, and the names of what it sets and holds.\n */\nexport function aiJobReviewDetails(review: AiJobReview | null): string[] {\n if (review?.reason !== 'doctrine') return []\n const lines = review.findings.flatMap((finding) => {\n const where = finding.nodeIds?.length\n ? `nodes ${finding.nodeIds.join(', ')}`\n : finding.paths?.length\n ? `at ${finding.paths.join(', ')}`\n : null\n return where ? [`${finding.rule === null ? '' : `Rule ${finding.rule} `}${finding.code}: ${where}`] : []\n })\n for (const node of review.outline ?? []) {\n lines.push(\n [\n `${' '.repeat(node.depth)}${node.id} ${node.componentId}`,\n ...Object.entries(node.grid ?? {}).map(([name, value]) => `${name}=${JSON.stringify(value)}`),\n ...(node.props.length ? [`props ${node.props.join(', ')}`] : []),\n ...(node.sx?.length ? [`sx ${node.sx.join(', ')}`] : []),\n ...(node.children.length ? [`holds ${node.children.join(', ')}`] : []),\n ].join(' · '),\n )\n }\n return lines\n}\n\n/**\n * A third-party player the plan lists, with what it costs the page, read\n * before the member confirms it (rule 16, AGL-3433). The cost is the\n * platform's sentence, never the model's: the player is framed lazily, so its\n * host's code loads when a visitor reaches it, whether or not they press play.\n */\nexport function aiPlanEmbedLine(\n embed: AiBuildPlanEmbed,\n named: (ref: string) => string,\n): string {\n const host = AI_BUILD_PLAN_EMBED_HOST_NAMES[embed.host]\n const where = isAiPlanNewRef(embed.where) ? `the component ${named(embed.where)}` : embed.where\n const link = embed.url ? ` playing ${embed.url}` : ', its link left for you to paste'\n return `Embeds a ${host} player on ${where}${link}, as you asked (“${embed.asked}”). It loads ${host}’s own code when a visitor reaches it, whether or not they press play.`\n}\n\nexport function AiJobPlan({\n job,\n onResume,\n busy = false,\n staff = false,\n user,\n orgSlug,\n}: AiJobPlanProps): JSX.Element | null {\n const [detailsOpen, setDetailsOpen] = useState(false)\n // Unticked until the person ticks it: a build publishes only when its\n // request asked AND they confirm it here (AGL-3616).\n const [publish, setPublish] = useState(false)\n // Confirming builds pages while another job is building on this site\n // (AGL-3765), from the list the indicator and the panel already hold: said\n // beside Confirm, which still confirms.\n const confirmsPages =\n job.status === 'needs_review' &&\n job.review?.reason === 'plan' &&\n !aiJobConfirmingOwnPlan(job) &&\n AI_PAGE_BUILDING_JOB_KINDS.includes(job.kind)\n const inFlight = useAiJobsInFlightKnown(user, job.orgId, confirmsPages)\n const building = confirmsPages ? aiSiteBuildInFlight(inFlight, { hostId: job.hostId, exceptJobId: job.id }) : null\n const { plan, review } = job\n if (!plan && !review) return null\n const details = staff ? aiJobReviewDetails(review) : []\n /** A reference as a person reads it: the record's name, or what the plan creates. */\n const named = (ref: string | null): string =>\n !ref\n ? ''\n : isAiPlanNewRef(ref)\n ? ref.slice('new:'.length)\n : (plan?.labels[ref] ?? ref)\n // A plan the machine is confirming itself is not one to confirm (AGL-3596).\n const waiting = job.status === 'needs_review' && review !== null && !aiJobConfirmingOwnPlan(job)\n // The guard rail (AGL-2911): what the plan is estimated to cost is read\n // before it is confirmed, not after it has been spent. An estimate, and\n // said to be one: what it is likely to cost — what builds like it measured\n // — and its ceiling, every pass at its reserve (AGL-3722). A page job\n // counts the creations it builds before its page (AGL-3031).\n const range = plan && waiting && review.reason === 'plan' ? aiJobCreditRange(job.kind, plan) : null\n // A Free build past what is left asks first (AGL-3722): build what fits,\n // the home page first, or upgrade — never a refusal with no way on.\n const freeCredits = review?.freeCredits ?? null\n const prompt =\n plan && range && job.kind === 'build' ? aiCreditsPromptFor(range, freeCredits, aiBuildSmaller(plan)) : null\n // A Free build at its page cap says so (AGL-3722): pages past it were left for a later request.\n const pageCapNote =\n plan && waiting && review.reason === 'plan' && job.kind === 'build'\n ? aiBuildFreePageCapNote(plan, Boolean(freeCredits))\n : null\n const offersPublish = job.kind === 'build' && job.publishAsked === true && waiting && review.reason === 'plan'\n const publishing = offersPublish && publish ? { publish: true } : {}\n return (\n <Box sx={{ mt: 1 }}>\n {plan && (\n <Stack spacing={0.5} role=\"list\" aria-label=\"Plan\">\n <Typography variant=\"caption\" color=\"text.secondary\">\n {plan.status === 'confirmed' ? 'Confirmed plan' : 'Proposed plan'}\n </Typography>\n {plan.reuse.map((entry, index) => (\n <Typography key={`reuse-${index}`} variant=\"body2\" role=\"listitem\">\n Reuses the {entry.kind === 'screen' ? 'page' : entry.kind} {named(entry.id)} — {entry.purpose}\n </Typography>\n ))}\n {plan.create.map((entry, index) => (\n <Typography key={`create-${index}`} variant=\"body2\" role=\"listitem\">\n Creates the {AI_BUILD_PLAN_CREATION_NOUNS[entry.kind].noun} {entry.name}\n {entry.duplicateOf\n ? `, from a copy of ${named(entry.duplicateOf)}`\n : ''}{' '}\n — {entry.why}\n </Typography>\n ))}\n {plan.screens.map((screen, index) => (\n <Typography key={`screen-${index}`} variant=\"body2\" role=\"listitem\">\n {screen.record\n ? `Builds the record template ${screen.title}, a page per record of ${named(screen.record.dataset)} at /${screen.record.base}/…`\n : `Builds the page ${screen.title} at ${screen.slug}`}\n {screen.duplicateOf\n ? `, from a copy of ${named(screen.duplicateOf)}`\n : ''}\n {screen.layout ? ` in ${named(screen.layout)}` : ''}\n {screen.sections.length\n ? `: ${screen.sections.map((section) => section.name).join(', ')}`\n : ''}\n </Typography>\n ))}\n {(plan.items ?? []).map((item) => (\n <Typography key={`item-${item.slot}`} variant=\"body2\" role=\"listitem\">\n {`Makes the ${aiBuildOpNoun(item.op).toLowerCase()} ${item.name}`}\n {item.why ? ` — ${item.why}` : ''}\n </Typography>\n ))}\n {(plan.embeds ?? []).map((embed, index) => (\n <Typography key={`embed-${index}`} variant=\"body2\" role=\"listitem\">\n {aiPlanEmbedLine(embed, named)}\n </Typography>\n ))}\n {/* A store's own pages (AGL-3676): added by the platform, written by code, no credits. */}\n {aiBuildStorePagesAdded(plan).map((page) => (\n <Typography key={`store-${page.key}`} variant=\"body2\" role=\"listitem\" data-platform-added=\"true\">\n {`Adds the page ${page.title} at ${page.href} — added for your store automatically, uses no AI credits`}\n </Typography>\n ))}\n </Stack>\n )}\n {/*\n A review written for the member (AGL-3594) carries the checks' own\n sentence as `detail`: its findings are then staff reading too, and the\n member reads the job's one sentence alone.\n */}\n {staff && review?.detail && (\n <Typography variant=\"caption\" color=\"text.secondary\" component=\"div\" sx={{ mt: 0.5 }}>\n {review.detail}\n </Typography>\n )}\n {review?.reason === 'doctrine' && review.findings.length > 0 && (staff || !review.detail) && (\n <Box\n component=\"ul\"\n sx={{ my: 0.5, pl: 2.5 }}\n aria-label=\"Building rules broken\"\n >\n {review.findings.map((finding, index) => (\n <Typography\n key={`finding-${index}`}\n component=\"li\"\n variant=\"caption\"\n >\n {finding.message}\n </Typography>\n ))}\n </Box>\n )}\n {details.length > 0 && (\n <Box sx={{ mt: 0.5 }}>\n <Button\n size=\"small\"\n aria-expanded={detailsOpen}\n onClick={() => setDetailsOpen((prior) => !prior)}\n >\n {detailsOpen ? 'Hide what was refused' : 'Show what was refused'}\n </Button>\n <Collapse in={detailsOpen} unmountOnExit>\n <Typography\n variant=\"caption\"\n component=\"pre\"\n aria-label=\"What was refused\"\n sx={{ m: 0, fontFamily: 'monospace', whiteSpace: 'pre', overflowX: 'auto' }}\n >\n {details.join('\\n')}\n </Typography>\n </Collapse>\n </Box>\n )}\n {range && range.ceiling > 0 && (\n <Typography\n variant=\"caption\"\n color=\"text.secondary\"\n sx={{ display: 'block', mt: 1 }}\n >\n {`Estimated cost: ${aiCreditRangeText(range)}. What it costs is what its steps spend.`}\n {freeCredits && !prompt\n ? ` You have ${freeCredits.left.toLocaleString('en-US')} of your free AI credits left this month, until ${aiFreeCreditsResetLabel(freeCredits.resetsOn)}.`\n : ''}\n </Typography>\n )}\n {pageCapNote && (\n <Typography variant=\"caption\" color=\"text.secondary\" sx={{ display: 'block', mt: 0.5 }}>\n {pageCapNote}\n </Typography>\n )}\n {waiting && review.retryRefusal && review.reason !== 'plan' && (\n <Typography variant=\"caption\" color=\"text.secondary\" component=\"div\" sx={{ mt: 1 }}>\n {review.retryRefusal}\n </Typography>\n )}\n {offersPublish && (\n <FormControlLabel\n sx={{ display: 'flex', mt: 1 }}\n control={<Checkbox size=\"small\" checked={publish} onChange={(event) => setPublish(event.target.checked)} />}\n label={<Typography variant=\"body2\">{'Publish the new pages when they are built'}</Typography>}\n />\n )}\n {waiting && prompt && (\n <AiCreditsPromptNotice\n prompt={prompt}\n noun=\"build\"\n orgSlug={orgSlug}\n busy={busy}\n onBuildWhatFits={() => onResume(job, { ...publishing, creditsConfirmed: true })}\n onSmaller={() => onResume(job, { ...publishing, creditsConfirmed: true, reduce: 'first-page' })}\n />\n )}\n {building && (\n <Alert severity=\"info\" sx={{ mt: 1 }}>\n {AI_SITE_BUILD_IN_FLIGHT_COPY}\n </Alert>\n )}\n {waiting && !prompt && (\n <Button\n size=\"small\"\n variant=\"contained\"\n // Disabled with its reason above when the Free allowance left\n // cannot pay for another try (AGL-3594).\n disabled={busy || (review.reason !== 'plan' && Boolean(review.retryRefusal))}\n onClick={() => onResume(job, offersPublish && publish ? publishing : undefined)}\n sx={{ mt: 1 }}\n >\n {review.reason === 'plan' ? 'Confirm plan' : 'Try again'}\n </Button>\n )}\n {/* A guided start that did not work out can take the starter instead (AGL-3594). */}\n {waiting && user && aiSiteStarterFallbackOffered(job) && <AiSiteStarterFallback job={job} user={user} />}\n </Box>\n )\n}\n\nexport default AiJobPlan\n"],"names":["AI_BUILD_PLAN_CREATION_NOUNS","AI_BUILD_PLAN_EMBED_HOST_NAMES","isAiPlanNewRef","aiBuildFreePageCapNote","aiBuildSmaller","aiJobCreditRange","aiCreditRangeText","aiCreditsPromptFor","aiFreeCreditsResetLabel","AiCreditsPromptNotice","aiBuildOpNoun","aiBuildStorePagesAdded","AI_PAGE_BUILDING_JOB_KINDS","AI_SITE_BUILD_IN_FLIGHT_COPY","aiJobConfirmingOwnPlan","aiSiteBuildInFlight","aiSiteStarterFallbackOffered","useAiJobsInFlightKnown","AiSiteStarterFallback","Alert","Box","Button","Checkbox","Collapse","FormControlLabel","Stack","Typography","useState","aiJobReviewDetails","review","reason","lines","findings","flatMap","finding","where","nodeIds","length","join","paths","rule","code","node","outline","push","repeat","depth","id","componentId","Object","entries","grid","map","name","value","JSON","stringify","props","sx","children","aiPlanEmbedLine","embed","named","host","link","url","asked","AiJobPlan","job","onResume","busy","staff","user","orgSlug","plan","detailsOpen","setDetailsOpen","publish","setPublish","confirmsPages","status","includes","kind","inFlight","orgId","building","hostId","exceptJobId","details","ref","slice","labels","waiting","range","freeCredits","prompt","pageCapNote","Boolean","offersPublish","publishAsked","publishing","mt","spacing","role","aria-label","variant","color","reuse","entry","index","purpose","create","noun","duplicateOf","why","screens","screen","record","title","dataset","base","slug","layout","sections","section","items","item","op","toLowerCase","slot","embeds","page","data-platform-added","href","key","detail","component","my","pl","message","size","aria-expanded","onClick","prior","in","unmountOnExit","m","fontFamily","whiteSpace","overflowX","ceiling","display","left","toLocaleString","resetsOn","retryRefusal","control","checked","onChange","event","target","label","onBuildWhatFits","creditsConfirmed","onSmaller","reduce","severity","disabled","undefined"],"mappings":"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"}
1
+ {"version":3,"sources":["../../../../../../../libs/plugins/ai/src/lib/components/ai-job-plan.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 { aiJobPlanHeading, aiJobPlanLines, aiPlanEmbedLine } from '../model/ai-job-plan-lines'\nimport type { AiJobReview, AiJobSummary } from '../model/ai-jobs.types'\nimport { aiBuildFreePageCapNote, aiBuildSmaller, aiJobCreditRange } from '../model/ai-build-job'\nimport { aiCreditRangeText, aiCreditsPromptFor } from '../model/ai-credit-estimate'\nimport { aiFreeCreditsResetLabel } from '../model/ai-site-job'\nimport { AiCreditsPromptNotice } from './ai-credits-prompt.component'\nimport type { AiJobResumeOptions } from './ai-job-requests'\nimport {\n AI_PAGE_BUILDING_JOB_KINDS,\n AI_SITE_BUILD_IN_FLIGHT_COPY,\n aiJobConfirmingOwnPlan,\n aiSiteBuildInFlight,\n} from '../model/ai-job-activity'\nimport { aiSiteStarterFallbackOffered } from '../model/ai-job-failure-copy'\nimport { useAiJobsInFlightKnown } from './ai-jobs-store'\nimport { AiSiteStarterFallback } from './ai-site-starter-fallback.component'\nimport { Alert, Box, Button, Checkbox, Collapse, FormControlLabel, Stack, Typography } from '@mui/material'\nimport { useState } from 'react'\n\n/**\n * A job's plan and what it waits for (AGL-2935), inside the AI jobs drawer\n * and the dialog that started the job (AGL-3593): what the job reuses from\n * the site, what it creates and why, the screens it builds — and, while the\n * job waits for a person, the one button that confirms the plan or tries a\n * refused step again. Both send the same request (`resumeAiJobRequest`);\n * this renders.\n */\nexport interface AiJobPlanProps {\n job: AiJobSummary\n /**\n * Confirms the plan, or tries the refused step again. A build whose request\n * asked to publish confirms with `publish` when its box is ticked (AGL-3616).\n */\n onResume: (job: AiJobSummary, options?: AiJobResumeOptions) => void\n /** A resume for this job is in flight. */\n busy?: boolean\n /**\n * The viewer is staff (AGL-3078), who can open where a refused answer broke\n * its rules and the outline of those parts, to tell a shape the rules should\n * allow from an answer that ignored its re-ask. A member reads the findings.\n */\n staff?: boolean\n /**\n * The signed-in user, for \"Use the starter site instead\" on a guided start\n * that did not work out (AGL-3594); the action is drawn only when given.\n */\n user?: Parameters<typeof AiSiteStarterFallback>[0]['user']\n /** The workspace's path slug, for the Upgrade a Free build past what is left offers (AGL-3722). */\n orgSlug?: string | null\n}\n\n/**\n * Where a refused answer broke its rules, and the outline of those parts, as\n * lines staff read (AGL-3078): each finding with the nodes or plan entries it\n * names, then each outlined node indented by its depth, with its element, a\n * Grid's layout as written, and the names of what it sets and holds.\n */\nexport function aiJobReviewDetails(review: AiJobReview | null): string[] {\n if (review?.reason !== 'doctrine') return []\n const lines = review.findings.flatMap((finding) => {\n const where = finding.nodeIds?.length\n ? `nodes ${finding.nodeIds.join(', ')}`\n : finding.paths?.length\n ? `at ${finding.paths.join(', ')}`\n : null\n return where ? [`${finding.rule === null ? '' : `Rule ${finding.rule} `}${finding.code}: ${where}`] : []\n })\n for (const node of review.outline ?? []) {\n lines.push(\n [\n `${' '.repeat(node.depth)}${node.id} ${node.componentId}`,\n ...Object.entries(node.grid ?? {}).map(([name, value]) => `${name}=${JSON.stringify(value)}`),\n ...(node.props.length ? [`props ${node.props.join(', ')}`] : []),\n ...(node.sx?.length ? [`sx ${node.sx.join(', ')}`] : []),\n ...(node.children.length ? [`holds ${node.children.join(', ')}`] : []),\n ].join(' · '),\n )\n }\n return lines\n}\n\n// A plan's lines are the model's, which the native apps' follow view sends\n// too (AGL-3854); re-exported for this card's existing readers.\nexport { aiPlanEmbedLine }\n\nexport function AiJobPlan({\n job,\n onResume,\n busy = false,\n staff = false,\n user,\n orgSlug,\n}: AiJobPlanProps): JSX.Element | null {\n const [detailsOpen, setDetailsOpen] = useState(false)\n // Unticked until the person ticks it: a build publishes only when its\n // request asked AND they confirm it here (AGL-3616).\n const [publish, setPublish] = useState(false)\n // Confirming builds pages while another job is building on this site\n // (AGL-3765), from the list the indicator and the panel already hold: said\n // beside Confirm, which still confirms.\n const confirmsPages =\n job.status === 'needs_review' &&\n job.review?.reason === 'plan' &&\n !aiJobConfirmingOwnPlan(job) &&\n AI_PAGE_BUILDING_JOB_KINDS.includes(job.kind)\n const inFlight = useAiJobsInFlightKnown(user, job.orgId, confirmsPages)\n const building = confirmsPages ? aiSiteBuildInFlight(inFlight, { hostId: job.hostId, exceptJobId: job.id }) : null\n const { plan, review } = job\n if (!plan && !review) return null\n const details = staff ? aiJobReviewDetails(review) : []\n // A plan the machine is confirming itself is not one to confirm (AGL-3596).\n const waiting = job.status === 'needs_review' && review !== null && !aiJobConfirmingOwnPlan(job)\n // The guard rail (AGL-2911): what the plan is estimated to cost is read\n // before it is confirmed, not after it has been spent. An estimate, and\n // said to be one: what it is likely to cost — what builds like it measured\n // — and its ceiling, every pass at its reserve (AGL-3722). A page job\n // counts the creations it builds before its page (AGL-3031).\n const range = plan && waiting && review.reason === 'plan' ? aiJobCreditRange(job.kind, plan) : null\n // A Free build past what is left asks first (AGL-3722): build what fits,\n // the home page first, or upgrade — never a refusal with no way on.\n const freeCredits = review?.freeCredits ?? null\n const prompt =\n plan && range && job.kind === 'build' ? aiCreditsPromptFor(range, freeCredits, aiBuildSmaller(plan)) : null\n // A Free build at its page cap says so (AGL-3722): pages past it were left for a later request.\n const pageCapNote =\n plan && waiting && review.reason === 'plan' && job.kind === 'build'\n ? aiBuildFreePageCapNote(plan, Boolean(freeCredits))\n : null\n const offersPublish = job.kind === 'build' && job.publishAsked === true && waiting && review.reason === 'plan'\n const publishing = offersPublish && publish ? { publish: true } : {}\n return (\n <Box sx={{ mt: 1 }}>\n {plan && (\n <Stack spacing={0.5} role=\"list\" aria-label=\"Plan\">\n <Typography variant=\"caption\" color=\"text.secondary\">\n {aiJobPlanHeading(plan)}\n </Typography>\n {aiJobPlanLines(plan).map((line) => (\n <Typography\n key={line.key}\n variant=\"body2\"\n role=\"listitem\"\n {...(line.platformAdded ? { 'data-platform-added': 'true' } : {})}\n >\n {line.text}\n </Typography>\n ))}\n </Stack>\n )}\n {/*\n A review written for the member (AGL-3594) carries the checks' own\n sentence as `detail`: its findings are then staff reading too, and the\n member reads the job's one sentence alone.\n */}\n {staff && review?.detail && (\n <Typography variant=\"caption\" color=\"text.secondary\" component=\"div\" sx={{ mt: 0.5 }}>\n {review.detail}\n </Typography>\n )}\n {review?.reason === 'doctrine' && review.findings.length > 0 && (staff || !review.detail) && (\n <Box\n component=\"ul\"\n sx={{ my: 0.5, pl: 2.5 }}\n aria-label=\"Building rules broken\"\n >\n {review.findings.map((finding, index) => (\n <Typography\n key={`finding-${index}`}\n component=\"li\"\n variant=\"caption\"\n >\n {finding.message}\n </Typography>\n ))}\n </Box>\n )}\n {details.length > 0 && (\n <Box sx={{ mt: 0.5 }}>\n <Button\n size=\"small\"\n aria-expanded={detailsOpen}\n onClick={() => setDetailsOpen((prior) => !prior)}\n >\n {detailsOpen ? 'Hide what was refused' : 'Show what was refused'}\n </Button>\n <Collapse in={detailsOpen} unmountOnExit>\n <Typography\n variant=\"caption\"\n component=\"pre\"\n aria-label=\"What was refused\"\n sx={{ m: 0, fontFamily: 'monospace', whiteSpace: 'pre', overflowX: 'auto' }}\n >\n {details.join('\\n')}\n </Typography>\n </Collapse>\n </Box>\n )}\n {range && range.ceiling > 0 && (\n <Typography\n variant=\"caption\"\n color=\"text.secondary\"\n sx={{ display: 'block', mt: 1 }}\n >\n {`Estimated cost: ${aiCreditRangeText(range)}. What it costs is what its steps spend.`}\n {freeCredits && !prompt\n ? ` You have ${freeCredits.left.toLocaleString('en-US')} of your free AI credits left this month, until ${aiFreeCreditsResetLabel(freeCredits.resetsOn)}.`\n : ''}\n </Typography>\n )}\n {pageCapNote && (\n <Typography variant=\"caption\" color=\"text.secondary\" sx={{ display: 'block', mt: 0.5 }}>\n {pageCapNote}\n </Typography>\n )}\n {waiting && review.retryRefusal && review.reason !== 'plan' && (\n <Typography variant=\"caption\" color=\"text.secondary\" component=\"div\" sx={{ mt: 1 }}>\n {review.retryRefusal}\n </Typography>\n )}\n {offersPublish && (\n <FormControlLabel\n sx={{ display: 'flex', mt: 1 }}\n control={<Checkbox size=\"small\" checked={publish} onChange={(event) => setPublish(event.target.checked)} />}\n label={<Typography variant=\"body2\">{'Publish the new pages when they are built'}</Typography>}\n />\n )}\n {waiting && prompt && (\n <AiCreditsPromptNotice\n prompt={prompt}\n noun=\"build\"\n orgSlug={orgSlug}\n busy={busy}\n onBuildWhatFits={() => onResume(job, { ...publishing, creditsConfirmed: true })}\n onSmaller={() => onResume(job, { ...publishing, creditsConfirmed: true, reduce: 'first-page' })}\n />\n )}\n {building && (\n <Alert severity=\"info\" sx={{ mt: 1 }}>\n {AI_SITE_BUILD_IN_FLIGHT_COPY}\n </Alert>\n )}\n {waiting && !prompt && (\n <Button\n size=\"small\"\n variant=\"contained\"\n // Disabled with its reason above when the Free allowance left\n // cannot pay for another try (AGL-3594).\n disabled={busy || (review.reason !== 'plan' && Boolean(review.retryRefusal))}\n onClick={() => onResume(job, offersPublish && publish ? publishing : undefined)}\n sx={{ mt: 1 }}\n >\n {review.reason === 'plan' ? 'Confirm plan' : 'Try again'}\n </Button>\n )}\n {/* A guided start that did not work out can take the starter instead (AGL-3594). */}\n {waiting && user && aiSiteStarterFallbackOffered(job) && <AiSiteStarterFallback job={job} user={user} />}\n </Box>\n )\n}\n\nexport default AiJobPlan\n"],"names":["aiJobPlanHeading","aiJobPlanLines","aiPlanEmbedLine","aiBuildFreePageCapNote","aiBuildSmaller","aiJobCreditRange","aiCreditRangeText","aiCreditsPromptFor","aiFreeCreditsResetLabel","AiCreditsPromptNotice","AI_PAGE_BUILDING_JOB_KINDS","AI_SITE_BUILD_IN_FLIGHT_COPY","aiJobConfirmingOwnPlan","aiSiteBuildInFlight","aiSiteStarterFallbackOffered","useAiJobsInFlightKnown","AiSiteStarterFallback","Alert","Box","Button","Checkbox","Collapse","FormControlLabel","Stack","Typography","useState","aiJobReviewDetails","review","reason","lines","findings","flatMap","finding","where","nodeIds","length","join","paths","rule","code","node","outline","push","repeat","depth","id","componentId","Object","entries","grid","map","name","value","JSON","stringify","props","sx","children","AiJobPlan","job","onResume","busy","staff","user","orgSlug","detailsOpen","setDetailsOpen","publish","setPublish","confirmsPages","status","includes","kind","inFlight","orgId","building","hostId","exceptJobId","plan","details","waiting","range","freeCredits","prompt","pageCapNote","Boolean","offersPublish","publishAsked","publishing","mt","spacing","role","aria-label","variant","color","line","platformAdded","text","key","detail","component","my","pl","index","message","size","aria-expanded","onClick","prior","in","unmountOnExit","m","fontFamily","whiteSpace","overflowX","ceiling","display","left","toLocaleString","resetsOn","retryRefusal","control","checked","onChange","event","target","label","noun","onBuildWhatFits","creditsConfirmed","onSmaller","reduce","severity","disabled","undefined"],"mappings":"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"}
@@ -355,15 +355,54 @@ export function AiSiteStartCard({ hostId, orgId, orgSlug, host, startBlank, leav
355
355
  setServerPrompt(null);
356
356
  try {
357
357
  var _ref;
358
+ const requestJob = (siteId, check)=>authorizedFetch(userRef.current, '/api/ai/jobs', {
359
+ method: 'POST',
360
+ headers: {
361
+ 'Content-Type': 'application/json'
362
+ },
363
+ body: JSON.stringify(_extends({
364
+ orgId,
365
+ hostId: siteId,
366
+ kind: 'site',
367
+ brief: aiSiteStartBrief(asked),
368
+ // The guided start confirms its own plan (AGL-3594): the build
369
+ // follows the plan with no approval to make.
370
+ inputs: _extends({}, aiSiteStartInputs(asked), {
371
+ [AI_JOB_AUTO_CONFIRM_INPUT]: true
372
+ })
373
+ }, pickedModel ? {
374
+ model: pickedModel
375
+ } : {}, options.creditsConfirmed ? {
376
+ creditsConfirmed: true
377
+ } : {}, check ? {
378
+ check: true
379
+ } : {}))
380
+ });
381
+ // A refusal said in the dialog, or the Free go-ahead it asks for.
382
+ const refused = async (response)=>{
383
+ var _ref;
384
+ const payload = await response.json().catch(()=>null);
385
+ if (response.ok) return payload != null ? payload : {};
386
+ if (response.status === 409 && (payload == null ? void 0 : payload.code) === AI_CREDITS_CONFIRM_CODE && (payload == null ? void 0 : payload.credits)) {
387
+ setServerPrompt(payload.credits);
388
+ return null;
389
+ }
390
+ const locked = parseLockdownRefusal(response.status, payload);
391
+ setNotice(locked ? lockdownRefusalText(locked) : String((_ref = payload == null ? void 0 : payload.error) != null ? _ref : 'The site could not be started. Try again.'));
392
+ return null;
393
+ };
358
394
  // The site, created now when it does not exist yet (AGL-3761): this is
359
- // the moment the person asked for it. A refusal is said here, and one
360
- // about the name or address goes back to step 1, where they are typed.
395
+ // the moment the person asked for it. The start is checked first
396
+ // (AGL-3859), so one the jobs route would refuse, or would ask the Free
397
+ // go-ahead for, is answered before any site exists. A refusal about the
398
+ // name or address goes back to step 1, where they are typed.
361
399
  let site = {
362
400
  hostId,
363
401
  host,
364
402
  orgSlug
365
403
  };
366
404
  if (!hostId && pendingSite) {
405
+ if (!pendingSite.created && !await refused(await requestJob(null, true))) return;
367
406
  const made = await pendingSite.create();
368
407
  if ('error' in made) {
369
408
  setNotice(made.error);
@@ -377,38 +416,8 @@ export function AiSiteStartCard({ hostId, orgId, orgSlug, host, startBlank, leav
377
416
  };
378
417
  }
379
418
  if (!site.hostId) return;
380
- const response = await authorizedFetch(userRef.current, '/api/ai/jobs', {
381
- method: 'POST',
382
- headers: {
383
- 'Content-Type': 'application/json'
384
- },
385
- body: JSON.stringify(_extends({
386
- orgId,
387
- hostId: site.hostId,
388
- kind: 'site',
389
- brief: aiSiteStartBrief(asked),
390
- // The guided start confirms its own plan (AGL-3594): the build
391
- // follows the plan with no approval to make.
392
- inputs: _extends({}, aiSiteStartInputs(asked), {
393
- [AI_JOB_AUTO_CONFIRM_INPUT]: true
394
- })
395
- }, pickedModel ? {
396
- model: pickedModel
397
- } : {}, options.creditsConfirmed ? {
398
- creditsConfirmed: true
399
- } : {}))
400
- });
401
- const payload = await response.json().catch(()=>null);
402
- if (!response.ok) {
403
- var _ref1;
404
- if (response.status === 409 && (payload == null ? void 0 : payload.code) === AI_CREDITS_CONFIRM_CODE && (payload == null ? void 0 : payload.credits)) {
405
- setServerPrompt(payload.credits);
406
- return;
407
- }
408
- const locked = parseLockdownRefusal(response.status, payload);
409
- setNotice(locked ? lockdownRefusalText(locked) : String((_ref1 = payload == null ? void 0 : payload.error) != null ? _ref1 : 'The site could not be started. Try again.'));
410
- return;
411
- }
419
+ const payload = await refused(await requestJob(site.hostId, false));
420
+ if (!payload) return;
412
421
  const created = (_ref = payload == null ? void 0 : payload.job) != null ? _ref : null;
413
422
  if (!created) {
414
423
  setNotice('The site could not be started. Try again.');