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

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 (274) hide show
  1. package/README.md +3 -3
  2. package/package.json +17 -17
  3. package/src/lib/activity/ai-activity-actions.js +7 -1
  4. package/src/lib/activity/ai-activity-actions.js.map +1 -1
  5. package/src/lib/components/ai-automation-zones.d.ts +38 -0
  6. package/src/lib/components/ai-automation-zones.js +5 -1
  7. package/src/lib/components/ai-automation-zones.js.map +1 -1
  8. package/src/lib/components/ai-brief-dialog.component.d.ts +20 -2
  9. package/src/lib/components/ai-brief-dialog.component.js +87 -8
  10. package/src/lib/components/ai-brief-dialog.component.js.map +1 -1
  11. package/src/lib/components/ai-campaign-create.component.d.ts +54 -0
  12. package/src/lib/components/ai-campaign-create.component.js +270 -0
  13. package/src/lib/components/ai-campaign-create.component.js.map +1 -0
  14. package/src/lib/components/ai-describe-automation.component.d.ts +8 -3
  15. package/src/lib/components/ai-describe-automation.component.js +15 -6
  16. package/src/lib/components/ai-describe-automation.component.js.map +1 -1
  17. package/src/lib/components/ai-describe-button.component.d.ts +20 -8
  18. package/src/lib/components/ai-describe-button.component.js +19 -36
  19. package/src/lib/components/ai-describe-button.component.js.map +1 -1
  20. package/src/lib/components/ai-describe-email.component.d.ts +31 -0
  21. package/src/lib/components/ai-describe-email.component.js +22 -0
  22. package/src/lib/components/ai-describe-email.component.js.map +1 -0
  23. package/src/lib/components/ai-describe-org-automation.component.d.ts +36 -0
  24. package/src/lib/components/ai-describe-org-automation.component.js +238 -0
  25. package/src/lib/components/ai-describe-org-automation.component.js.map +1 -0
  26. package/src/lib/components/ai-experiment-cards.component.d.ts +9 -1
  27. package/src/lib/components/ai-experiment-cards.component.js +104 -18
  28. package/src/lib/components/ai-experiment-cards.component.js.map +1 -1
  29. package/src/lib/components/ai-explain-automation.component.js +1 -5
  30. package/src/lib/components/ai-explain-automation.component.js.map +1 -1
  31. package/src/lib/components/ai-funnel-zones.component.d.ts +61 -0
  32. package/src/lib/components/ai-funnel-zones.component.js +178 -0
  33. package/src/lib/components/ai-funnel-zones.component.js.map +1 -0
  34. package/src/lib/components/ai-insight-card.component.d.ts +42 -0
  35. package/src/lib/components/ai-insight-card.component.js +137 -0
  36. package/src/lib/components/ai-insight-card.component.js.map +1 -0
  37. package/src/lib/components/ai-insight-dialog.component.d.ts +6 -0
  38. package/src/lib/components/ai-insight-dialog.component.js +9 -3
  39. package/src/lib/components/ai-insight-dialog.component.js.map +1 -1
  40. package/src/lib/components/ai-job-plan.component.d.ts +7 -2
  41. package/src/lib/components/ai-job-plan.component.js +35 -5
  42. package/src/lib/components/ai-job-plan.component.js.map +1 -1
  43. package/src/lib/components/ai-job-requests.d.ts +17 -1
  44. package/src/lib/components/ai-job-requests.js +39 -3
  45. package/src/lib/components/ai-job-requests.js.map +1 -1
  46. package/src/lib/components/ai-jobs-list-page.component.js +12 -1
  47. package/src/lib/components/ai-jobs-list-page.component.js.map +1 -1
  48. package/src/lib/components/ai-logic-zones.d.ts +64 -0
  49. package/src/lib/components/ai-logic-zones.js +18 -0
  50. package/src/lib/components/ai-logic-zones.js.map +1 -0
  51. package/src/lib/components/ai-logic.component.d.ts +77 -0
  52. package/src/lib/components/ai-logic.component.js +553 -0
  53. package/src/lib/components/ai-logic.component.js.map +1 -0
  54. package/src/lib/components/ai-marketing-insight.component.d.ts +30 -0
  55. package/src/lib/components/ai-marketing-insight.component.js +80 -0
  56. package/src/lib/components/ai-marketing-insight.component.js.map +1 -0
  57. package/src/lib/components/ai-media-create.component.d.ts +55 -0
  58. package/src/lib/components/ai-media-create.component.js +433 -0
  59. package/src/lib/components/ai-media-create.component.js.map +1 -0
  60. package/src/lib/components/ai-overlay-cards.component.d.ts +83 -0
  61. package/src/lib/components/ai-overlay-cards.component.js +505 -0
  62. package/src/lib/components/ai-overlay-cards.component.js.map +1 -0
  63. package/src/lib/components/ai-product-zones.d.ts +5 -0
  64. package/src/lib/components/ai-product-zones.js +1 -1
  65. package/src/lib/components/ai-product-zones.js.map +1 -1
  66. package/src/lib/components/ai-products-create-button.component.d.ts +42 -0
  67. package/src/lib/components/ai-products-create-button.component.js +67 -0
  68. package/src/lib/components/ai-products-create-button.component.js.map +1 -0
  69. package/src/lib/components/ai-products-hub-card.component.js +100 -81
  70. package/src/lib/components/ai-products-hub-card.component.js.map +1 -1
  71. package/src/lib/components/ai-revise-automation.component.d.ts +16 -0
  72. package/src/lib/components/ai-revise-automation.component.js +207 -0
  73. package/src/lib/components/ai-revise-automation.component.js.map +1 -0
  74. package/src/lib/components/ai-site-build-page.component.d.ts +1 -1
  75. package/src/lib/components/ai-site-build-page.component.js +177 -20
  76. package/src/lib/components/ai-site-build-page.component.js.map +1 -1
  77. package/src/lib/components/ai-site-start-card.component.d.ts +10 -1
  78. package/src/lib/components/ai-site-start-card.component.js +7 -4
  79. package/src/lib/components/ai-site-start-card.component.js.map +1 -1
  80. package/src/lib/components/ai-upsell-dialog.component.d.ts +53 -0
  81. package/src/lib/components/ai-upsell-dialog.component.js +177 -0
  82. package/src/lib/components/ai-upsell-dialog.component.js.map +1 -0
  83. package/src/lib/components/assist-build-card.component.d.ts +42 -0
  84. package/src/lib/components/assist-build-card.component.js +183 -0
  85. package/src/lib/components/assist-build-card.component.js.map +1 -0
  86. package/src/lib/components/assist-edit-canvas.d.ts +2 -0
  87. package/src/lib/components/assist-edit-canvas.js +56 -1
  88. package/src/lib/components/assist-edit-canvas.js.map +1 -1
  89. package/src/lib/components/assist-jobs-drawer.component.d.ts +11 -0
  90. package/src/lib/components/assist-jobs-drawer.component.js +85 -4
  91. package/src/lib/components/assist-jobs-drawer.component.js.map +1 -1
  92. package/src/lib/components/assist-panel.component.js +51 -2
  93. package/src/lib/components/assist-panel.component.js.map +1 -1
  94. package/src/lib/components/use-ai-job-run.d.ts +3 -14
  95. package/src/lib/components/use-ai-job-run.js +0 -50
  96. package/src/lib/components/use-ai-job-run.js.map +1 -1
  97. package/src/lib/jobs/ai-build-capabilities.d.ts +58 -0
  98. package/src/lib/jobs/ai-build-capabilities.js +256 -0
  99. package/src/lib/jobs/ai-build-capabilities.js.map +1 -0
  100. package/src/lib/jobs/ai-build-unit-outcome.d.ts +52 -0
  101. package/src/lib/jobs/ai-build-unit-outcome.js +138 -0
  102. package/src/lib/jobs/ai-build-unit-outcome.js.map +1 -0
  103. package/src/lib/jobs/ai-job-build-step.d.ts +144 -0
  104. package/src/lib/jobs/ai-job-build-step.js +657 -0
  105. package/src/lib/jobs/ai-job-build-step.js.map +1 -0
  106. package/src/lib/jobs/ai-job-draft-ids.js +9 -1
  107. package/src/lib/jobs/ai-job-draft-ids.js.map +1 -1
  108. package/src/lib/jobs/ai-job-drafts.d.ts +14 -4
  109. package/src/lib/jobs/ai-job-drafts.js +25 -4
  110. package/src/lib/jobs/ai-job-drafts.js.map +1 -1
  111. package/src/lib/jobs/ai-job-layout-site-pages.d.ts +70 -0
  112. package/src/lib/jobs/ai-job-layout-site-pages.js +216 -0
  113. package/src/lib/jobs/ai-job-layout-site-pages.js.map +1 -0
  114. package/src/lib/jobs/ai-job-layout-step.d.ts +2 -2
  115. package/src/lib/jobs/ai-job-layout-step.js +19 -1
  116. package/src/lib/jobs/ai-job-layout-step.js.map +1 -1
  117. package/src/lib/jobs/ai-job-logic-step.d.ts +107 -0
  118. package/src/lib/jobs/ai-job-logic-step.js +395 -0
  119. package/src/lib/jobs/ai-job-logic-step.js.map +1 -0
  120. package/src/lib/jobs/ai-job-overlay-copy.d.ts +70 -0
  121. package/src/lib/jobs/ai-job-overlay-copy.js +178 -0
  122. package/src/lib/jobs/ai-job-overlay-copy.js.map +1 -0
  123. package/src/lib/jobs/ai-job-page-step.js +6 -6
  124. package/src/lib/jobs/ai-job-page-step.js.map +1 -1
  125. package/src/lib/jobs/ai-job-plan-step.d.ts +26 -1
  126. package/src/lib/jobs/ai-job-plan-step.js +79 -11
  127. package/src/lib/jobs/ai-job-plan-step.js.map +1 -1
  128. package/src/lib/jobs/ai-job-site-step.d.ts +15 -1
  129. package/src/lib/jobs/ai-job-site-step.js +207 -58
  130. package/src/lib/jobs/ai-job-site-step.js.map +1 -1
  131. package/src/lib/jobs/ai-job-text-step.d.ts +22 -1
  132. package/src/lib/jobs/ai-job-text-step.js +12 -0
  133. package/src/lib/jobs/ai-job-text-step.js.map +1 -1
  134. package/src/lib/jobs/ai-job-workflow-step.d.ts +54 -4
  135. package/src/lib/jobs/ai-job-workflow-step.js +318 -13
  136. package/src/lib/jobs/ai-job-workflow-step.js.map +1 -1
  137. package/src/lib/jobs/ai-jobs.d.ts +90 -2
  138. package/src/lib/jobs/ai-jobs.js +495 -61
  139. package/src/lib/jobs/ai-jobs.js.map +1 -1
  140. package/src/lib/jobs/ai-logic-records.d.ts +40 -0
  141. package/src/lib/jobs/ai-logic-records.js +55 -0
  142. package/src/lib/jobs/ai-logic-records.js.map +1 -0
  143. package/src/lib/jobs/ai-site-publish.d.ts +7 -0
  144. package/src/lib/jobs/ai-site-publish.js +9 -0
  145. package/src/lib/jobs/ai-site-publish.js.map +1 -1
  146. package/src/lib/jobs/ai-workflow-records.d.ts +4 -0
  147. package/src/lib/jobs/ai-workflow-records.js +40 -1
  148. package/src/lib/jobs/ai-workflow-records.js.map +1 -1
  149. package/src/lib/model/ai-automation-draft.d.ts +18 -0
  150. package/src/lib/model/ai-automation-draft.js +86 -0
  151. package/src/lib/model/ai-automation-draft.js.map +1 -1
  152. package/src/lib/model/ai-build-job.d.ts +201 -0
  153. package/src/lib/model/ai-build-job.js +471 -0
  154. package/src/lib/model/ai-build-job.js.map +1 -0
  155. package/src/lib/model/ai-build-plan.d.ts +61 -0
  156. package/src/lib/model/ai-build-plan.js +154 -9
  157. package/src/lib/model/ai-build-plan.js.map +1 -1
  158. package/src/lib/model/ai-build-progress.d.ts +56 -0
  159. package/src/lib/model/ai-build-progress.js +128 -0
  160. package/src/lib/model/ai-build-progress.js.map +1 -0
  161. package/src/lib/model/ai-insight.d.ts +20 -10
  162. package/src/lib/model/ai-insight.js +72 -9
  163. package/src/lib/model/ai-insight.js.map +1 -1
  164. package/src/lib/model/ai-job-activity.js +3 -1
  165. package/src/lib/model/ai-job-activity.js.map +1 -1
  166. package/src/lib/model/ai-job-failure-copy.d.ts +20 -1
  167. package/src/lib/model/ai-job-failure-copy.js +28 -1
  168. package/src/lib/model/ai-job-failure-copy.js.map +1 -1
  169. package/src/lib/model/ai-job-notice.d.ts +3 -0
  170. package/src/lib/model/ai-job-notice.js +11 -2
  171. package/src/lib/model/ai-job-notice.js.map +1 -1
  172. package/src/lib/model/ai-jobs.types.d.ts +87 -2
  173. package/src/lib/model/ai-jobs.types.js +3 -1
  174. package/src/lib/model/ai-jobs.types.js.map +1 -1
  175. package/src/lib/model/ai-logic-job.d.ts +108 -0
  176. package/src/lib/model/ai-logic-job.js +327 -0
  177. package/src/lib/model/ai-logic-job.js.map +1 -0
  178. package/src/lib/model/ai-media-credits.d.ts +52 -0
  179. package/src/lib/model/ai-media-credits.js +61 -0
  180. package/src/lib/model/ai-media-credits.js.map +1 -0
  181. package/src/lib/model/ai-overlay-copy.d.ts +114 -0
  182. package/src/lib/model/ai-overlay-copy.js +175 -0
  183. package/src/lib/model/ai-overlay-copy.js.map +1 -0
  184. package/src/lib/model/ai-site-build-progress.d.ts +28 -3
  185. package/src/lib/model/ai-site-build-progress.js +231 -17
  186. package/src/lib/model/ai-site-build-progress.js.map +1 -1
  187. package/src/lib/model/ai-site-start-seo.d.ts +16 -0
  188. package/src/lib/model/ai-site-start-seo.js +54 -4
  189. package/src/lib/model/ai-site-start-seo.js.map +1 -1
  190. package/src/lib/model/ai-site-start.d.ts +14 -0
  191. package/src/lib/model/ai-site-start.js +43 -0
  192. package/src/lib/model/ai-site-start.js.map +1 -1
  193. package/src/lib/model/ai-svg.d.ts +69 -0
  194. package/src/lib/model/ai-svg.js +265 -0
  195. package/src/lib/model/ai-svg.js.map +1 -0
  196. package/src/lib/model/ai-usage-by-user.d.ts +3 -2
  197. package/src/lib/model/ai-usage-by-user.js.map +1 -1
  198. package/src/lib/model/ai-workflow-job.d.ts +92 -4
  199. package/src/lib/model/ai-workflow-job.js +124 -7
  200. package/src/lib/model/ai-workflow-job.js.map +1 -1
  201. package/src/lib/model/assist-build.d.ts +58 -0
  202. package/src/lib/model/assist-build.js +52 -0
  203. package/src/lib/model/assist-build.js.map +1 -0
  204. package/src/lib/model/assist-edit.d.ts +48 -3
  205. package/src/lib/model/assist-edit.js +48 -4
  206. package/src/lib/model/assist-edit.js.map +1 -1
  207. package/src/lib/plugin-config.js +2 -0
  208. package/src/lib/plugin-config.js.map +1 -1
  209. package/src/lib/plugin.js +240 -11
  210. package/src/lib/plugin.js.map +1 -1
  211. package/src/lib/providers/catalog.d.ts +81 -4
  212. package/src/lib/providers/catalog.js +80 -9
  213. package/src/lib/providers/catalog.js.map +1 -1
  214. package/src/lib/providers/image-contract.d.ts +116 -0
  215. package/src/lib/providers/image-contract.js +74 -0
  216. package/src/lib/providers/image-contract.js.map +1 -0
  217. package/src/lib/providers/model-choice.js +11 -0
  218. package/src/lib/providers/model-choice.js.map +1 -1
  219. package/src/lib/providers/routing.js +18 -0
  220. package/src/lib/providers/routing.js.map +1 -1
  221. package/src/lib/providers/vertex-image.d.ts +121 -0
  222. package/src/lib/providers/vertex-image.js +312 -0
  223. package/src/lib/providers/vertex-image.js.map +1 -0
  224. package/src/lib/runtime/ai-doctrine-validators.d.ts +19 -0
  225. package/src/lib/runtime/ai-doctrine-validators.js +89 -0
  226. package/src/lib/runtime/ai-doctrine-validators.js.map +1 -1
  227. package/src/lib/runtime/ai-doctrine.d.ts +6 -0
  228. package/src/lib/runtime/ai-doctrine.js +16 -6
  229. package/src/lib/runtime/ai-doctrine.js.map +1 -1
  230. package/src/lib/runtime/ai-eval-live.js +4 -0
  231. package/src/lib/runtime/ai-eval-live.js.map +1 -1
  232. package/src/lib/runtime/ai-eval.d.ts +15 -1
  233. package/src/lib/runtime/ai-eval.js +52 -1
  234. package/src/lib/runtime/ai-eval.js.map +1 -1
  235. package/src/lib/runtime/experiment-variant-copy.d.ts +34 -0
  236. package/src/lib/runtime/experiment-variant-copy.js +102 -0
  237. package/src/lib/runtime/experiment-variant-copy.js.map +1 -0
  238. package/src/lib/server/ai-experiment-versions.d.ts +51 -0
  239. package/src/lib/server/ai-experiment-versions.js +270 -0
  240. package/src/lib/server/ai-experiment-versions.js.map +1 -0
  241. package/src/lib/server/ai-jobs-resume.js +74 -4
  242. package/src/lib/server/ai-jobs-resume.js.map +1 -1
  243. package/src/lib/server/ai-media-image.d.ts +66 -0
  244. package/src/lib/server/ai-media-image.js +521 -0
  245. package/src/lib/server/ai-media-image.js.map +1 -0
  246. package/src/lib/server/ai-media-svg.d.ts +91 -0
  247. package/src/lib/server/ai-media-svg.js +186 -0
  248. package/src/lib/server/ai-media-svg.js.map +1 -0
  249. package/src/lib/server/assist-build.d.ts +54 -0
  250. package/src/lib/server/assist-build.js +121 -0
  251. package/src/lib/server/assist-build.js.map +1 -0
  252. package/src/lib/server/assist-chat.js +108 -12
  253. package/src/lib/server/assist-chat.js.map +1 -1
  254. package/src/lib/server/assist-edit.js +213 -3
  255. package/src/lib/server/assist-edit.js.map +1 -1
  256. package/src/lib/server/assist-view-context.js +242 -4
  257. package/src/lib/server/assist-view-context.js.map +1 -1
  258. package/src/lib/server.js +26 -0
  259. package/src/lib/server.js.map +1 -1
  260. package/src/lib/tools/ai-logic-tool.d.ts +27 -0
  261. package/src/lib/tools/ai-logic-tool.js +207 -0
  262. package/src/lib/tools/ai-logic-tool.js.map +1 -0
  263. package/src/lib/tools/ai-overlay-tool.d.ts +35 -0
  264. package/src/lib/tools/ai-overlay-tool.js +107 -0
  265. package/src/lib/tools/ai-overlay-tool.js.map +1 -0
  266. package/src/lib/tools/ai-workflow-tool.d.ts +11 -0
  267. package/src/lib/tools/ai-workflow-tool.js +31 -0
  268. package/src/lib/tools/ai-workflow-tool.js.map +1 -1
  269. package/src/lib/usage/assist-job-refund.d.ts +31 -3
  270. package/src/lib/usage/assist-job-refund.js +46 -10
  271. package/src/lib/usage/assist-job-refund.js.map +1 -1
  272. package/src/lib/usage/assist-usage.d.ts +5 -0
  273. package/src/lib/usage/assist-usage.js +2 -0
  274. package/src/lib/usage/assist-usage.js.map +1 -1
@@ -0,0 +1,207 @@
1
+ 'use client';
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ /**
4
+ * @license
5
+ * Copyright 2026 Aglyn LLC
6
+ *
7
+ * Licensed under the Apache License, Version 2.0 (the "License");
8
+ * you may not use this file except in compliance with the License.
9
+ * You may obtain a copy of the License at
10
+ *
11
+ * http://www.apache.org/licenses/LICENSE-2.0
12
+ *
13
+ * Unless required by applicable law or agreed to in writing, software
14
+ * distributed under the License is distributed on an "AS IS" BASIS,
15
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
+ * See the License for the specific language governing permissions and
17
+ * limitations under the License.
18
+ */ import { pluginDocsHelp } from "@aglyn/aglyn/app-utils/docs-help";
19
+ import { mdiCreation } from "@aglyn/shared-data-mdi";
20
+ import { MdiIcon } from "@aglyn/shared-ui-jsx";
21
+ import { useUser } from "@aglyn/tenant-feature-instance";
22
+ import { Alert, Box, Button, CircularProgress, Link, Stack, TextField, Typography } from "@mui/material";
23
+ import { useState } from "react";
24
+ import { openAiJobs } from "./ai-jobs-store.js";
25
+ import { aiJobProblem, useAiJobRun } from "./use-ai-job-run.js";
26
+ /**
27
+ * "Fix with AI" and "Change with AI" in the editor of a saved ACTION
28
+ * (AGL-3603), through the `automationEditor` zone. Each starts a `workflow`
29
+ * job in `revise` mode: the action as it is saved, and the change asked of
30
+ * it, become a NEW automation drafted switched off. The saved action is never
31
+ * written; the person opens the copy, reads what changed, and switches it on
32
+ * in place of the old one when it is right.
33
+ *
34
+ * A workflow of function calls is not offered either: the draft writer writes
35
+ * actions, and a workflow is explained rather than revised.
36
+ */ /** The longest change a job admits as its brief. */ const BRIEF_MAX_CHARS = 4000;
37
+ export const AI_AUTOMATION_REVISE_COPY = {
38
+ intro: 'Describe a change, or let AI fix what would stop it working. You get a changed copy, switched off, to review — this one is left as it is.',
39
+ label: 'What should change?',
40
+ placeholder: 'Also tag them “newsletter”, and wait a day before the email',
41
+ change: 'Change with AI',
42
+ fix: 'Fix with AI',
43
+ running: 'Drafting the changed copy. This can take a few minutes.',
44
+ drafted: 'Changed copy drafted',
45
+ review: 'Review the copy',
46
+ notListed: 'The copy is saved. It appears in the list in a moment.',
47
+ failed: 'The automation could not be changed. Try again.',
48
+ fixBrief: (name)=>`Fix whatever in “${name}” would stop it working as intended — a record the site no longer has, a condition that can never match, a step in the wrong order. Change nothing else.`
49
+ };
50
+ export function AiReviseAutomation({ hostId, orgId, target, openAction }) {
51
+ var _aiJobProblem;
52
+ const copy = AI_AUTOMATION_REVISE_COPY;
53
+ const help = pluginDocsHelp('aiAutomations', {
54
+ anchor: '#change'
55
+ });
56
+ const { data: user } = useUser();
57
+ const run = useAiJobRun(user, copy.failed);
58
+ const [brief, setBrief] = useState('');
59
+ const [notListed, setNotListed] = useState(false);
60
+ if (target.type !== 'action') return null;
61
+ const { job } = run;
62
+ const busy = run.starting || run.running;
63
+ const draft = (job == null ? void 0 : job.status) === 'done' ? job.outputs.find((output)=>output.resource === 'workflow') : undefined;
64
+ const problem = (_aiJobProblem = aiJobProblem(job, copy.failed)) != null ? _aiJobProblem : (job == null ? void 0 : job.status) === 'done' && !draft ? copy.failed : null;
65
+ const start = async (text)=>{
66
+ const trimmed = text.trim();
67
+ if (!orgId || !trimmed) return;
68
+ setNotListed(false);
69
+ if (await run.start({
70
+ orgId,
71
+ hostId,
72
+ kind: 'workflow',
73
+ brief: trimmed,
74
+ inputs: {
75
+ mode: 'revise',
76
+ targetType: 'action',
77
+ targetId: target.id
78
+ }
79
+ })) {
80
+ setBrief('');
81
+ }
82
+ };
83
+ const review = ()=>{
84
+ if (!draft) return;
85
+ if (!(openAction == null ? void 0 : openAction(draft.id))) setNotListed(true);
86
+ };
87
+ return /*#__PURE__*/ _jsx(Box, {
88
+ sx: {
89
+ border: 1,
90
+ borderColor: 'divider',
91
+ borderRadius: 1,
92
+ p: 1.5
93
+ },
94
+ "aria-label": "Change this automation with AI",
95
+ children: /*#__PURE__*/ _jsxs(Stack, {
96
+ spacing: 1,
97
+ children: [
98
+ /*#__PURE__*/ _jsxs(Typography, {
99
+ variant: "body2",
100
+ color: "text.secondary",
101
+ children: [
102
+ copy.intro,
103
+ ' ',
104
+ /*#__PURE__*/ _jsx(Link, {
105
+ href: help.href,
106
+ target: "_blank",
107
+ rel: "noopener",
108
+ title: help.excerpt,
109
+ children: 'How it works'
110
+ })
111
+ ]
112
+ }),
113
+ /*#__PURE__*/ _jsx(TextField, {
114
+ size: "small",
115
+ label: copy.label,
116
+ placeholder: copy.placeholder,
117
+ value: brief,
118
+ multiline: true,
119
+ maxRows: 4,
120
+ onChange: (event)=>setBrief(event.target.value.slice(0, BRIEF_MAX_CHARS)),
121
+ disabled: busy
122
+ }),
123
+ /*#__PURE__*/ _jsxs(Stack, {
124
+ direction: "row",
125
+ spacing: 1,
126
+ children: [
127
+ /*#__PURE__*/ _jsx(Button, {
128
+ size: "small",
129
+ variant: "outlined",
130
+ startIcon: /*#__PURE__*/ _jsx(MdiIcon, {
131
+ path: mdiCreation.path
132
+ }),
133
+ disabled: busy || !orgId || !brief.trim(),
134
+ onClick: ()=>void start(brief),
135
+ children: copy.change
136
+ }),
137
+ /*#__PURE__*/ _jsx(Button, {
138
+ size: "small",
139
+ variant: "text",
140
+ startIcon: /*#__PURE__*/ _jsx(MdiIcon, {
141
+ path: mdiCreation.path
142
+ }),
143
+ disabled: busy || !orgId,
144
+ onClick: ()=>void start(copy.fixBrief(target.name)),
145
+ children: copy.fix
146
+ })
147
+ ]
148
+ }),
149
+ run.running && job ? /*#__PURE__*/ _jsx(Alert, {
150
+ severity: "info",
151
+ icon: /*#__PURE__*/ _jsx(CircularProgress, {
152
+ size: 18,
153
+ "aria-label": "Drafting"
154
+ }),
155
+ action: /*#__PURE__*/ _jsx(Button, {
156
+ color: "inherit",
157
+ size: "small",
158
+ variant: "outlined",
159
+ onClick: ()=>openAiJobs({
160
+ jobId: job.id
161
+ }),
162
+ children: 'Open AI jobs'
163
+ }),
164
+ children: copy.running
165
+ }) : null,
166
+ draft ? /*#__PURE__*/ _jsxs(Alert, {
167
+ severity: "success",
168
+ action: openAction ? /*#__PURE__*/ _jsx(Button, {
169
+ color: "inherit",
170
+ size: "small",
171
+ variant: "outlined",
172
+ onClick: review,
173
+ children: copy.review
174
+ }) : undefined,
175
+ children: [
176
+ /*#__PURE__*/ _jsx(Typography, {
177
+ variant: "body2",
178
+ sx: {
179
+ fontWeight: 600
180
+ },
181
+ children: `${copy.drafted}: ${draft.label}`
182
+ }),
183
+ draft.note ? /*#__PURE__*/ _jsx(Typography, {
184
+ variant: "body2",
185
+ children: draft.note
186
+ }) : null
187
+ ]
188
+ }) : null,
189
+ problem ? /*#__PURE__*/ _jsx(Alert, {
190
+ severity: (job == null ? void 0 : job.status) === 'failed' ? 'error' : 'warning',
191
+ children: problem
192
+ }) : null,
193
+ run.notice ? /*#__PURE__*/ _jsx(Alert, {
194
+ severity: "warning",
195
+ children: run.notice
196
+ }) : null,
197
+ notListed ? /*#__PURE__*/ _jsx(Alert, {
198
+ severity: "info",
199
+ children: copy.notListed
200
+ }) : null
201
+ ]
202
+ })
203
+ });
204
+ }
205
+ export default AiReviseAutomation;
206
+
207
+ //# sourceMappingURL=ai-revise-automation.component.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../../../../libs/plugins/ai/src/lib/components/ai-revise-automation.component.tsx"],"sourcesContent":["'use client'\n\n/**\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 { pluginDocsHelp } from '@aglyn/aglyn/app-utils/docs-help'\nimport { mdiCreation } from '@aglyn/shared-data-mdi'\nimport { MdiIcon } from '@aglyn/shared-ui-jsx'\nimport { useUser } from '@aglyn/tenant-feature-instance'\nimport {\n Alert,\n Box,\n Button,\n CircularProgress,\n Link,\n Stack,\n TextField,\n Typography,\n} from '@mui/material'\nimport { useState } from 'react'\nimport { openAiJobs } from './ai-jobs-store'\nimport type { ConsoleAutomationEditorZoneProps } from './ai-automation-zones'\nimport { aiJobProblem, useAiJobRun } from './use-ai-job-run'\n\n/**\n * \"Fix with AI\" and \"Change with AI\" in the editor of a saved ACTION\n * (AGL-3603), through the `automationEditor` zone. Each starts a `workflow`\n * job in `revise` mode: the action as it is saved, and the change asked of\n * it, become a NEW automation drafted switched off. The saved action is never\n * written; the person opens the copy, reads what changed, and switches it on\n * in place of the old one when it is right.\n *\n * A workflow of function calls is not offered either: the draft writer writes\n * actions, and a workflow is explained rather than revised.\n */\n\n/** The longest change a job admits as its brief. */\nconst BRIEF_MAX_CHARS = 4_000\n\nexport const AI_AUTOMATION_REVISE_COPY = {\n intro: 'Describe a change, or let AI fix what would stop it working. You get a changed copy, switched off, to review — this one is left as it is.',\n label: 'What should change?',\n placeholder: 'Also tag them “newsletter”, and wait a day before the email',\n change: 'Change with AI',\n fix: 'Fix with AI',\n running: 'Drafting the changed copy. This can take a few minutes.',\n drafted: 'Changed copy drafted',\n review: 'Review the copy',\n notListed: 'The copy is saved. It appears in the list in a moment.',\n failed: 'The automation could not be changed. Try again.',\n fixBrief: (name: string) =>\n `Fix whatever in “${name}” would stop it working as intended — a record the site no longer has, a condition that can never match, a step in the wrong order. Change nothing else.`,\n} as const\n\nexport function AiReviseAutomation({ hostId, orgId, target, openAction }: ConsoleAutomationEditorZoneProps) {\n const copy = AI_AUTOMATION_REVISE_COPY\n const help = pluginDocsHelp('aiAutomations', { anchor: '#change' })\n const { data: user } = useUser()\n const run = useAiJobRun(user, copy.failed)\n const [brief, setBrief] = useState('')\n const [notListed, setNotListed] = useState(false)\n\n if (target.type !== 'action') return null\n const { job } = run\n const busy = run.starting || run.running\n const draft = job?.status === 'done' ? job.outputs.find((output) => output.resource === 'workflow') : undefined\n const problem = aiJobProblem(job, copy.failed) ?? (job?.status === 'done' && !draft ? copy.failed : null)\n\n const start = async (text: string) => {\n const trimmed = text.trim()\n if (!orgId || !trimmed) return\n setNotListed(false)\n if (\n await run.start({\n orgId,\n hostId,\n kind: 'workflow',\n brief: trimmed,\n inputs: { mode: 'revise', targetType: 'action', targetId: target.id },\n })\n ) {\n setBrief('')\n }\n }\n\n const review = () => {\n if (!draft) return\n if (!openAction?.(draft.id)) setNotListed(true)\n }\n\n return (\n <Box sx={{ border: 1, borderColor: 'divider', borderRadius: 1, p: 1.5 }} aria-label=\"Change this automation with AI\">\n <Stack spacing={1}>\n <Typography variant=\"body2\" color=\"text.secondary\">\n {copy.intro}{' '}\n <Link href={help.href} target=\"_blank\" rel=\"noopener\" title={help.excerpt}>\n {'How it works'}\n </Link>\n </Typography>\n <TextField\n size=\"small\"\n label={copy.label}\n placeholder={copy.placeholder}\n value={brief}\n multiline\n maxRows={4}\n onChange={(event) => setBrief(event.target.value.slice(0, BRIEF_MAX_CHARS))}\n disabled={busy}\n />\n <Stack direction=\"row\" spacing={1}>\n <Button\n size=\"small\"\n variant=\"outlined\"\n startIcon={<MdiIcon path={mdiCreation.path} />}\n disabled={busy || !orgId || !brief.trim()}\n onClick={() => void start(brief)}\n >\n {copy.change}\n </Button>\n <Button\n size=\"small\"\n variant=\"text\"\n startIcon={<MdiIcon path={mdiCreation.path} />}\n disabled={busy || !orgId}\n onClick={() => void start(copy.fixBrief(target.name))}\n >\n {copy.fix}\n </Button>\n </Stack>\n {run.running && job ? (\n <Alert\n severity=\"info\"\n icon={<CircularProgress size={18} aria-label=\"Drafting\" />}\n action={\n <Button color=\"inherit\" size=\"small\" variant=\"outlined\" onClick={() => openAiJobs({ jobId: job.id })}>\n {'Open AI jobs'}\n </Button>\n }\n >\n {copy.running}\n </Alert>\n ) : null}\n {draft ? (\n <Alert\n severity=\"success\"\n action={\n openAction ? (\n <Button color=\"inherit\" size=\"small\" variant=\"outlined\" onClick={review}>\n {copy.review}\n </Button>\n ) : undefined\n }\n >\n <Typography variant=\"body2\" sx={{ fontWeight: 600 }}>\n {`${copy.drafted}: ${draft.label}`}\n </Typography>\n {draft.note ? <Typography variant=\"body2\">{draft.note}</Typography> : null}\n </Alert>\n ) : null}\n {problem ? <Alert severity={job?.status === 'failed' ? 'error' : 'warning'}>{problem}</Alert> : null}\n {run.notice ? <Alert severity=\"warning\">{run.notice}</Alert> : null}\n {notListed ? <Alert severity=\"info\">{copy.notListed}</Alert> : null}\n </Stack>\n </Box>\n )\n}\n\nexport default AiReviseAutomation\n"],"names":["pluginDocsHelp","mdiCreation","MdiIcon","useUser","Alert","Box","Button","CircularProgress","Link","Stack","TextField","Typography","useState","openAiJobs","aiJobProblem","useAiJobRun","BRIEF_MAX_CHARS","AI_AUTOMATION_REVISE_COPY","intro","label","placeholder","change","fix","running","drafted","review","notListed","failed","fixBrief","name","AiReviseAutomation","hostId","orgId","target","openAction","copy","help","anchor","data","user","run","brief","setBrief","setNotListed","type","job","busy","starting","draft","status","outputs","find","output","resource","undefined","problem","start","text","trimmed","trim","kind","inputs","mode","targetType","targetId","id","sx","border","borderColor","borderRadius","p","aria-label","spacing","variant","color","href","rel","title","excerpt","size","value","multiline","maxRows","onChange","event","slice","disabled","direction","startIcon","path","onClick","severity","icon","action","jobId","fontWeight","note","notice"],"mappings":"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"}
@@ -16,7 +16,7 @@
16
16
  */
17
17
  import type { ConsolePluginPageProps } from '@aglyn/aglyn/plugin-manager/feature-plugins';
18
18
  import type { MaybeTokenSource } from '@aglyn/shared-util-http/authorized-token';
19
- import type { AiJobSummary } from '../model/ai-jobs.types';
19
+ import { type AiJobSummary } from '../model/ai-jobs.types';
20
20
  /**
21
21
  * "Building your site" (AGL-3594): one job's page, at `/ai-jobs/{jobId}`
22
22
  * under its site — where the guided start sends a person the moment they
@@ -17,15 +17,20 @@
17
17
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
18
18
  import { PLATFORM_BRAND_NAME } from "@aglyn/aglyn";
19
19
  import { PageHeaderRecord } from "@aglyn/aglyn/app-utils/page-header-record-context";
20
- import { mdiAlertCircle, mdiCheckCircle, mdiChevronDown, mdiClockOutline } from "@aglyn/shared-data-mdi";
20
+ import { mdiAlertCircle, mdiCheckCircle, mdiChevronDown, mdiClockOutline, mdiMinusCircleOutline } from "@aglyn/shared-data-mdi";
21
21
  import { AppLink, MdiIcon } from "@aglyn/shared-ui-jsx";
22
22
  import { useUser } from "@aglyn/tenant-feature-instance";
23
23
  import { Accordion, AccordionDetails, AccordionSummary, Alert, Box, Button, Card, CircularProgress, Container, LinearProgress, Stack, Typography } from "@mui/material";
24
24
  import { useCallback, useEffect, useRef, useState } from "react";
25
- import { aiJobPageCopy, aiSiteBuildCreditsLine, aiSiteBuildPhase, aiSiteBuildRows } from "../model/ai-site-build-progress.js";
26
- import { aiSiteStarterFallbackOffered } from "../model/ai-job-failure-copy.js";
25
+ import { aiJobPageCopy, aiSiteBuildCreditsLine, aiSiteBuildFraction, aiSiteBuildPhase, aiSiteBuildRows } from "../model/ai-site-build-progress.js";
26
+ import { aiJobRefundCopy, aiSiteStarterFallbackOffered } from "../model/ai-job-failure-copy.js";
27
+ import { aiSiteStartAnswersFromInputs } from "../model/ai-site-start.js";
28
+ import { AiSiteStartCard } from "./ai-site-start-card.component.js";
29
+ import { AI_JOB_TERMINAL_STATUSES } from "../model/ai-jobs.types.js";
27
30
  import { followAiJobEvents } from "./ai-job-events.js";
28
31
  import { aiSiteBuildDoneLinks } from "./ai-job-links.js";
32
+ import { AiJobPlan } from "./ai-job-plan.component.js";
33
+ import { aiBuildCanRetry } from "../model/ai-build-progress.js";
29
34
  import { resumeAiJobRequest } from "./ai-job-requests.js";
30
35
  import { useAiJobSite } from "./ai-job-site.js";
31
36
  import { AiSiteStarterFallback } from "./ai-site-starter-fallback.component.js";
@@ -55,7 +60,11 @@ import { AiSiteStarterFallback } from "./ai-site-starter-fallback.component.js";
55
60
  const [job, setJob] = useState(null);
56
61
  const [attempt, setAttempt] = useState(0);
57
62
  const status = job && typeof job === 'object' ? job.status : null;
58
- const moving = status === null || status === 'queued' || status === 'running';
63
+ // Followed until the job ENDS (AGL-3596), not until it first stops: a guided
64
+ // start parks on its plan for the instant it takes to confirm it, and a page
65
+ // that stopped following there showed that park — the plan's 13 credits and
66
+ // "the plan is ready" — after the job had built, spent and failed.
67
+ const moving = status === null || !AI_JOB_TERMINAL_STATUSES.includes(status);
59
68
  useEffect(()=>{
60
69
  if (!orgId || !jobId || !moving) return undefined;
61
70
  const controller = new AbortController();
@@ -106,6 +115,11 @@ const ROW_ICON = {
106
115
  path: mdiAlertCircle.path,
107
116
  color: 'error.main',
108
117
  label: 'Stopped'
118
+ },
119
+ skipped: {
120
+ path: mdiMinusCircleOutline.path,
121
+ color: 'text.disabled',
122
+ label: 'Not built'
109
123
  }
110
124
  };
111
125
  function RowIcon({ state }) {
@@ -131,7 +145,30 @@ function RowIcon({ state }) {
131
145
  })
132
146
  });
133
147
  }
134
- /** The page's frame: the site's name over the heading and its sentence. */ function Frame({ siteName, heading, lede, children }) {
148
+ /** The page's frame: the site's name over the heading and its sentence. */ /** "0:42", "3:05": how long the active row has been running, from when it started or was first seen. */ function useElapsed(key, startedAt) {
149
+ const [now, setNow] = useState(()=>Date.now());
150
+ const seen = useRef({
151
+ key: null,
152
+ at: Date.now()
153
+ });
154
+ if (seen.current.key !== key) seen.current = {
155
+ key,
156
+ at: Date.now()
157
+ };
158
+ useEffect(()=>{
159
+ if (!key) return;
160
+ const timer = setInterval(()=>setNow(Date.now()), 1000);
161
+ return ()=>clearInterval(timer);
162
+ }, [
163
+ key
164
+ ]);
165
+ if (!key) return null;
166
+ const started = startedAt ? Date.parse(startedAt) : NaN;
167
+ const from = Number.isFinite(started) ? Math.min(started, seen.current.at) : seen.current.at;
168
+ const seconds = Math.max(0, Math.floor((now - from) / 1000));
169
+ return `${Math.floor(seconds / 60)}:${String(seconds % 60).padStart(2, '0')}`;
170
+ }
171
+ function Frame({ siteName, heading, lede, children }) {
135
172
  return /*#__PURE__*/ _jsx(Container, {
136
173
  maxWidth: "sm",
137
174
  sx: {
@@ -173,22 +210,30 @@ function RowIcon({ state }) {
173
210
  });
174
211
  }
175
212
  export function AiSiteBuildPage({ hostId, segments, basePath }) {
176
- var _split_, _ready_sitePublish;
177
- var _ready_review, _ready_review1;
213
+ var _split_, _aiSiteBuildRows_find, _rows_find, _ready_sitePublish, _ready_refundedCredits;
214
+ var _ready_review, _ready_review1, _ready_review2;
178
215
  const { data: user } = useUser();
179
216
  const jobId = (segments == null ? void 0 : segments[0]) ? decodeURIComponent(String(segments[0])) : null;
180
217
  const orgSlug = (_split_ = (basePath != null ? basePath : '').split('/')[1]) != null ? _split_ : '';
218
+ // `/{orgSlug}/hosts/{subdomain}/ai-jobs`: the site's subdomain, which a console URL names it by.
219
+ const hostSubdomain = (basePath != null ? basePath : '').split('/')[3] || null;
181
220
  const site = useAiJobSite(hostId);
182
221
  const orgId = site.status === 'ready' ? site.orgId : null;
183
222
  const siteName = site.status === 'ready' ? site.name : undefined;
184
223
  const [job, setJob, retry] = useAiJobById(user, orgId, jobId);
185
224
  const [busy, setBusy] = useState(false);
186
225
  const [notice, setNotice] = useState(null);
226
+ // A failed guided start's Try again reopens its questions, filled in (AGL-3596);
227
+ // `?retry=1` — what the AI jobs drawer links — opens them on arrival.
228
+ const [retrying, setRetrying] = useState(()=>typeof window !== 'undefined' && new URLSearchParams(window.location.search).get('retry') === '1');
187
229
  const tryAgain = useCallback(async ()=>{
188
230
  if (!orgId || !job || typeof job !== 'object') return;
189
231
  setBusy(true);
190
232
  setNotice(null);
191
- const decision = await resumeAiJobRequest(user, orgId, job);
233
+ // A finished build tries again only what failed (AGL-3616).
234
+ const decision = await resumeAiJobRequest(user, orgId, job, aiBuildCanRetry(job) ? {
235
+ retry: 'failed-items'
236
+ } : {});
192
237
  if (decision.job) setJob(decision.job);
193
238
  if (decision.error) setNotice(decision.error);
194
239
  setBusy(false);
@@ -198,8 +243,24 @@ export function AiSiteBuildPage({ hostId, segments, basePath }) {
198
243
  user,
199
244
  setJob
200
245
  ]);
246
+ const confirmPlan = useCallback(async (target, options = {})=>{
247
+ if (!orgId) return;
248
+ setBusy(true);
249
+ setNotice(null);
250
+ const decision = await resumeAiJobRequest(user, orgId, target, options);
251
+ if (decision.job) setJob(decision.job);
252
+ if (decision.error) setNotice(decision.error);
253
+ setBusy(false);
254
+ }, [
255
+ orgId,
256
+ user,
257
+ setJob
258
+ ]);
201
259
  const ready = job && typeof job === 'object' ? job : null;
202
260
  const copy = ready ? aiJobPageCopy(ready, PLATFORM_BRAND_NAME) : null;
261
+ // The active row's running time, read before any early return (a hook).
262
+ const liveRow = ready && aiSiteBuildPhase(ready) === 'working' ? (_aiSiteBuildRows_find = aiSiteBuildRows(ready).find((row)=>row.state === 'active')) != null ? _aiSiteBuildRows_find : null : null;
263
+ const elapsed = useElapsed(liveRow ? `${ready == null ? void 0 : ready.id}:${liveRow.id}` : null, liveRow == null ? void 0 : liveRow.startedAt);
203
264
  // The shell's header names the job's page as the page does, and its trail
204
265
  // walks back to the site's AI jobs.
205
266
  const record = /*#__PURE__*/ _jsx(PageHeaderRecord, {
@@ -267,6 +328,8 @@ export function AiSiteBuildPage({ hostId, segments, basePath }) {
267
328
  }
268
329
  const phase = aiSiteBuildPhase(ready);
269
330
  const rows = aiSiteBuildRows(ready);
331
+ const fraction = aiSiteBuildFraction(rows);
332
+ const activeRow = phase === 'working' ? (_rows_find = rows.find((row)=>row.state === 'active')) != null ? _rows_find : null : null;
270
333
  const credits = aiSiteBuildCreditsLine(ready);
271
334
  const links = phase === 'done' ? aiSiteBuildDoneLinks(ready, orgSlug) : {
272
335
  view: null,
@@ -275,7 +338,13 @@ export function AiSiteBuildPage({ hostId, segments, basePath }) {
275
338
  const sitePublish = ready.kind === 'site' && phase === 'done' ? (_ready_sitePublish = ready.sitePublish) != null ? _ready_sitePublish : null : null;
276
339
  const liveUrl = sitePublish && sitePublish.published.length > 0 ? sitePublish.liveUrl : null;
277
340
  const retryRefusal = (_ready_review = ready.review) == null ? void 0 : _ready_review.retryRefusal;
278
- const canRetry = phase === 'stopped' && ((_ready_review1 = ready.review) == null ? void 0 : _ready_review1.reason) === 'doctrine';
341
+ const buildRetry = aiBuildCanRetry(ready);
342
+ const canRetry = phase === 'stopped' && ((_ready_review1 = ready.review) == null ? void 0 : _ready_review1.reason) === 'doctrine' || buildRetry;
343
+ const buildPlanWaiting = ready.kind === 'build' && phase === 'stopped' && ((_ready_review2 = ready.review) == null ? void 0 : _ready_review2.reason) === 'plan';
344
+ // A guided start that ended without building its site starts over from its
345
+ // own answers, as a fresh job: the questions reopen filled in.
346
+ const restartAnswers = ready.kind === 'site' && (phase === 'failed' || phase === 'canceled') ? aiSiteStartAnswersFromInputs(ready.siteInputs) : null;
347
+ const refund = phase === 'failed' || phase === 'stopped' || phase === 'canceled' ? aiJobRefundCopy(ready) : null;
279
348
  return /*#__PURE__*/ _jsxs(Frame, {
280
349
  siteName: siteName,
281
350
  heading: copy.heading,
@@ -292,9 +361,13 @@ export function AiSiteBuildPage({ hostId, segments, basePath }) {
292
361
  borderRadius: 2
293
362
  },
294
363
  children: [
295
- phase === 'working' && /*#__PURE__*/ _jsx(LinearProgress, {
364
+ phase === 'working' && (fraction !== null ? /*#__PURE__*/ _jsx(LinearProgress, {
365
+ variant: "determinate",
366
+ value: Math.round(fraction * 100),
367
+ "aria-label": `Building: ${rows.filter((row)=>row.state === 'done').length} of ${rows.length} steps done`
368
+ }) : /*#__PURE__*/ _jsx(LinearProgress, {
296
369
  "aria-label": "Building"
297
- }),
370
+ })),
298
371
  /*#__PURE__*/ _jsx(Box, {
299
372
  component: "ol",
300
373
  "aria-label": "Progress",
@@ -308,12 +381,14 @@ export function AiSiteBuildPage({ hostId, segments, basePath }) {
308
381
  },
309
382
  children: /*#__PURE__*/ _jsx(Stack, {
310
383
  spacing: 2,
311
- children: rows.map((row)=>/*#__PURE__*/ _jsxs(Stack, {
384
+ children: rows.map((row)=>{
385
+ var _row_sections;
386
+ return /*#__PURE__*/ _jsxs(Stack, {
312
387
  component: "li",
313
388
  direction: "row",
314
389
  spacing: 2,
315
390
  sx: {
316
- alignItems: 'center'
391
+ alignItems: 'flex-start'
317
392
  },
318
393
  children: [
319
394
  /*#__PURE__*/ _jsx(Box, {
@@ -326,22 +401,89 @@ export function AiSiteBuildPage({ hostId, segments, basePath }) {
326
401
  state: row.state
327
402
  })
328
403
  }),
329
- /*#__PURE__*/ _jsx(Typography, {
330
- variant: "body1",
331
- color: row.state === 'waiting' ? 'text.secondary' : 'text.primary',
332
- children: row.label
404
+ /*#__PURE__*/ _jsxs(Box, {
405
+ sx: {
406
+ flex: 1,
407
+ minWidth: 0
408
+ },
409
+ children: [
410
+ /*#__PURE__*/ _jsxs(Stack, {
411
+ direction: "row",
412
+ spacing: 1,
413
+ sx: {
414
+ alignItems: 'baseline',
415
+ justifyContent: 'space-between'
416
+ },
417
+ children: [
418
+ /*#__PURE__*/ _jsx(Typography, {
419
+ variant: "body1",
420
+ color: row.state === 'waiting' || row.state === 'skipped' ? 'text.secondary' : 'text.primary',
421
+ children: row.label
422
+ }),
423
+ row.id === (activeRow == null ? void 0 : activeRow.id) && elapsed ? /*#__PURE__*/ _jsx(Typography, {
424
+ variant: "body2",
425
+ color: "text.secondary",
426
+ sx: {
427
+ fontVariantNumeric: 'tabular-nums'
428
+ },
429
+ children: elapsed
430
+ }) : typeof row.credits === 'number' && row.credits > 0 ? /*#__PURE__*/ _jsx(Typography, {
431
+ variant: "body2",
432
+ color: "text.secondary",
433
+ sx: {
434
+ whiteSpace: 'nowrap'
435
+ },
436
+ children: `${row.credits} ${row.credits === 1 ? 'credit' : 'credits'}`
437
+ }) : null
438
+ ]
439
+ }),
440
+ row.id === (activeRow == null ? void 0 : activeRow.id) && row.hint ? /*#__PURE__*/ _jsx(Typography, {
441
+ variant: "body2",
442
+ color: "text.secondary",
443
+ children: row.hint
444
+ }) : null,
445
+ ((_row_sections = row.sections) == null ? void 0 : _row_sections.length) && (row.state === 'active' || row.state === 'done') ? /*#__PURE__*/ _jsx(Typography, {
446
+ variant: "body2",
447
+ color: "text.secondary",
448
+ children: `${row.state === 'active' ? 'Writing' : 'Wrote'}: ${row.sections.join(', ')}`
449
+ }) : null,
450
+ row.detail ? /*#__PURE__*/ _jsx(Typography, {
451
+ variant: "body2",
452
+ color: "text.secondary",
453
+ children: row.detail
454
+ }) : null
455
+ ]
333
456
  })
334
457
  ]
335
- }, row.id))
458
+ }, row.id);
459
+ })
336
460
  })
337
461
  })
338
462
  ]
339
463
  }),
340
- credits && /*#__PURE__*/ _jsx(Typography, {
464
+ refund && ((_ready_refundedCredits = ready.refundedCredits) != null ? _ready_refundedCredits : 0) > 0 ? /*#__PURE__*/ _jsx(Alert, {
465
+ severity: "info",
466
+ children: refund
467
+ }) : credits ? /*#__PURE__*/ _jsx(Typography, {
341
468
  variant: "body2",
342
469
  color: "text.secondary",
343
470
  children: credits
344
- }),
471
+ }) : null,
472
+ retrying && restartAnswers && hostId ? /*#__PURE__*/ _jsx(AiSiteStartCard, {
473
+ hostId: hostId,
474
+ orgId: orgId != null ? orgId : undefined,
475
+ orgSlug: orgSlug,
476
+ host: hostSubdomain,
477
+ initialAnswers: restartAnswers,
478
+ startBlank: ()=>setRetrying(false),
479
+ leave: ()=>setRetrying(false)
480
+ }) : null,
481
+ buildPlanWaiting ? // A build's plan, confirmed here as in the chat (AGL-3616).
482
+ /*#__PURE__*/ _jsx(AiJobPlan, {
483
+ job: ready,
484
+ busy: busy,
485
+ onResume: (target, options)=>void confirmPlan(target, options)
486
+ }) : null,
345
487
  sitePublish && sitePublish.drafts.length > 0 && // The pages the publish left as drafts, each with its plain reason;
346
488
  // Edit your pages is where they are fixed and published.
347
489
  /*#__PURE__*/ _jsxs(Alert, {
@@ -376,6 +518,14 @@ export function AiSiteBuildPage({ hostId, segments, basePath }) {
376
518
  })
377
519
  ]
378
520
  }),
521
+ phase === 'done' && buildRetry && /*#__PURE__*/ _jsx(Box, {
522
+ children: /*#__PURE__*/ _jsx(Button, {
523
+ variant: "outlined",
524
+ disabled: busy,
525
+ onClick: ()=>void tryAgain(),
526
+ children: 'Try again what failed'
527
+ })
528
+ }),
379
529
  phase === 'done' && /*#__PURE__*/ _jsxs(Stack, {
380
530
  direction: {
381
531
  xs: 'column',
@@ -428,6 +578,11 @@ export function AiSiteBuildPage({ hostId, segments, basePath }) {
428
578
  }
429
579
  },
430
580
  children: [
581
+ restartAnswers && hostId && /*#__PURE__*/ _jsx(Button, {
582
+ variant: "contained",
583
+ onClick: ()=>setRetrying(true),
584
+ children: 'Try again'
585
+ }),
431
586
  canRetry && /*#__PURE__*/ _jsx(Button, {
432
587
  variant: "contained",
433
588
  disabled: busy || Boolean(retryRefusal),
@@ -443,6 +598,8 @@ export function AiSiteBuildPage({ hostId, segments, basePath }) {
443
598
  ]
444
599
  }),
445
600
  ready.plan && ready.plan.screens.length > 0 && /*#__PURE__*/ _jsxs(Accordion, {
601
+ // Open while the site is built, so the plan is in view as each part of it is written.
602
+ defaultExpanded: phase === 'working',
446
603
  variant: "outlined",
447
604
  disableGutters: true,
448
605
  sx: {