@aglyn/plugins-ai 1.0.0-beta.270 → 1.0.0-beta.272

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 (281) hide show
  1. package/package.json +17 -17
  2. package/src/lib/activity/ai-activity-actions.d.ts +4 -3
  3. package/src/lib/activity/ai-activity-actions.js +4 -0
  4. package/src/lib/activity/ai-activity-actions.js.map +1 -1
  5. package/src/lib/assets/site-styles/beauty.webp +0 -0
  6. package/src/lib/assets/site-styles/blog.webp +0 -0
  7. package/src/lib/assets/site-styles/business.webp +0 -0
  8. package/src/lib/assets/site-styles/coming-soon.webp +0 -0
  9. package/src/lib/assets/site-styles/education.webp +0 -0
  10. package/src/lib/assets/site-styles/events.webp +0 -0
  11. package/src/lib/assets/site-styles/fitness.webp +0 -0
  12. package/src/lib/assets/site-styles/landing.webp +0 -0
  13. package/src/lib/assets/site-styles/music.webp +0 -0
  14. package/src/lib/assets/site-styles/nonprofit.webp +0 -0
  15. package/src/lib/assets/site-styles/personal.webp +0 -0
  16. package/src/lib/assets/site-styles/photography.webp +0 -0
  17. package/src/lib/assets/site-styles/portfolio.webp +0 -0
  18. package/src/lib/assets/site-styles/professional.webp +0 -0
  19. package/src/lib/assets/site-styles/realestate.webp +0 -0
  20. package/src/lib/assets/site-styles/restaurant.webp +0 -0
  21. package/src/lib/assets/site-styles/store.webp +0 -0
  22. package/src/lib/assets/site-styles/studio.webp +0 -0
  23. package/src/lib/assets/site-styles/trades.webp +0 -0
  24. package/src/lib/assets/site-styles/wellness.webp +0 -0
  25. package/src/lib/assets/site-styles/yoga.webp +0 -0
  26. package/src/lib/components/ai-credits-card.component.d.ts +4 -3
  27. package/src/lib/components/ai-credits-card.component.js +15 -15
  28. package/src/lib/components/ai-credits-card.component.js.map +1 -1
  29. package/src/lib/components/ai-job-input-form.component.d.ts +36 -0
  30. package/src/lib/components/ai-job-input-form.component.js +100 -0
  31. package/src/lib/components/ai-job-input-form.component.js.map +1 -0
  32. package/src/lib/components/ai-job-requests.d.ts +4 -0
  33. package/src/lib/components/ai-job-requests.js +4 -0
  34. package/src/lib/components/ai-job-requests.js.map +1 -1
  35. package/src/lib/components/ai-site-build-page.component.js +18 -0
  36. package/src/lib/components/ai-site-build-page.component.js.map +1 -1
  37. package/src/lib/components/ai-site-import-job.component.d.ts +41 -0
  38. package/src/lib/components/ai-site-import-job.component.js +707 -0
  39. package/src/lib/components/ai-site-import-job.component.js.map +1 -0
  40. package/src/lib/components/ai-site-import-start.component.d.ts +64 -0
  41. package/src/lib/components/ai-site-import-start.component.js +335 -0
  42. package/src/lib/components/ai-site-import-start.component.js.map +1 -0
  43. package/src/lib/components/ai-site-ownership-proof.component.d.ts +42 -0
  44. package/src/lib/components/ai-site-ownership-proof.component.js +353 -0
  45. package/src/lib/components/ai-site-ownership-proof.component.js.map +1 -0
  46. package/src/lib/components/ai-site-start-card.component.d.ts +1 -1
  47. package/src/lib/components/ai-site-start-card.component.js +261 -119
  48. package/src/lib/components/ai-site-start-card.component.js.map +1 -1
  49. package/src/lib/components/ai-site-start-steps.component.d.ts +43 -2
  50. package/src/lib/components/ai-site-start-steps.component.js +651 -15
  51. package/src/lib/components/ai-site-start-steps.component.js.map +1 -1
  52. package/src/lib/components/ai-site-start-tracking.d.ts +10 -0
  53. package/src/lib/components/ai-site-start-tracking.js +14 -0
  54. package/src/lib/components/ai-site-start-tracking.js.map +1 -1
  55. package/src/lib/components/ai-site-style-previews.js +26 -22
  56. package/src/lib/components/ai-site-style-previews.js.map +1 -1
  57. package/src/lib/components/ai-upsell-dialog.component.d.ts +7 -5
  58. package/src/lib/components/ai-upsell-dialog.component.js +8 -6
  59. package/src/lib/components/ai-upsell-dialog.component.js.map +1 -1
  60. package/src/lib/components/assist-build-card.component.js +11 -1
  61. package/src/lib/components/assist-build-card.component.js.map +1 -1
  62. package/src/lib/components/assist-jobs-drawer.component.js +9 -1
  63. package/src/lib/components/assist-jobs-drawer.component.js.map +1 -1
  64. package/src/lib/components/assist-panel.component.js +8 -4
  65. package/src/lib/components/assist-panel.component.js.map +1 -1
  66. package/src/lib/components/staff-org-ai-card.component.js +4 -7
  67. package/src/lib/components/staff-org-ai-card.component.js.map +1 -1
  68. package/src/lib/declarations.d.ts +2 -2
  69. package/src/lib/declarations.js +9 -5
  70. package/src/lib/declarations.js.map +1 -1
  71. package/src/lib/jobs/ai-build-capabilities.js +3 -1
  72. package/src/lib/jobs/ai-build-capabilities.js.map +1 -1
  73. package/src/lib/jobs/ai-business-profile-prefill.d.ts +1 -1
  74. package/src/lib/jobs/ai-business-profile-prefill.js +14 -3
  75. package/src/lib/jobs/ai-business-profile-prefill.js.map +1 -1
  76. package/src/lib/jobs/ai-job-build-step.js +5 -3
  77. package/src/lib/jobs/ai-job-build-step.js.map +1 -1
  78. package/src/lib/jobs/ai-job-drafts.d.ts +14 -0
  79. package/src/lib/jobs/ai-job-drafts.js +24 -0
  80. package/src/lib/jobs/ai-job-drafts.js.map +1 -1
  81. package/src/lib/jobs/ai-job-form-step.d.ts +15 -1
  82. package/src/lib/jobs/ai-job-form-step.js +75 -8
  83. package/src/lib/jobs/ai-job-form-step.js.map +1 -1
  84. package/src/lib/jobs/ai-job-import-step.d.ts +136 -0
  85. package/src/lib/jobs/ai-job-import-step.js +809 -0
  86. package/src/lib/jobs/ai-job-import-step.js.map +1 -0
  87. package/src/lib/jobs/ai-job-page-language.d.ts +52 -1
  88. package/src/lib/jobs/ai-job-page-language.js +99 -5
  89. package/src/lib/jobs/ai-job-page-language.js.map +1 -1
  90. package/src/lib/jobs/ai-job-page-step.d.ts +19 -2
  91. package/src/lib/jobs/ai-job-page-step.js +42 -18
  92. package/src/lib/jobs/ai-job-page-step.js.map +1 -1
  93. package/src/lib/jobs/ai-job-plan-step.d.ts +25 -2
  94. package/src/lib/jobs/ai-job-plan-step.js +103 -29
  95. package/src/lib/jobs/ai-job-plan-step.js.map +1 -1
  96. package/src/lib/jobs/ai-job-settings-step.js +4 -3
  97. package/src/lib/jobs/ai-job-settings-step.js.map +1 -1
  98. package/src/lib/jobs/ai-job-site-datasets.d.ts +27 -0
  99. package/src/lib/jobs/ai-job-site-datasets.js +140 -14
  100. package/src/lib/jobs/ai-job-site-datasets.js.map +1 -1
  101. package/src/lib/jobs/ai-job-site-look.js +18 -5
  102. package/src/lib/jobs/ai-job-site-look.js.map +1 -1
  103. package/src/lib/jobs/ai-job-site-step.d.ts +16 -1
  104. package/src/lib/jobs/ai-job-site-step.js +95 -22
  105. package/src/lib/jobs/ai-job-site-step.js.map +1 -1
  106. package/src/lib/jobs/ai-job-text-step.d.ts +15 -1
  107. package/src/lib/jobs/ai-job-text-step.js.map +1 -1
  108. package/src/lib/jobs/ai-job-tracking-step.d.ts +14 -3
  109. package/src/lib/jobs/ai-job-tracking-step.js +28 -5
  110. package/src/lib/jobs/ai-job-tracking-step.js.map +1 -1
  111. package/src/lib/jobs/ai-jobs.d.ts +13 -1
  112. package/src/lib/jobs/ai-jobs.js +77 -10
  113. package/src/lib/jobs/ai-jobs.js.map +1 -1
  114. package/src/lib/jobs/ai-layout-owner-photos.d.ts +16 -1
  115. package/src/lib/jobs/ai-layout-owner-photos.js +47 -0
  116. package/src/lib/jobs/ai-layout-owner-photos.js.map +1 -1
  117. package/src/lib/jobs/ai-layout-stock-photos.d.ts +27 -2
  118. package/src/lib/jobs/ai-layout-stock-photos.js +190 -19
  119. package/src/lib/jobs/ai-layout-stock-photos.js.map +1 -1
  120. package/src/lib/jobs/ai-site-inspiration-signals.d.ts +98 -0
  121. package/src/lib/jobs/ai-site-inspiration-signals.js +585 -0
  122. package/src/lib/jobs/ai-site-inspiration-signals.js.map +1 -0
  123. package/src/lib/jobs/ai-site-inspiration.d.ts +157 -0
  124. package/src/lib/jobs/ai-site-inspiration.js +346 -0
  125. package/src/lib/jobs/ai-site-inspiration.js.map +1 -0
  126. package/src/lib/jobs/ai-site-publish.d.ts +26 -1
  127. package/src/lib/jobs/ai-site-publish.js +162 -13
  128. package/src/lib/jobs/ai-site-publish.js.map +1 -1
  129. package/src/lib/jobs/ai-theme-brand-inputs.d.ts +77 -3
  130. package/src/lib/jobs/ai-theme-brand-inputs.js +135 -31
  131. package/src/lib/jobs/ai-theme-brand-inputs.js.map +1 -1
  132. package/src/lib/jobs/fixtures/ai-candle-shop-free-plan-recording.d.ts +97 -0
  133. package/src/lib/jobs/fixtures/ai-candle-shop-free-plan-recording.js +137 -0
  134. package/src/lib/jobs/fixtures/ai-candle-shop-free-plan-recording.js.map +1 -0
  135. package/src/lib/jobs/fixtures/ai-site-inspiration-pages.d.ts +38 -0
  136. package/src/lib/jobs/fixtures/ai-site-inspiration-pages.js +103 -0
  137. package/src/lib/jobs/fixtures/ai-site-inspiration-pages.js.map +1 -0
  138. package/src/lib/jobs/fixtures/ai-stock-photo-agl3988-recordings.d.ts +25 -0
  139. package/src/lib/jobs/fixtures/ai-stock-photo-agl3988-recordings.js +174 -0
  140. package/src/lib/jobs/fixtures/ai-stock-photo-agl3988-recordings.js.map +1 -0
  141. package/src/lib/layout-language/ai-layout-compiler.d.ts +1 -1
  142. package/src/lib/layout-language/ai-layout-compiler.js +438 -25
  143. package/src/lib/layout-language/ai-layout-compiler.js.map +1 -1
  144. package/src/lib/layout-language/ai-layout-contact.d.ts +57 -0
  145. package/src/lib/layout-language/ai-layout-contact.js +137 -0
  146. package/src/lib/layout-language/ai-layout-contact.js.map +1 -0
  147. package/src/lib/layout-language/ai-layout-copy.d.ts +12 -0
  148. package/src/lib/layout-language/ai-layout-copy.js +34 -2
  149. package/src/lib/layout-language/ai-layout-copy.js.map +1 -1
  150. package/src/lib/layout-language/ai-layout-design.d.ts +65 -8
  151. package/src/lib/layout-language/ai-layout-design.js +411 -97
  152. package/src/lib/layout-language/ai-layout-design.js.map +1 -1
  153. package/src/lib/layout-language/ai-layout-frame.js +23 -0
  154. package/src/lib/layout-language/ai-layout-frame.js.map +1 -1
  155. package/src/lib/layout-language/ai-layout-labels.d.ts +2 -0
  156. package/src/lib/layout-language/ai-layout-labels.js +12 -6
  157. package/src/lib/layout-language/ai-layout-labels.js.map +1 -1
  158. package/src/lib/layout-language/ai-layout-language.d.ts +3 -2
  159. package/src/lib/layout-language/ai-layout-language.js +4 -3
  160. package/src/lib/layout-language/ai-layout-language.js.map +1 -1
  161. package/src/lib/layout-language/ai-layout-links.d.ts +13 -0
  162. package/src/lib/layout-language/ai-layout-links.js +30 -0
  163. package/src/lib/layout-language/ai-layout-links.js.map +1 -1
  164. package/src/lib/layout-language/ai-layout-pictures.d.ts +49 -6
  165. package/src/lib/layout-language/ai-layout-pictures.js +145 -22
  166. package/src/lib/layout-language/ai-layout-pictures.js.map +1 -1
  167. package/src/lib/model/ai-build-job.d.ts +16 -1
  168. package/src/lib/model/ai-build-job.js +40 -0
  169. package/src/lib/model/ai-build-job.js.map +1 -1
  170. package/src/lib/model/ai-credit-estimate.d.ts +20 -0
  171. package/src/lib/model/ai-credit-estimate.js +13 -0
  172. package/src/lib/model/ai-credit-estimate.js.map +1 -1
  173. package/src/lib/model/ai-job-activity.d.ts +2 -2
  174. package/src/lib/model/ai-job-activity.js +6 -4
  175. package/src/lib/model/ai-job-activity.js.map +1 -1
  176. package/src/lib/model/ai-job-input.d.ts +33 -0
  177. package/src/lib/model/ai-job-input.js +59 -0
  178. package/src/lib/model/ai-job-input.js.map +1 -0
  179. package/src/lib/model/ai-job-notice.d.ts +4 -0
  180. package/src/lib/model/ai-job-notice.js +28 -4
  181. package/src/lib/model/ai-job-notice.js.map +1 -1
  182. package/src/lib/model/ai-jobs.types.d.ts +69 -3
  183. package/src/lib/model/ai-jobs.types.js +2 -1
  184. package/src/lib/model/ai-jobs.types.js.map +1 -1
  185. package/src/lib/model/ai-site-details.d.ts +122 -0
  186. package/src/lib/model/ai-site-details.js +300 -0
  187. package/src/lib/model/ai-site-details.js.map +1 -0
  188. package/src/lib/model/ai-site-entity.d.ts +181 -0
  189. package/src/lib/model/ai-site-entity.js +390 -0
  190. package/src/lib/model/ai-site-entity.js.map +1 -0
  191. package/src/lib/model/ai-site-import-view.d.ts +130 -0
  192. package/src/lib/model/ai-site-import-view.js +182 -0
  193. package/src/lib/model/ai-site-import-view.js.map +1 -0
  194. package/src/lib/model/ai-site-import.d.ts +302 -0
  195. package/src/lib/model/ai-site-import.js +526 -0
  196. package/src/lib/model/ai-site-import.js.map +1 -0
  197. package/src/lib/model/ai-site-inspiration.d.ts +72 -0
  198. package/src/lib/model/ai-site-inspiration.js +109 -0
  199. package/src/lib/model/ai-site-inspiration.js.map +1 -0
  200. package/src/lib/model/ai-site-job.d.ts +13 -1
  201. package/src/lib/model/ai-site-job.js +15 -2
  202. package/src/lib/model/ai-site-job.js.map +1 -1
  203. package/src/lib/model/ai-site-kinds.js +109 -21
  204. package/src/lib/model/ai-site-kinds.js.map +1 -1
  205. package/src/lib/model/ai-site-look.d.ts +10 -0
  206. package/src/lib/model/ai-site-look.js +24 -0
  207. package/src/lib/model/ai-site-look.js.map +1 -1
  208. package/src/lib/model/ai-site-start-seo.d.ts +19 -5
  209. package/src/lib/model/ai-site-start-seo.js +25 -7
  210. package/src/lib/model/ai-site-start-seo.js.map +1 -1
  211. package/src/lib/model/ai-site-start-steps.d.ts +9 -3
  212. package/src/lib/model/ai-site-start-steps.js +67 -5
  213. package/src/lib/model/ai-site-start-steps.js.map +1 -1
  214. package/src/lib/model/ai-site-start.d.ts +81 -4
  215. package/src/lib/model/ai-site-start.js +207 -13
  216. package/src/lib/model/ai-site-start.js.map +1 -1
  217. package/src/lib/model/ai-upsell-copy.js +4 -1
  218. package/src/lib/model/ai-upsell-copy.js.map +1 -1
  219. package/src/lib/plan-entitlements.d.ts +4 -3
  220. package/src/lib/plan-entitlements.js +3 -8
  221. package/src/lib/plan-entitlements.js.map +1 -1
  222. package/src/lib/runtime/ai-dataset-generation.d.ts +8 -1
  223. package/src/lib/runtime/ai-dataset-generation.js +12 -2
  224. package/src/lib/runtime/ai-dataset-generation.js.map +1 -1
  225. package/src/lib/runtime/ai-doctrine-validators.d.ts +26 -33
  226. package/src/lib/runtime/ai-doctrine-validators.js +54 -44
  227. package/src/lib/runtime/ai-doctrine-validators.js.map +1 -1
  228. package/src/lib/runtime/ai-doctrine.js +1 -1
  229. package/src/lib/runtime/ai-doctrine.js.map +1 -1
  230. package/src/lib/runtime/ai-node-tree.d.ts +7 -0
  231. package/src/lib/runtime/ai-node-tree.js +9 -1
  232. package/src/lib/runtime/ai-node-tree.js.map +1 -1
  233. package/src/lib/server/ai-create-route.d.ts +1 -1
  234. package/src/lib/server/ai-create-route.js +3 -4
  235. package/src/lib/server/ai-create-route.js.map +1 -1
  236. package/src/lib/server/ai-jobs-resume.js +27 -3
  237. package/src/lib/server/ai-jobs-resume.js.map +1 -1
  238. package/src/lib/server/ai-jobs-route.js +18 -0
  239. package/src/lib/server/ai-jobs-route.js.map +1 -1
  240. package/src/lib/server/ai-site-import-route.d.ts +89 -0
  241. package/src/lib/server/ai-site-import-route.js +356 -0
  242. package/src/lib/server/ai-site-import-route.js.map +1 -0
  243. package/src/lib/server.js +14 -0
  244. package/src/lib/server.js.map +1 -1
  245. package/src/lib/site-import/fixtures/site-import-crawl-recordings.d.ts +45 -0
  246. package/src/lib/site-import/fixtures/site-import-crawl-recordings.js +313 -0
  247. package/src/lib/site-import/fixtures/site-import-crawl-recordings.js.map +1 -0
  248. package/src/lib/site-import/fixtures/site-import-wave-recordings.d.ts +50 -0
  249. package/src/lib/site-import/fixtures/site-import-wave-recordings.js +217 -0
  250. package/src/lib/site-import/fixtures/site-import-wave-recordings.js.map +1 -0
  251. package/src/lib/site-import/site-import-crawl.d.ts +163 -0
  252. package/src/lib/site-import/site-import-crawl.js +467 -0
  253. package/src/lib/site-import/site-import-crawl.js.map +1 -0
  254. package/src/lib/site-import/site-import-flag.d.ts +23 -0
  255. package/src/lib/site-import/site-import-flag.js +23 -0
  256. package/src/lib/site-import/site-import-flag.js.map +1 -0
  257. package/src/lib/site-import/site-import-html.d.ts +94 -0
  258. package/src/lib/site-import/site-import-html.js +462 -0
  259. package/src/lib/site-import/site-import-html.js.map +1 -0
  260. package/src/lib/site-import/site-import-images.d.ts +54 -0
  261. package/src/lib/site-import/site-import-images.js +204 -0
  262. package/src/lib/site-import/site-import-images.js.map +1 -0
  263. package/src/lib/site-import/site-import-page.d.ts +48 -0
  264. package/src/lib/site-import/site-import-page.js +150 -0
  265. package/src/lib/site-import/site-import-page.js.map +1 -0
  266. package/src/lib/site-import/site-import-review.d.ts +40 -0
  267. package/src/lib/site-import/site-import-review.js +149 -0
  268. package/src/lib/site-import/site-import-review.js.map +1 -0
  269. package/src/lib/site-import/site-import-robots.d.ts +52 -0
  270. package/src/lib/site-import/site-import-robots.js +126 -0
  271. package/src/lib/site-import/site-import-robots.js.map +1 -0
  272. package/src/lib/usage/assist-credits.d.ts +4 -4
  273. package/src/lib/usage/assist-credits.js +4 -4
  274. package/src/lib/usage/assist-credits.js.map +1 -1
  275. package/src/lib/usage/staff-org-ai-view.js +6 -3
  276. package/src/lib/usage/staff-org-ai-view.js.map +1 -1
  277. package/src/lib/usage/staff-org-ai.d.ts +4 -2
  278. package/src/lib/usage/staff-org-ai.js +7 -7
  279. package/src/lib/usage/staff-org-ai.js.map +1 -1
  280. package/src/lib/usage/staff-org-usage-ai.js +2 -2
  281. package/src/lib/usage/staff-org-usage-ai.js.map +1 -1
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../../../libs/plugins/ai/src/lib/components/ai-upsell-dialog.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 { aiAddonName } from '@aglyn/aglyn'\nimport { trackEvent } from '@aglyn/aglyn/app-utils/analytics-events'\nimport type { ConsoleWidgetUpgrade } from '@aglyn/aglyn/plugin-manager/feature-plugins'\nimport { mdiCreation } from '@aglyn/shared-data-mdi'\nimport { pluginDocsHelp } from '@aglyn/aglyn/app-utils/docs-help'\nimport { HelpTip, MdiIcon } from '@aglyn/shared-ui-jsx'\nimport {\n Button,\n Dialog,\n DialogActions,\n DialogContent,\n DialogTitle,\n Stack,\n Typography,\n} from '@mui/material'\nimport { useEffect, useState, type ReactNode } from 'react'\nimport {\n AI_UPSELL_COPY,\n AI_UPSELL_CREATE_LABEL,\n aiUpsellLabel,\n aiUpsellOffer,\n type AiUpsellKind,\n} from '../model/ai-upsell-copy'\n\n/**\n * \"Create with AI\" on a plan that could buy the AI add-on and has not\n * (AGL-3601). The shell mounts the entry with `entitled={false}` only where\n * the add-on is sold to this workspace, and the jobs route has said the plan\n * is the one thing missing; the entry then keeps its place on the page and\n * opens this instead of the brief, so the reader sees where the add-on is used.\n */\n\n// The entries' words are the model's, which the native apps' door reads too\n// (AGL-3854); re-exported for this dialog's existing readers.\nexport { AI_UPSELL_COPY, AI_UPSELL_CREATE_LABEL, aiUpsellLabel, aiUpsellOffer }\nexport type { AiUpsellCopy, AiUpsellKind } from '../model/ai-upsell-copy'\n\nexport interface AiUpsellDialogProps {\n kind: AiUpsellKind\n open: boolean\n onClose: () => void\n upgrade: ConsoleWidgetUpgrade\n}\n\n/** The add-on's own section of the Create with AI guide (AGL-3660). */\nconst aiUpsellHelp = () =>\n pluginDocsHelp('aiCreate', {\n anchor: '#without-the-add-on',\n excerpt: `Create with AI needs the ${aiAddonName()} add-on on a paid plan. An owner or admin adds it from Billing; on Free, the monthly AI credits cover it.`,\n })\n\nexport function AiUpsellDialog({ kind, open, onClose, upgrade }: AiUpsellDialogProps) {\n const copy = AI_UPSELL_COPY[kind]\n const { canManageBilling, billingHref } = upgrade\n\n // Counted once per opening: the denominator the click is a rate against.\n useEffect(() => {\n if (open) trackEvent('ai_upsell_shown', { kind, can_manage: canManageBilling })\n }, [open, kind, canManageBilling])\n\n return (\n <Dialog open={open} onClose={onClose} fullWidth maxWidth=\"xs\">\n <DialogTitle sx={{ display: 'flex', alignItems: 'center', gap: 0.5 }}>\n {copy.title}\n <HelpTip {...aiUpsellHelp()} />\n </DialogTitle>\n <DialogContent>\n <Stack spacing={2}>\n <Typography variant=\"body2\">{copy.does}</Typography>\n <Typography variant=\"body2\" color=\"text.secondary\">\n {aiUpsellOffer(canManageBilling, kind === 'insight' ? copy.title : AI_UPSELL_CREATE_LABEL)}\n </Typography>\n </Stack>\n </DialogContent>\n <DialogActions>\n <Button onClick={onClose}>{canManageBilling ? 'Not now' : 'Close'}</Button>\n {canManageBilling ? (\n <Button\n variant=\"contained\"\n href={billingHref}\n onClick={() => trackEvent('ai_upsell_clicked', { kind })}\n >\n {`Add ${aiAddonName()}`}\n </Button>\n ) : null}\n </DialogActions>\n </Dialog>\n )\n}\n\n/**\n * The entry itself on a plan without the add-on: the same button, label and\n * icon as the entitled entry, opening {@link AiUpsellDialog}. Every entry that\n * draws it renders from the shell's client-side gates alone and asks the\n * server nothing until it is used (AGL-3601).\n */\nexport function AiUpsellButton({\n kind,\n upgrade,\n label,\n}: {\n kind: AiUpsellKind\n upgrade: ConsoleWidgetUpgrade\n /** The entitled entry's own label, when it is not the kind's. */\n label?: string\n}): ReactNode {\n const [open, setOpen] = useState(false)\n return (\n <>\n <Button\n size=\"small\"\n variant=\"outlined\"\n startIcon={<MdiIcon path={mdiCreation.path} />}\n onClick={() => setOpen(true)}\n >\n {label ?? aiUpsellLabel(kind)}\n </Button>\n <AiUpsellDialog kind={kind} open={open} onClose={() => setOpen(false)} upgrade={upgrade} />\n </>\n )\n}\n"],"names":["aiAddonName","trackEvent","mdiCreation","pluginDocsHelp","HelpTip","MdiIcon","Button","Dialog","DialogActions","DialogContent","DialogTitle","Stack","Typography","useEffect","useState","AI_UPSELL_COPY","AI_UPSELL_CREATE_LABEL","aiUpsellLabel","aiUpsellOffer","aiUpsellHelp","anchor","excerpt","AiUpsellDialog","kind","open","onClose","upgrade","copy","canManageBilling","billingHref","can_manage","fullWidth","maxWidth","sx","display","alignItems","gap","title","spacing","variant","does","color","onClick","href","AiUpsellButton","label","setOpen","size","startIcon","path"],"mappings":"AAAA;;;AAEA;;;;;;;;;;;;;;;CAeC,GAED,SAASA,WAAW,QAAQ,eAAc;AAC1C,SAASC,UAAU,QAAQ,0CAAyC;AAEpE,SAASC,WAAW,QAAQ,yBAAwB;AACpD,SAASC,cAAc,QAAQ,mCAAkC;AACjE,SAASC,OAAO,EAAEC,OAAO,QAAQ,uBAAsB;AACvD,SACEC,MAAM,EACNC,MAAM,EACNC,aAAa,EACbC,aAAa,EACbC,WAAW,EACXC,KAAK,EACLC,UAAU,QACL,gBAAe;AACtB,SAASC,SAAS,EAAEC,QAAQ,QAAwB,QAAO;AAC3D,SACEC,cAAc,EACdC,sBAAsB,EACtBC,aAAa,EACbC,aAAa,QAER,6BAAyB;AAEhC;;;;;;CAMC,GAED,4EAA4E;AAC5E,8DAA8D;AAC9D,SAASH,cAAc,EAAEC,sBAAsB,EAAEC,aAAa,EAAEC,aAAa,GAAE;AAU/E,qEAAqE,GACrE,MAAMC,eAAe,IACnBhB,eAAe,YAAY;QACzBiB,QAAQ;QACRC,SAAS,CAAC,yBAAyB,EAAErB,cAAc,yGAAyG,CAAC;IAC/J;AAEF,OAAO,SAASsB,eAAe,EAAEC,IAAI,EAAEC,IAAI,EAAEC,OAAO,EAAEC,OAAO,EAAuB;IAClF,MAAMC,OAAOZ,cAAc,CAACQ,KAAK;IACjC,MAAM,EAAEK,gBAAgB,EAAEC,WAAW,EAAE,GAAGH;IAE1C,yEAAyE;IACzEb,UAAU;QACR,IAAIW,MAAMvB,WAAW,mBAAmB;YAAEsB;YAAMO,YAAYF;QAAiB;IAC/E,GAAG;QAACJ;QAAMD;QAAMK;KAAiB;IAEjC,qBACE,MAACrB;QAAOiB,MAAMA;QAAMC,SAASA;QAASM,SAAS;QAACC,UAAS;;0BACvD,MAACtB;gBAAYuB,IAAI;oBAAEC,SAAS;oBAAQC,YAAY;oBAAUC,KAAK;gBAAI;;oBAChET,KAAKU,KAAK;kCACX,KAACjC,sBAAYe;;;0BAEf,KAACV;0BACC,cAAA,MAACE;oBAAM2B,SAAS;;sCACd,KAAC1B;4BAAW2B,SAAQ;sCAASZ,KAAKa,IAAI;;sCACtC,KAAC5B;4BAAW2B,SAAQ;4BAAQE,OAAM;sCAC/BvB,cAAcU,kBAAkBL,SAAS,YAAYI,KAAKU,KAAK,GAAGrB;;;;;0BAIzE,MAACR;;kCACC,KAACF;wBAAOoC,SAASjB;kCAAUG,mBAAmB,YAAY;;oBACzDA,iCACC,KAACtB;wBACCiC,SAAQ;wBACRI,MAAMd;wBACNa,SAAS,IAAMzC,WAAW,qBAAqB;gCAAEsB;4BAAK;kCAErD,CAAC,IAAI,EAAEvB,eAAe;yBAEvB;;;;;AAIZ;AAEA;;;;;CAKC,GACD,OAAO,SAAS4C,eAAe,EAC7BrB,IAAI,EACJG,OAAO,EACPmB,KAAK,EAMN;IACC,MAAM,CAACrB,MAAMsB,QAAQ,GAAGhC,SAAS;IACjC,qBACE;;0BACE,KAACR;gBACCyC,MAAK;gBACLR,SAAQ;gBACRS,yBAAW,KAAC3C;oBAAQ4C,MAAM/C,YAAY+C,IAAI;;gBAC1CP,SAAS,IAAMI,QAAQ;0BAEtBD,gBAAAA,QAAS5B,cAAcM;;0BAE1B,KAACD;gBAAeC,MAAMA;gBAAMC,MAAMA;gBAAMC,SAAS,IAAMqB,QAAQ;gBAAQpB,SAASA;;;;AAGtF"}
1
+ {"version":3,"sources":["../../../../../../../libs/plugins/ai/src/lib/components/ai-upsell-dialog.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 { aiAddonName } from '@aglyn/aglyn'\nimport { trackEvent } from '@aglyn/aglyn/app-utils/analytics-events'\nimport type { ConsoleWidgetUpgrade } from '@aglyn/aglyn/plugin-manager/feature-plugins'\nimport { mdiCreation } from '@aglyn/shared-data-mdi'\nimport { pluginDocsHelp } from '@aglyn/aglyn/app-utils/docs-help'\nimport { HelpTip, MdiIcon } from '@aglyn/shared-ui-jsx'\nimport {\n Button,\n Dialog,\n DialogActions,\n DialogContent,\n DialogTitle,\n Stack,\n Typography,\n} from '@mui/material'\nimport { useEffect, useState, type ReactNode } from 'react'\nimport {\n AI_UPSELL_COPY,\n AI_UPSELL_CREATE_LABEL,\n aiUpsellLabel,\n aiUpsellOffer,\n type AiUpsellKind,\n} from '../model/ai-upsell-copy'\n\n/**\n * \"Create with AI\" where generation is switched off for a workspace that\n * could buy an Aglyn AI tier (AGL-3601, AGL-3965). Since AGL-3965 every paid\n * plan's own credits pay for generation, so this is reached only where a\n * per-org setting closed it. The shell mounts the entry with\n * `entitled={false}` only where a tier is sold to this workspace, and the\n * jobs route has said that is the one thing missing; the entry then keeps its\n * place on the page and opens this instead of the brief.\n */\n\n// The entries' words are the model's, which the native apps' door reads too\n// (AGL-3854); re-exported for this dialog's existing readers.\nexport { AI_UPSELL_COPY, AI_UPSELL_CREATE_LABEL, aiUpsellLabel, aiUpsellOffer }\nexport type { AiUpsellCopy, AiUpsellKind } from '../model/ai-upsell-copy'\n\nexport interface AiUpsellDialogProps {\n kind: AiUpsellKind\n open: boolean\n onClose: () => void\n upgrade: ConsoleWidgetUpgrade\n}\n\n/** The add-on's own section of the Create with AI guide (AGL-3660). */\nconst aiUpsellHelp = () =>\n pluginDocsHelp('aiCreate', {\n anchor: '#without-the-add-on',\n excerpt: `On every paid plan, Create with AI runs on the AI credits the plan includes. Where it is switched off for a workspace, an ${aiAddonName()} tier switches it on; an owner or admin chooses one in Billing.`,\n })\n\nexport function AiUpsellDialog({ kind, open, onClose, upgrade }: AiUpsellDialogProps) {\n const copy = AI_UPSELL_COPY[kind]\n const { canManageBilling, billingHref } = upgrade\n\n // Counted once per opening: the denominator the click is a rate against.\n useEffect(() => {\n if (open) trackEvent('ai_upsell_shown', { kind, can_manage: canManageBilling })\n }, [open, kind, canManageBilling])\n\n return (\n <Dialog open={open} onClose={onClose} fullWidth maxWidth=\"xs\">\n <DialogTitle sx={{ display: 'flex', alignItems: 'center', gap: 0.5 }}>\n {copy.title}\n <HelpTip {...aiUpsellHelp()} />\n </DialogTitle>\n <DialogContent>\n <Stack spacing={2}>\n <Typography variant=\"body2\">{copy.does}</Typography>\n <Typography variant=\"body2\" color=\"text.secondary\">\n {aiUpsellOffer(canManageBilling, kind === 'insight' ? copy.title : AI_UPSELL_CREATE_LABEL)}\n </Typography>\n </Stack>\n </DialogContent>\n <DialogActions>\n <Button onClick={onClose}>{canManageBilling ? 'Not now' : 'Close'}</Button>\n {canManageBilling ? (\n <Button\n variant=\"contained\"\n href={billingHref}\n onClick={() => trackEvent('ai_upsell_clicked', { kind })}\n >\n {`Add ${aiAddonName()}`}\n </Button>\n ) : null}\n </DialogActions>\n </Dialog>\n )\n}\n\n/**\n * The entry itself on a plan without the add-on: the same button, label and\n * icon as the entitled entry, opening {@link AiUpsellDialog}. Every entry that\n * draws it renders from the shell's client-side gates alone and asks the\n * server nothing until it is used (AGL-3601).\n */\nexport function AiUpsellButton({\n kind,\n upgrade,\n label,\n}: {\n kind: AiUpsellKind\n upgrade: ConsoleWidgetUpgrade\n /** The entitled entry's own label, when it is not the kind's. */\n label?: string\n}): ReactNode {\n const [open, setOpen] = useState(false)\n return (\n <>\n <Button\n size=\"small\"\n variant=\"outlined\"\n startIcon={<MdiIcon path={mdiCreation.path} />}\n onClick={() => setOpen(true)}\n >\n {label ?? aiUpsellLabel(kind)}\n </Button>\n <AiUpsellDialog kind={kind} open={open} onClose={() => setOpen(false)} upgrade={upgrade} />\n </>\n )\n}\n"],"names":["aiAddonName","trackEvent","mdiCreation","pluginDocsHelp","HelpTip","MdiIcon","Button","Dialog","DialogActions","DialogContent","DialogTitle","Stack","Typography","useEffect","useState","AI_UPSELL_COPY","AI_UPSELL_CREATE_LABEL","aiUpsellLabel","aiUpsellOffer","aiUpsellHelp","anchor","excerpt","AiUpsellDialog","kind","open","onClose","upgrade","copy","canManageBilling","billingHref","can_manage","fullWidth","maxWidth","sx","display","alignItems","gap","title","spacing","variant","does","color","onClick","href","AiUpsellButton","label","setOpen","size","startIcon","path"],"mappings":"AAAA;;;AAEA;;;;;;;;;;;;;;;CAeC,GAED,SAASA,WAAW,QAAQ,eAAc;AAC1C,SAASC,UAAU,QAAQ,0CAAyC;AAEpE,SAASC,WAAW,QAAQ,yBAAwB;AACpD,SAASC,cAAc,QAAQ,mCAAkC;AACjE,SAASC,OAAO,EAAEC,OAAO,QAAQ,uBAAsB;AACvD,SACEC,MAAM,EACNC,MAAM,EACNC,aAAa,EACbC,aAAa,EACbC,WAAW,EACXC,KAAK,EACLC,UAAU,QACL,gBAAe;AACtB,SAASC,SAAS,EAAEC,QAAQ,QAAwB,QAAO;AAC3D,SACEC,cAAc,EACdC,sBAAsB,EACtBC,aAAa,EACbC,aAAa,QAER,6BAAyB;AAEhC;;;;;;;;CAQC,GAED,4EAA4E;AAC5E,8DAA8D;AAC9D,SAASH,cAAc,EAAEC,sBAAsB,EAAEC,aAAa,EAAEC,aAAa,GAAE;AAU/E,qEAAqE,GACrE,MAAMC,eAAe,IACnBhB,eAAe,YAAY;QACzBiB,QAAQ;QACRC,SAAS,CAAC,0HAA0H,EAAErB,cAAc,+DAA+D,CAAC;IACtN;AAEF,OAAO,SAASsB,eAAe,EAAEC,IAAI,EAAEC,IAAI,EAAEC,OAAO,EAAEC,OAAO,EAAuB;IAClF,MAAMC,OAAOZ,cAAc,CAACQ,KAAK;IACjC,MAAM,EAAEK,gBAAgB,EAAEC,WAAW,EAAE,GAAGH;IAE1C,yEAAyE;IACzEb,UAAU;QACR,IAAIW,MAAMvB,WAAW,mBAAmB;YAAEsB;YAAMO,YAAYF;QAAiB;IAC/E,GAAG;QAACJ;QAAMD;QAAMK;KAAiB;IAEjC,qBACE,MAACrB;QAAOiB,MAAMA;QAAMC,SAASA;QAASM,SAAS;QAACC,UAAS;;0BACvD,MAACtB;gBAAYuB,IAAI;oBAAEC,SAAS;oBAAQC,YAAY;oBAAUC,KAAK;gBAAI;;oBAChET,KAAKU,KAAK;kCACX,KAACjC,sBAAYe;;;0BAEf,KAACV;0BACC,cAAA,MAACE;oBAAM2B,SAAS;;sCACd,KAAC1B;4BAAW2B,SAAQ;sCAASZ,KAAKa,IAAI;;sCACtC,KAAC5B;4BAAW2B,SAAQ;4BAAQE,OAAM;sCAC/BvB,cAAcU,kBAAkBL,SAAS,YAAYI,KAAKU,KAAK,GAAGrB;;;;;0BAIzE,MAACR;;kCACC,KAACF;wBAAOoC,SAASjB;kCAAUG,mBAAmB,YAAY;;oBACzDA,iCACC,KAACtB;wBACCiC,SAAQ;wBACRI,MAAMd;wBACNa,SAAS,IAAMzC,WAAW,qBAAqB;gCAAEsB;4BAAK;kCAErD,CAAC,IAAI,EAAEvB,eAAe;yBAEvB;;;;;AAIZ;AAEA;;;;;CAKC,GACD,OAAO,SAAS4C,eAAe,EAC7BrB,IAAI,EACJG,OAAO,EACPmB,KAAK,EAMN;IACC,MAAM,CAACrB,MAAMsB,QAAQ,GAAGhC,SAAS;IACjC,qBACE;;0BACE,KAACR;gBACCyC,MAAK;gBACLR,SAAQ;gBACRS,yBAAW,KAAC3C;oBAAQ4C,MAAM/C,YAAY+C,IAAI;;gBAC1CP,SAAS,IAAMI,QAAQ;0BAEtBD,gBAAAA,QAAS5B,cAAcM;;0BAE1B,KAACD;gBAAeC,MAAMA;gBAAMC,MAAMA;gBAAMC,SAAS,IAAMqB,QAAQ;gBAAQpB,SAASA;;;;AAGtF"}
@@ -27,6 +27,7 @@ import { aiCreditsBillingHref, aiStoreFinishHostId, aiStoreFinishLinks } from ".
27
27
  import { AiStoreFinishCard } from "./ai-store-finish-card.component.js";
28
28
  import { AI_JOB_TERMINAL_STATUSES } from "../model/ai-jobs.types.js";
29
29
  import { followAiJobEvents } from "./ai-job-events.js";
30
+ import { AiJobInputForm } from "./ai-job-input-form.component.js";
30
31
  import { AiJobPlan } from "./ai-job-plan.component.js";
31
32
  import { resumeAiJobRequest } from "./ai-job-requests.js";
32
33
  import { openAiJobs } from "./ai-jobs-store.js";
@@ -177,7 +178,16 @@ export function AssistBuildCard({ proposal, job, notice, orgId, user, staff = fa
177
178
  ]
178
179
  }, row.slot))
179
180
  }),
180
- job && paused && // Out of credits mid-build (AGL-3722): paused, never failed. What is
181
+ job && paused && job.input ? // A plan that needs an ID only the person has (AGL-3978): asked here,
182
+ // and answered back onto the plan card.
183
+ /*#__PURE__*/ _jsx(AiJobInputForm, {
184
+ job: _extends({}, job, {
185
+ input: job.input
186
+ }),
187
+ orgId: orgId,
188
+ user: user,
189
+ onJob: onJob
190
+ }) : job && paused && // Out of credits mid-build (AGL-3722): paused, never failed. What is
181
191
  // built is kept, and Resume carries on from the next item.
182
192
  /*#__PURE__*/ _jsx(Alert, {
183
193
  severity: "warning",
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../../../libs/plugins/ai/src/lib/components/assist-build-card.component.tsx"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n'use client'\n\nimport type { MaybeTokenSource } from '@aglyn/shared-util-http/authorized-token'\nimport { pluginDocsHelp } from '@aglyn/aglyn/app-utils/docs-help'\nimport { HelpTip } from '@aglyn/shared-ui-jsx'\nimport { Alert, Box, Button, CircularProgress, Paper, Stack, Typography } from '@mui/material'\nimport { useEffect, useRef, useState } from 'react'\nimport { aiBuildCanRetry, aiBuildItemRows, aiBuildOutcomeLine, aiBuildRetryCreditRange } from '../model/ai-build-progress'\nimport { aiCreditRangeText, type AiCreditsPrompt } from '../model/ai-credit-estimate'\nimport { AiCreditsPromptNotice } from './ai-credits-prompt.component'\nimport { aiCreditsBillingHref, aiStoreFinishHostId, aiStoreFinishLinks } from './ai-job-links'\nimport { AiStoreFinishCard } from './ai-store-finish-card.component'\nimport { AI_JOB_TERMINAL_STATUSES, type AiJobSummary } from '../model/ai-jobs.types'\nimport type { AssistBuildProposal } from '../model/assist-build'\nimport { followAiJobEvents } from './ai-job-events'\nimport { AiJobPlan } from './ai-job-plan.component'\nimport { resumeAiJobRequest, type AiJobResumeOptions } from './ai-job-requests'\nimport { openAiJobs } from './ai-jobs-store'\n\n/**\n * The one card a build proposed in the chat becomes (AGL-3616): while its\n * job plans, a line saying so; then the job's own plan card, with its one\n * price and Confirm — the same `AiJobPlan` the AI jobs drawer shows, so\n * confirming here and there is one door; then where the build stands, item\n * by item, with AI jobs a click away. The job itself is started by the\n * panel, once, when the turn that proposed it ends; this card only follows\n * it, so re-rendering a stored thread never starts a second build.\n */\nexport interface AssistBuildCardProps {\n proposal: AssistBuildProposal\n /** The job the proposal started, as last seen; `null` while it is being created. */\n job: AiJobSummary | null\n /** Why the job could not be created or confirmed, when it could not. */\n notice: string | null\n orgId: string\n user: MaybeTokenSource\n staff?: boolean\n /** The job as it moved, for the thread to keep. */\n onJob: (job: AiJobSummary) => void\n onNotice: (notice: string | null) => void\n /** The workspace's path slug, for Upgrade on a Free build past what is left or paused (AGL-3722). */\n orgSlug?: string | null\n}\n\n/** The card's own section of the Assist builds guide (AGL-3660). */\nconst ASSIST_BUILD_HELP = pluginDocsHelp('aiAssistBuilds', {\n anchor: '#the-plan-card',\n excerpt:\n 'What one request will build, item by item, with its estimate. Nothing is built until you choose Confirm plan, and what it makes is a draft.',\n})\n\nconst ITEM_STATES = { done: 'built', active: 'building', waiting: 'waiting', failed: 'failed', skipped: 'not built' } as const\n\nexport function AssistBuildCard({\n proposal,\n job,\n notice,\n orgId,\n user,\n staff = false,\n onJob,\n onNotice,\n orgSlug,\n}: AssistBuildCardProps): JSX.Element {\n const [busy, setBusy] = useState(false)\n // A Free Try again past what is left (AGL-3722): its prompt, until chosen.\n const [retryPrompt, setRetryPrompt] = useState<AiCreditsPrompt | null>(null)\n const userRef = useRef(user)\n userRef.current = user\n const onJobRef = useRef(onJob)\n onJobRef.current = onJob\n\n // Follow a job that is still planning or building; a plan waiting for its\n // confirmation and a settled job need nothing more from the stream.\n // A build the meter paused (AGL-3722) waits for Resume, not the stream.\n const paused = job?.status === 'needs_input'\n const following = Boolean(\n job && !AI_JOB_TERMINAL_STATUSES.includes(job.status) && job.status !== 'needs_review' && !paused,\n )\n const jobId = job?.id ?? null\n useEffect(() => {\n if (!following || !jobId) return\n const controller = new AbortController()\n void followAiJobEvents(() => userRef.current, orgId, jobId, controller.signal, (next) => onJobRef.current(next))\n return () => controller.abort()\n }, [following, jobId, orgId])\n\n const resume = async (target: AiJobSummary, options?: AiJobResumeOptions) => {\n setBusy(true)\n onNotice(null)\n setRetryPrompt(null)\n const decision = await resumeAiJobRequest(user, orgId, target, options)\n if (decision.job) onJob(decision.job)\n // A Free Try again past what is left asks with its choices; a plan's\n // card draws its own from the job the door answered with.\n if (decision.credits && options?.retry) setRetryPrompt(decision.credits)\n else if (decision.error && !(decision.credits && target.status === 'needs_review')) onNotice(decision.error)\n setBusy(false)\n }\n const retryRange = job && aiBuildCanRetry(job) ? aiBuildRetryCreditRange(job) : null\n\n const settled = job ? AI_JOB_TERMINAL_STATUSES.includes(job.status) : false\n const outcome = job ? aiBuildOutcomeLine(job) : null\n // A build that made the site a store (AGL-3676) ends with what is left before it sells.\n const storeFinish = job && orgSlug ? aiStoreFinishLinks(job, orgSlug) : null\n return (\n <Paper variant=\"outlined\" sx={{ mt: 1, p: 1.5 }} aria-label=\"Build plan\">\n <Stack direction=\"row\" spacing={0.5} sx={{ alignItems: 'center' }}>\n <Typography variant=\"subtitle2\">{proposal.summary}</Typography>\n <HelpTip {...ASSIST_BUILD_HELP} />\n </Stack>\n {!job && !notice && (\n <Stack direction=\"row\" spacing={1} sx={{ mt: 0.5, alignItems: 'center' }}>\n <CircularProgress size={14} />\n <Typography variant=\"body2\" color=\"text.secondary\">\n {'Planning what to build on this site…'}\n </Typography>\n </Stack>\n )}\n {notice && (\n <Typography variant=\"body2\" color=\"error\" sx={{ mt: 0.5 }} role=\"alert\">\n {notice}\n </Typography>\n )}\n {job && job.status === 'needs_review' && (\n <AiJobPlan\n job={job}\n busy={busy}\n staff={staff}\n user={user}\n orgSlug={orgSlug}\n onResume={(target, options) => void resume(target, options)}\n />\n )}\n {job && following && (\n <Stack direction=\"row\" spacing={1} sx={{ mt: 0.5, alignItems: 'center' }}>\n <CircularProgress size={14} />\n <Typography variant=\"body2\" color=\"text.secondary\">\n {job.plan?.status === 'confirmed'\n ? 'Building each part in turn. What it makes is an unpublished draft unless you chose to publish.'\n : 'Planning what to build on this site…'}\n </Typography>\n </Stack>\n )}\n {job && (job.items?.length ?? 0) > 0 && job.status !== 'needs_review' && (\n <Box component=\"ul\" aria-label=\"Items\" sx={{ m: 0, mt: 0.5, pl: 2 }}>\n {aiBuildItemRows(job).map((row) => (\n <Typography key={row.slot} component=\"li\" variant=\"caption\" data-item-state={row.state}>\n {`${row.label} — ${ITEM_STATES[row.state]}`}\n {row.detail ? `. ${row.detail}` : ''}\n </Typography>\n ))}\n </Box>\n )}\n {job && paused && (\n // Out of credits mid-build (AGL-3722): paused, never failed. What is\n // built is kept, and Resume carries on from the next item.\n <Alert\n severity=\"warning\"\n sx={{ mt: 0.5 }}\n action={\n <Stack direction=\"row\" spacing={1}>\n {orgSlug ? (\n <Button color=\"inherit\" size=\"small\" href={aiCreditsBillingHref(orgSlug)}>\n {'Upgrade'}\n </Button>\n ) : null}\n <Button color=\"inherit\" size=\"small\" disabled={busy} onClick={() => void resume(job)}>\n {'Resume'}\n </Button>\n </Stack>\n }\n >\n {`Paused. ${job.error ?? 'Your AI credits ran out.'} What is built so far is kept, and Resume carries on from the next item once you upgrade or your credits renew.`}\n </Alert>\n )}\n {job && retryPrompt && (\n <AiCreditsPromptNotice\n prompt={retryPrompt}\n noun=\"build\"\n orgSlug={orgSlug}\n busy={busy}\n onBuildWhatFits={() => void resume(job, { retry: 'failed-items', creditsConfirmed: true })}\n />\n )}\n {settled && (\n <Typography variant=\"body2\" sx={{ mt: 0.5 }}>\n {outcome ?? job?.error ?? ''}\n </Typography>\n )}\n {storeFinish && (\n <Box sx={{ mt: 1 }}>\n <AiStoreFinishCard steps={storeFinish} hostId={job ? aiStoreFinishHostId(job) : null} />\n </Box>\n )}\n {job && (\n <Stack direction=\"row\" spacing={1} sx={{ mt: 1 }}>\n {job && aiBuildCanRetry(job) && (\n <Button size=\"small\" variant=\"contained\" disabled={busy} onClick={() => void resume(job, { retry: 'failed-items' })}>\n {retryRange ? `Try again what failed · ${aiCreditRangeText(retryRange)}` : 'Try again what failed'}\n </Button>\n )}\n <Button size=\"small\" onClick={() => openAiJobs({ jobId: job.id })}>\n {'Open in AI jobs'}\n </Button>\n </Stack>\n )}\n </Paper>\n )\n}\n"],"names":["pluginDocsHelp","HelpTip","Alert","Box","Button","CircularProgress","Paper","Stack","Typography","useEffect","useRef","useState","aiBuildCanRetry","aiBuildItemRows","aiBuildOutcomeLine","aiBuildRetryCreditRange","aiCreditRangeText","AiCreditsPromptNotice","aiCreditsBillingHref","aiStoreFinishHostId","aiStoreFinishLinks","AiStoreFinishCard","AI_JOB_TERMINAL_STATUSES","followAiJobEvents","AiJobPlan","resumeAiJobRequest","openAiJobs","ASSIST_BUILD_HELP","anchor","excerpt","ITEM_STATES","done","active","waiting","failed","skipped","AssistBuildCard","proposal","job","notice","orgId","user","staff","onJob","onNotice","orgSlug","outcome","busy","setBusy","retryPrompt","setRetryPrompt","userRef","current","onJobRef","paused","status","following","Boolean","includes","jobId","id","controller","AbortController","signal","next","abort","resume","target","options","decision","credits","retry","error","retryRange","settled","storeFinish","variant","sx","mt","p","aria-label","direction","spacing","alignItems","summary","size","color","role","onResume","plan","items","length","component","m","pl","map","row","data-item-state","state","label","detail","slot","severity","action","href","disabled","onClick","prompt","noun","onBuildWhatFits","creditsConfirmed","steps","hostId"],"mappings":"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"}
1
+ {"version":3,"sources":["../../../../../../../libs/plugins/ai/src/lib/components/assist-build-card.component.tsx"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n'use client'\n\nimport type { MaybeTokenSource } from '@aglyn/shared-util-http/authorized-token'\nimport { pluginDocsHelp } from '@aglyn/aglyn/app-utils/docs-help'\nimport { HelpTip } from '@aglyn/shared-ui-jsx'\nimport { Alert, Box, Button, CircularProgress, Paper, Stack, Typography } from '@mui/material'\nimport { useEffect, useRef, useState } from 'react'\nimport { aiBuildCanRetry, aiBuildItemRows, aiBuildOutcomeLine, aiBuildRetryCreditRange } from '../model/ai-build-progress'\nimport { aiCreditRangeText, type AiCreditsPrompt } from '../model/ai-credit-estimate'\nimport { AiCreditsPromptNotice } from './ai-credits-prompt.component'\nimport { aiCreditsBillingHref, aiStoreFinishHostId, aiStoreFinishLinks } from './ai-job-links'\nimport { AiStoreFinishCard } from './ai-store-finish-card.component'\nimport { AI_JOB_TERMINAL_STATUSES, type AiJobSummary } from '../model/ai-jobs.types'\nimport type { AssistBuildProposal } from '../model/assist-build'\nimport { followAiJobEvents } from './ai-job-events'\nimport { AiJobInputForm } from './ai-job-input-form.component'\nimport { AiJobPlan } from './ai-job-plan.component'\nimport { resumeAiJobRequest, type AiJobResumeOptions } from './ai-job-requests'\nimport { openAiJobs } from './ai-jobs-store'\n\n/**\n * The one card a build proposed in the chat becomes (AGL-3616): while its\n * job plans, a line saying so; then the job's own plan card, with its one\n * price and Confirm — the same `AiJobPlan` the AI jobs drawer shows, so\n * confirming here and there is one door; then where the build stands, item\n * by item, with AI jobs a click away. The job itself is started by the\n * panel, once, when the turn that proposed it ends; this card only follows\n * it, so re-rendering a stored thread never starts a second build.\n */\nexport interface AssistBuildCardProps {\n proposal: AssistBuildProposal\n /** The job the proposal started, as last seen; `null` while it is being created. */\n job: AiJobSummary | null\n /** Why the job could not be created or confirmed, when it could not. */\n notice: string | null\n orgId: string\n user: MaybeTokenSource\n staff?: boolean\n /** The job as it moved, for the thread to keep. */\n onJob: (job: AiJobSummary) => void\n onNotice: (notice: string | null) => void\n /** The workspace's path slug, for Upgrade on a Free build past what is left or paused (AGL-3722). */\n orgSlug?: string | null\n}\n\n/** The card's own section of the Assist builds guide (AGL-3660). */\nconst ASSIST_BUILD_HELP = pluginDocsHelp('aiAssistBuilds', {\n anchor: '#the-plan-card',\n excerpt:\n 'What one request will build, item by item, with its estimate. Nothing is built until you choose Confirm plan, and what it makes is a draft.',\n})\n\nconst ITEM_STATES = { done: 'built', active: 'building', waiting: 'waiting', failed: 'failed', skipped: 'not built' } as const\n\nexport function AssistBuildCard({\n proposal,\n job,\n notice,\n orgId,\n user,\n staff = false,\n onJob,\n onNotice,\n orgSlug,\n}: AssistBuildCardProps): JSX.Element {\n const [busy, setBusy] = useState(false)\n // A Free Try again past what is left (AGL-3722): its prompt, until chosen.\n const [retryPrompt, setRetryPrompt] = useState<AiCreditsPrompt | null>(null)\n const userRef = useRef(user)\n userRef.current = user\n const onJobRef = useRef(onJob)\n onJobRef.current = onJob\n\n // Follow a job that is still planning or building; a plan waiting for its\n // confirmation and a settled job need nothing more from the stream.\n // A build the meter paused (AGL-3722) waits for Resume, not the stream.\n const paused = job?.status === 'needs_input'\n const following = Boolean(\n job && !AI_JOB_TERMINAL_STATUSES.includes(job.status) && job.status !== 'needs_review' && !paused,\n )\n const jobId = job?.id ?? null\n useEffect(() => {\n if (!following || !jobId) return\n const controller = new AbortController()\n void followAiJobEvents(() => userRef.current, orgId, jobId, controller.signal, (next) => onJobRef.current(next))\n return () => controller.abort()\n }, [following, jobId, orgId])\n\n const resume = async (target: AiJobSummary, options?: AiJobResumeOptions) => {\n setBusy(true)\n onNotice(null)\n setRetryPrompt(null)\n const decision = await resumeAiJobRequest(user, orgId, target, options)\n if (decision.job) onJob(decision.job)\n // A Free Try again past what is left asks with its choices; a plan's\n // card draws its own from the job the door answered with.\n if (decision.credits && options?.retry) setRetryPrompt(decision.credits)\n else if (decision.error && !(decision.credits && target.status === 'needs_review')) onNotice(decision.error)\n setBusy(false)\n }\n const retryRange = job && aiBuildCanRetry(job) ? aiBuildRetryCreditRange(job) : null\n\n const settled = job ? AI_JOB_TERMINAL_STATUSES.includes(job.status) : false\n const outcome = job ? aiBuildOutcomeLine(job) : null\n // A build that made the site a store (AGL-3676) ends with what is left before it sells.\n const storeFinish = job && orgSlug ? aiStoreFinishLinks(job, orgSlug) : null\n return (\n <Paper variant=\"outlined\" sx={{ mt: 1, p: 1.5 }} aria-label=\"Build plan\">\n <Stack direction=\"row\" spacing={0.5} sx={{ alignItems: 'center' }}>\n <Typography variant=\"subtitle2\">{proposal.summary}</Typography>\n <HelpTip {...ASSIST_BUILD_HELP} />\n </Stack>\n {!job && !notice && (\n <Stack direction=\"row\" spacing={1} sx={{ mt: 0.5, alignItems: 'center' }}>\n <CircularProgress size={14} />\n <Typography variant=\"body2\" color=\"text.secondary\">\n {'Planning what to build on this site…'}\n </Typography>\n </Stack>\n )}\n {notice && (\n <Typography variant=\"body2\" color=\"error\" sx={{ mt: 0.5 }} role=\"alert\">\n {notice}\n </Typography>\n )}\n {job && job.status === 'needs_review' && (\n <AiJobPlan\n job={job}\n busy={busy}\n staff={staff}\n user={user}\n orgSlug={orgSlug}\n onResume={(target, options) => void resume(target, options)}\n />\n )}\n {job && following && (\n <Stack direction=\"row\" spacing={1} sx={{ mt: 0.5, alignItems: 'center' }}>\n <CircularProgress size={14} />\n <Typography variant=\"body2\" color=\"text.secondary\">\n {job.plan?.status === 'confirmed'\n ? 'Building each part in turn. What it makes is an unpublished draft unless you chose to publish.'\n : 'Planning what to build on this site…'}\n </Typography>\n </Stack>\n )}\n {job && (job.items?.length ?? 0) > 0 && job.status !== 'needs_review' && (\n <Box component=\"ul\" aria-label=\"Items\" sx={{ m: 0, mt: 0.5, pl: 2 }}>\n {aiBuildItemRows(job).map((row) => (\n <Typography key={row.slot} component=\"li\" variant=\"caption\" data-item-state={row.state}>\n {`${row.label} — ${ITEM_STATES[row.state]}`}\n {row.detail ? `. ${row.detail}` : ''}\n </Typography>\n ))}\n </Box>\n )}\n {job && paused && job.input ? (\n // A plan that needs an ID only the person has (AGL-3978): asked here,\n // and answered back onto the plan card.\n <AiJobInputForm job={{ ...job, input: job.input }} orgId={orgId} user={user} onJob={onJob} />\n ) : job && paused && (\n // Out of credits mid-build (AGL-3722): paused, never failed. What is\n // built is kept, and Resume carries on from the next item.\n <Alert\n severity=\"warning\"\n sx={{ mt: 0.5 }}\n action={\n <Stack direction=\"row\" spacing={1}>\n {orgSlug ? (\n <Button color=\"inherit\" size=\"small\" href={aiCreditsBillingHref(orgSlug)}>\n {'Upgrade'}\n </Button>\n ) : null}\n <Button color=\"inherit\" size=\"small\" disabled={busy} onClick={() => void resume(job)}>\n {'Resume'}\n </Button>\n </Stack>\n }\n >\n {`Paused. ${job.error ?? 'Your AI credits ran out.'} What is built so far is kept, and Resume carries on from the next item once you upgrade or your credits renew.`}\n </Alert>\n )}\n {job && retryPrompt && (\n <AiCreditsPromptNotice\n prompt={retryPrompt}\n noun=\"build\"\n orgSlug={orgSlug}\n busy={busy}\n onBuildWhatFits={() => void resume(job, { retry: 'failed-items', creditsConfirmed: true })}\n />\n )}\n {settled && (\n <Typography variant=\"body2\" sx={{ mt: 0.5 }}>\n {outcome ?? job?.error ?? ''}\n </Typography>\n )}\n {storeFinish && (\n <Box sx={{ mt: 1 }}>\n <AiStoreFinishCard steps={storeFinish} hostId={job ? aiStoreFinishHostId(job) : null} />\n </Box>\n )}\n {job && (\n <Stack direction=\"row\" spacing={1} sx={{ mt: 1 }}>\n {job && aiBuildCanRetry(job) && (\n <Button size=\"small\" variant=\"contained\" disabled={busy} onClick={() => void resume(job, { retry: 'failed-items' })}>\n {retryRange ? `Try again what failed · ${aiCreditRangeText(retryRange)}` : 'Try again what failed'}\n </Button>\n )}\n <Button size=\"small\" onClick={() => openAiJobs({ jobId: job.id })}>\n {'Open in AI jobs'}\n </Button>\n </Stack>\n )}\n </Paper>\n )\n}\n"],"names":["pluginDocsHelp","HelpTip","Alert","Box","Button","CircularProgress","Paper","Stack","Typography","useEffect","useRef","useState","aiBuildCanRetry","aiBuildItemRows","aiBuildOutcomeLine","aiBuildRetryCreditRange","aiCreditRangeText","AiCreditsPromptNotice","aiCreditsBillingHref","aiStoreFinishHostId","aiStoreFinishLinks","AiStoreFinishCard","AI_JOB_TERMINAL_STATUSES","followAiJobEvents","AiJobInputForm","AiJobPlan","resumeAiJobRequest","openAiJobs","ASSIST_BUILD_HELP","anchor","excerpt","ITEM_STATES","done","active","waiting","failed","skipped","AssistBuildCard","proposal","job","notice","orgId","user","staff","onJob","onNotice","orgSlug","outcome","busy","setBusy","retryPrompt","setRetryPrompt","userRef","current","onJobRef","paused","status","following","Boolean","includes","jobId","id","controller","AbortController","signal","next","abort","resume","target","options","decision","credits","retry","error","retryRange","settled","storeFinish","variant","sx","mt","p","aria-label","direction","spacing","alignItems","summary","size","color","role","onResume","plan","items","length","component","m","pl","map","row","data-item-state","state","label","detail","slot","input","severity","action","href","disabled","onClick","prompt","noun","onBuildWhatFits","creditsConfirmed","steps","hostId"],"mappings":"AAAA;;;;;;;;;;;;;;;CAeC,GAED;;;AAGA,SAASA,cAAc,QAAQ,mCAAkC;AACjE,SAASC,OAAO,QAAQ,uBAAsB;AAC9C,SAASC,KAAK,EAAEC,GAAG,EAAEC,MAAM,EAAEC,gBAAgB,EAAEC,KAAK,EAAEC,KAAK,EAAEC,UAAU,QAAQ,gBAAe;AAC9F,SAASC,SAAS,EAAEC,MAAM,EAAEC,QAAQ,QAAQ,QAAO;AACnD,SAASC,eAAe,EAAEC,eAAe,EAAEC,kBAAkB,EAAEC,uBAAuB,QAAQ,gCAA4B;AAC1H,SAASC,iBAAiB,QAA8B,iCAA6B;AACrF,SAASC,qBAAqB,QAAQ,mCAA+B;AACrE,SAASC,oBAAoB,EAAEC,mBAAmB,EAAEC,kBAAkB,QAAQ,oBAAgB;AAC9F,SAASC,iBAAiB,QAAQ,sCAAkC;AACpE,SAASC,wBAAwB,QAA2B,4BAAwB;AAEpF,SAASC,iBAAiB,QAAQ,qBAAiB;AACnD,SAASC,cAAc,QAAQ,mCAA+B;AAC9D,SAASC,SAAS,QAAQ,6BAAyB;AACnD,SAASC,kBAAkB,QAAiC,uBAAmB;AAC/E,SAASC,UAAU,QAAQ,qBAAiB;AA2B5C,kEAAkE,GAClE,MAAMC,oBAAoB5B,eAAe,kBAAkB;IACzD6B,QAAQ;IACRC,SACE;AACJ;AAEA,MAAMC,cAAc;IAAEC,MAAM;IAASC,QAAQ;IAAYC,SAAS;IAAWC,QAAQ;IAAUC,SAAS;AAAY;AAEpH,OAAO,SAASC,gBAAgB,EAC9BC,QAAQ,EACRC,GAAG,EACHC,MAAM,EACNC,KAAK,EACLC,IAAI,EACJC,QAAQ,KAAK,EACbC,KAAK,EACLC,QAAQ,EACRC,OAAO,EACc;qBAkHDP,YAcXQ;QArDER,WAMEA;IAhFb,MAAM,CAACS,MAAMC,QAAQ,GAAGtC,SAAS;IACjC,2EAA2E;IAC3E,MAAM,CAACuC,aAAaC,eAAe,GAAGxC,SAAiC;IACvE,MAAMyC,UAAU1C,OAAOgC;IACvBU,QAAQC,OAAO,GAAGX;IAClB,MAAMY,WAAW5C,OAAOkC;IACxBU,SAASD,OAAO,GAAGT;IAEnB,0EAA0E;IAC1E,oEAAoE;IACpE,wEAAwE;IACxE,MAAMW,SAAShB,CAAAA,uBAAAA,IAAKiB,MAAM,MAAK;IAC/B,MAAMC,YAAYC,QAChBnB,OAAO,CAACjB,yBAAyBqC,QAAQ,CAACpB,IAAIiB,MAAM,KAAKjB,IAAIiB,MAAM,KAAK,kBAAkB,CAACD;IAE7F,MAAMK,gBAAQrB,uBAAAA,IAAKsB,EAAE,mBAAI;IACzBpD,UAAU;QACR,IAAI,CAACgD,aAAa,CAACG,OAAO;QAC1B,MAAME,aAAa,IAAIC;QACvB,KAAKxC,kBAAkB,IAAM6B,QAAQC,OAAO,EAAEZ,OAAOmB,OAAOE,WAAWE,MAAM,EAAE,CAACC,OAASX,SAASD,OAAO,CAACY;QAC1G,OAAO,IAAMH,WAAWI,KAAK;IAC/B,GAAG;QAACT;QAAWG;QAAOnB;KAAM;IAE5B,MAAM0B,SAAS,OAAOC,QAAsBC;QAC1CpB,QAAQ;QACRJ,SAAS;QACTM,eAAe;QACf,MAAMmB,WAAW,MAAM5C,mBAAmBgB,MAAMD,OAAO2B,QAAQC;QAC/D,IAAIC,SAAS/B,GAAG,EAAEK,MAAM0B,SAAS/B,GAAG;QACpC,qEAAqE;QACrE,0DAA0D;QAC1D,IAAI+B,SAASC,OAAO,KAAIF,2BAAAA,QAASG,KAAK,GAAErB,eAAemB,SAASC,OAAO;aAClE,IAAID,SAASG,KAAK,IAAI,CAAEH,CAAAA,SAASC,OAAO,IAAIH,OAAOZ,MAAM,KAAK,cAAa,GAAIX,SAASyB,SAASG,KAAK;QAC3GxB,QAAQ;IACV;IACA,MAAMyB,aAAanC,OAAO3B,gBAAgB2B,OAAOxB,wBAAwBwB,OAAO;IAEhF,MAAMoC,UAAUpC,MAAMjB,yBAAyBqC,QAAQ,CAACpB,IAAIiB,MAAM,IAAI;IACtE,MAAMT,UAAUR,MAAMzB,mBAAmByB,OAAO;IAChD,wFAAwF;IACxF,MAAMqC,cAAcrC,OAAOO,UAAU1B,mBAAmBmB,KAAKO,WAAW;IACxE,qBACE,MAACxC;QAAMuE,SAAQ;QAAWC,IAAI;YAAEC,IAAI;YAAGC,GAAG;QAAI;QAAGC,cAAW;;0BAC1D,MAAC1E;gBAAM2E,WAAU;gBAAMC,SAAS;gBAAKL,IAAI;oBAAEM,YAAY;gBAAS;;kCAC9D,KAAC5E;wBAAWqE,SAAQ;kCAAavC,SAAS+C,OAAO;;kCACjD,KAACpF,sBAAY2B;;;YAEd,CAACW,OAAO,CAACC,wBACR,MAACjC;gBAAM2E,WAAU;gBAAMC,SAAS;gBAAGL,IAAI;oBAAEC,IAAI;oBAAKK,YAAY;gBAAS;;kCACrE,KAAC/E;wBAAiBiF,MAAM;;kCACxB,KAAC9E;wBAAWqE,SAAQ;wBAAQU,OAAM;kCAC/B;;;;YAIN/C,wBACC,KAAChC;gBAAWqE,SAAQ;gBAAQU,OAAM;gBAAQT,IAAI;oBAAEC,IAAI;gBAAI;gBAAGS,MAAK;0BAC7DhD;;YAGJD,OAAOA,IAAIiB,MAAM,KAAK,gCACrB,KAAC/B;gBACCc,KAAKA;gBACLS,MAAMA;gBACNL,OAAOA;gBACPD,MAAMA;gBACNI,SAASA;gBACT2C,UAAU,CAACrB,QAAQC,UAAY,KAAKF,OAAOC,QAAQC;;YAGtD9B,OAAOkB,2BACN,MAAClD;gBAAM2E,WAAU;gBAAMC,SAAS;gBAAGL,IAAI;oBAAEC,IAAI;oBAAKK,YAAY;gBAAS;;kCACrE,KAAC/E;wBAAiBiF,MAAM;;kCACxB,KAAC9E;wBAAWqE,SAAQ;wBAAQU,OAAM;kCAC/BhD,EAAAA,YAAAA,IAAImD,IAAI,qBAARnD,UAAUiB,MAAM,MAAK,cAClB,mGACA;;;;YAITjB,OAAO,WAACA,aAAAA,IAAIoD,KAAK,qBAATpD,WAAWqD,MAAM,oBAAI,KAAK,KAAKrD,IAAIiB,MAAM,KAAK,gCACrD,KAACrD;gBAAI0F,WAAU;gBAAKZ,cAAW;gBAAQH,IAAI;oBAAEgB,GAAG;oBAAGf,IAAI;oBAAKgB,IAAI;gBAAE;0BAC/DlF,gBAAgB0B,KAAKyD,GAAG,CAAC,CAACC,oBACzB,MAACzF;wBAA0BqF,WAAU;wBAAKhB,SAAQ;wBAAUqB,mBAAiBD,IAAIE,KAAK;;4BACnF,GAAGF,IAAIG,KAAK,CAAC,GAAG,EAAErE,WAAW,CAACkE,IAAIE,KAAK,CAAC,EAAE;4BAC1CF,IAAII,MAAM,GAAG,CAAC,EAAE,EAAEJ,IAAII,MAAM,EAAE,GAAG;;uBAFnBJ,IAAIK,IAAI;;YAO9B/D,OAAOgB,UAAUhB,IAAIgE,KAAK,GACzB,sEAAsE;YACtE,wCAAwC;0BACxC,KAAC/E;gBAAee,KAAK,aAAKA;oBAAKgE,OAAOhE,IAAIgE,KAAK;;gBAAI9D,OAAOA;gBAAOC,MAAMA;gBAAME,OAAOA;iBAClFL,OAAOgB,UACT,qEAAqE;YACrE,2DAA2D;0BAC3D,KAACrD;gBACCsG,UAAS;gBACT1B,IAAI;oBAAEC,IAAI;gBAAI;gBACd0B,sBACE,MAAClG;oBAAM2E,WAAU;oBAAMC,SAAS;;wBAC7BrC,wBACC,KAAC1C;4BAAOmF,OAAM;4BAAUD,MAAK;4BAAQoB,MAAMxF,qBAAqB4B;sCAC7D;6BAED;sCACJ,KAAC1C;4BAAOmF,OAAM;4BAAUD,MAAK;4BAAQqB,UAAU3D;4BAAM4D,SAAS,IAAM,KAAKzC,OAAO5B;sCAC7E;;;;0BAKN,CAAC,QAAQ,GAAEA,aAAAA,IAAIkC,KAAK,YAATlC,aAAa,2BAA2B,+GAA+G,CAAC;;YAGvKA,OAAOW,6BACN,KAACjC;gBACC4F,QAAQ3D;gBACR4D,MAAK;gBACLhE,SAASA;gBACTE,MAAMA;gBACN+D,iBAAiB,IAAM,KAAK5C,OAAO5B,KAAK;wBAAEiC,OAAO;wBAAgBwC,kBAAkB;oBAAK;;YAG3FrC,yBACC,KAACnE;gBAAWqE,SAAQ;gBAAQC,IAAI;oBAAEC,IAAI;gBAAI;2BACvChC,QAAAA,kBAAAA,UAAWR,uBAAAA,IAAKkC,KAAK,YAArB1B,QAAyB;;YAG7B6B,6BACC,KAACzE;gBAAI2E,IAAI;oBAAEC,IAAI;gBAAE;0BACf,cAAA,KAAC1D;oBAAkB4F,OAAOrC;oBAAasC,QAAQ3E,MAAMpB,oBAAoBoB,OAAO;;;YAGnFA,qBACC,MAAChC;gBAAM2E,WAAU;gBAAMC,SAAS;gBAAGL,IAAI;oBAAEC,IAAI;gBAAE;;oBAC5CxC,OAAO3B,gBAAgB2B,sBACtB,KAACnC;wBAAOkF,MAAK;wBAAQT,SAAQ;wBAAY8B,UAAU3D;wBAAM4D,SAAS,IAAM,KAAKzC,OAAO5B,KAAK;gCAAEiC,OAAO;4BAAe;kCAC9GE,aAAa,CAAC,wBAAwB,EAAE1D,kBAAkB0D,aAAa,GAAG;;kCAG/E,KAACtE;wBAAOkF,MAAK;wBAAQsB,SAAS,IAAMjF,WAAW;gCAAEiC,OAAOrB,IAAIsB,EAAE;4BAAC;kCAC5D;;;;;;AAMb"}
@@ -26,6 +26,7 @@ import { authorizedFetch } from "@aglyn/shared-util-http/authorized-token";
26
26
  import { Box, Button, Chip, CircularProgress, Collapse, IconButton, Stack, Typography } from "@mui/material";
27
27
  import { useCallback, useEffect, useRef, useState } from "react";
28
28
  import { AI_JOB_PHASE_LABELS, aiJobActivityCounts, aiJobPhase, aiJobsHeaderChips } from "../model/ai-job-activity.js";
29
+ import { AiJobInputForm } from "./ai-job-input-form.component.js";
29
30
  import { resumeAiJobRequest } from "./ai-job-requests.js";
30
31
  import { useAiJobCancel } from "./ai-job-cancel.component.js";
31
32
  import { aiBuildCanRetry, aiBuildItemRows, aiBuildRetryCreditRange, aiSitePartialCopy } from "../model/ai-build-progress.js";
@@ -591,7 +592,14 @@ export function AssistJobsDrawer({ orgId, org, orgReady, orgSlug, user, visible,
591
592
  creditsConfirmed: true
592
593
  })
593
594
  }) : null,
594
- job.status === 'needs_input' ? /*#__PURE__*/ _jsxs(Stack, {
595
+ job.status === 'needs_input' && job.input ? /*#__PURE__*/ _jsx(AiJobInputForm, {
596
+ job: _extends({}, job, {
597
+ input: job.input
598
+ }),
599
+ orgId: orgId,
600
+ user: user,
601
+ onJob: patchJob
602
+ }) : /* Paused by the meter (AGL-3722): Resume carries on from where it stopped. */ job.status === 'needs_input' ? /*#__PURE__*/ _jsxs(Stack, {
595
603
  direction: "row",
596
604
  spacing: 1,
597
605
  sx: {
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../../../libs/plugins/ai/src/lib/components/assist-jobs-drawer.component.tsx"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { checkEntitlement } from '@aglyn/aglyn'\nimport { trackEvent } from '@aglyn/aglyn/app-utils/analytics-events'\nimport { formatBytes } from '@aglyn/aglyn/app-utils/measure-node-map'\nimport {\n AI_JOB_TERMINAL_STATUSES,\n type AiJobOutput,\n type AiJobSummary,\n} from '../model/ai-jobs.types'\nimport type { AglynOrgBilling } from '@aglyn/aglyn/foundation/definitions/org-billing.types'\nimport { mdiChevronDown, mdiChevronUp } from '@aglyn/shared-data-mdi'\nimport { pluginDocsHelp } from '@aglyn/aglyn/app-utils/docs-help'\nimport { AppLink, HelpTip, MdiIcon } from '@aglyn/shared-ui-jsx'\nimport { authorizedFetch } from '@aglyn/shared-util-http/authorized-token'\nimport {\n Box,\n Button,\n Chip,\n CircularProgress,\n Collapse,\n IconButton,\n Stack,\n Typography,\n} from '@mui/material'\nimport { useCallback, useEffect, useRef, useState } from 'react'\nimport {\n AI_JOB_PHASE_LABELS,\n aiJobActivityCounts,\n aiJobPhase,\n aiJobsHeaderChips,\n type AiJobActivityState,\n type AiJobPhase,\n} from '../model/ai-job-activity'\nimport type { AiInsightSurface } from '../model/ai-insight'\nimport { resumeAiJobRequest, type AiJobResumeOptions } from './ai-job-requests'\nimport { useAiJobCancel } from './ai-job-cancel.component'\nimport { aiBuildCanRetry, aiBuildItemRows, aiBuildRetryCreditRange, aiSitePartialCopy } from '../model/ai-build-progress'\nimport { aiCreditRangeText, type AiCreditsPrompt } from '../model/ai-credit-estimate'\nimport { AiCreditsPromptNotice } from './ai-credits-prompt.component'\nimport { publishAiJob, type AiJobsOpenRequest } from './ai-jobs-store'\nimport { AiPageBriefDialog } from './ai-page-brief-dialog.component'\nimport { AiInsightDialog } from './ai-insight-dialog.component'\nimport { AiJobPlan } from './ai-job-plan.component'\nimport { aiCreditsBillingHref, aiJobOutputHref, aiJobPrimaryLink, aiSiteBuildHref } from './ai-job-links'\nimport { aiJobRefundCopy } from '../model/ai-job-failure-copy'\nimport {\n AI_SITE_REMOVED_ROW_COPY,\n AI_SITE_START_AGAIN_LABEL,\n aiCreateSiteHref,\n stashAiSiteStartAnswers,\n} from '../model/ai-site-start-handoff'\nimport { readEventFrames } from './ai-job-events'\n\n/** Try again, with what it is likely to cost (AGL-3722). */\nfunction aiBuildRetryLabel(job: AiJobSummary): string {\n const range = aiBuildRetryCreditRange(job)\n return range ? `Try again what failed · ${aiCreditRangeText(range)}` : 'Try again what failed'\n}\n\n// Where an output opens, and the stream reader, live beside the dialogs that\n// share them (AGL-3593); this module has always exported them.\nexport { aiJobOutputHref, aiJobPrimaryLink, readEventFrames }\n\n/**\n * The AI jobs drawer inside the Assist panel (AGL-2904): the workspace's\n * running and recent generation jobs, each step's progress, an \"open\n * draft\" link per output, and cancel.\n *\n * Reads through the routes, never Firestore directly, so the same\n * membership, flag and entitlement rungs answer every read; progress comes\n * from the events route's server-sent stream, re-opened when the server\n * says `reconnect`. Everything loads on EXPAND rather than on mount: the\n * panel opens on every console page, and a list nobody asked for is a read\n * on every page view.\n *\n * It opens EXPANDED while any of the workspace's jobs is moving or waiting\n * for the person (AGL-3593) — the shared list the top-bar indicator reads\n * says so — because a plan waiting behind a collapsed row is a site that\n * never gets built. An \"Open AI jobs\" anywhere in the console expands it,\n * scrolls to the job it names and highlights it for a moment.\n *\n * Hidden — not disabled — unless the flag shows it AND the plan carries\n * `aiGenerative`: a released-off feature does not exist, and a plan without\n * it is sold the add-on on the Billing page, not here.\n */\n\n/** Jobs the drawer lists; the route caps higher, the drawer is a glance. */\nconst LIST_LIMIT = 10\n\n/** How much of a brief a row shows. */\nconst BRIEF_PREVIEW_CHARS = 90\n\n/**\n * A row's chip says where the job stands in the words every AI surface uses\n * (AGL-3593): a plan waiting to be confirmed is \"Plan ready\", never \"Running\"\n * and never the machine's `needs_review`.\n */\nconst PHASE_COLOR: Record<AiJobPhase, 'default' | 'primary' | 'success' | 'error' | 'warning'> = {\n queued: 'default',\n planning: 'primary',\n 'plan-ready': 'warning',\n building: 'primary',\n attention: 'warning',\n done: 'success',\n failed: 'error',\n canceled: 'default',\n}\n\n/** The header's count chips, colored as the rows they count. */\nconst STATE_COLOR: Record<AiJobActivityState, 'primary' | 'warning'> = {\n 'needs-you': 'warning',\n attention: 'warning',\n running: 'primary',\n}\n\n/** What each item state reads as in a row (AGL-3616). */\nconst ITEM_STATE_LABELS = {\n done: 'built',\n active: 'building',\n waiting: 'waiting',\n failed: 'failed',\n skipped: 'not built',\n} as const\n\n/** How long a job AI jobs was opened on stays highlighted. */\nconst HIGHLIGHT_MS = 2_500\n\n/**\n * Where a guided start that ended unbuilt is tried again (AGL-3596): its\n * \"Building your site\" page, opened on its own answers (`?retry=1`). Only for\n * a job of the site the console is on, whose subdomain the address names;\n * `null` otherwise.\n */\nexport function aiJobRestartHref(\n job: Pick<AiJobSummary, 'id' | 'kind' | 'status' | 'hostId' | 'siteInputs'>,\n input: { orgSlug: string; hostId?: string | null; pathname: string },\n): string | null {\n if (job.kind !== 'site' || (job.status !== 'failed' && job.status !== 'canceled')) return null\n if (!job.siteInputs || !job.hostId || job.hostId !== input.hostId) return null\n const subdomain = /^\\/[^/]+\\/hosts\\/([^/?#]+)/.exec(input.pathname)?.[1] ?? null\n const href = aiSiteBuildHref(input.orgSlug, subdomain, job.id)\n return href ? `${href}?retry=1` : null\n}\n\n/** What a job cost the person: what it spent, less what we refunded. */\nfunction netCredits(job: Pick<AiJobSummary, 'creditsSpent' | 'refundedCredits'>): number {\n return Math.max(0, (job.creditsSpent ?? 0) - (job.refundedCredits ?? 0))\n}\n\n/**\n * The navigation entry a page job proposes for the page it built (AGL-2907),\n * or `null`. The job writes no menu: the member adds the entry once the page\n * is live.\n */\nexport function aiJobNavigationProposal(output: AiJobOutput): string | null {\n if (output.resource !== 'screen') return null\n const navigation = output.proposal?.['navigation']\n if (!navigation || typeof navigation !== 'object') return null\n const label = (navigation as Record<string, unknown>)['label']\n return typeof label === 'string' && label.trim() ? label.trim() : null\n}\n\n\nexport interface AssistJobsDrawerProps {\n /** The org the panel is scoped to — `undefined` where the page named none. */\n orgId: string | undefined\n org: Partial<AglynOrgBilling> | undefined\n orgReady: boolean\n orgSlug: string\n user: Parameters<typeof authorizedFetch>[0]\n /** The `release_ai_generative` verdict, staff bypass applied (the shell's). */\n visible: boolean\n /**\n * The viewer is staff (AGL-3078): a job that stopped for a broken rule shows\n * them where the refused answer broke it. Who may read a job is unchanged.\n */\n isStaff?: boolean\n /** The site the console page is on, when it is on one: a page is described for a site. */\n hostId?: string | null\n /**\n * The page's insight surface (AGL-2915) — a site's Analytics, Data or CRM\n * Reports page, or the workspace's Data page — with the site's subdomain;\n * `null` elsewhere, where no question about the figures is offered.\n */\n insight?: { surface: Exclude<AiInsightSurface, 'digest'>; host: string | null } | null\n /**\n * The workspace's jobs that are not yet settled, from the shared store the\n * top-bar indicator reads (AGL-3593). The header counts them, and the\n * drawer opens expanded while there is any. Absent, the drawer counts what\n * it loaded itself.\n */\n inFlight?: readonly AiJobSummary[]\n /**\n * The latest request to open AI jobs (AGL-3593): a new `seq` expands the\n * drawer, and a named job is scrolled to and highlighted.\n */\n focus?: AiJobsOpenRequest | null\n}\n\nexport function AssistJobsDrawer({\n orgId,\n org,\n orgReady,\n orgSlug,\n user,\n visible,\n isStaff = false,\n hostId,\n insight,\n inFlight,\n focus,\n}: AssistJobsDrawerProps): JSX.Element | null {\n const entitled = orgReady && checkEntitlement(org as never, 'aiGenerative')\n const [expanded, setExpanded] = useState(false)\n /**\n * The person opened or closed the list themselves: from then on the\n * expanded-by-default rule leaves their choice alone until the workspace\n * changes.\n */\n const toggledRef = useRef(false)\n /** The job AI jobs was opened on, highlighted for a moment once it is listed. */\n const [highlight, setHighlight] = useState<string | null>(null)\n const listRef = useRef<HTMLDivElement | null>(null)\n const [jobs, setJobs] = useState<AiJobSummary[]>([])\n const [loading, setLoading] = useState(false)\n const [notice, setNotice] = useState<string | null>(null)\n /** Whether the page brief dialog is open (AGL-2907). */\n const [describing, setDescribing] = useState(false)\n /**\n * The insight dialog (AGL-2915): `'ask'` for a new question, a job id for an\n * answer a job already wrote, `null` when closed.\n */\n const [insightOpen, setInsightOpen] = useState<string | null>(null)\n /** Job ids whose terminal event has been tracked, so a re-read does not count twice. */\n const trackedRef = useRef(new Set<string>())\n /** The job whose stream is open, so a re-render does not open a second. */\n const watchingRef = useRef<string | null>(null)\n\n const patchJob = useCallback((next: AiJobSummary) => {\n // Every counting surface moves with the row (AGL-3593).\n publishAiJob(next)\n setJobs((prior) => {\n const index = prior.findIndex((job) => job.id === next.id)\n if (index === -1) return [next, ...prior].slice(0, LIST_LIMIT)\n const copy = [...prior]\n copy[index] = next\n return copy\n })\n if (\n AI_JOB_TERMINAL_STATUSES.includes(next.status) &&\n !trackedRef.current.has(next.id)\n ) {\n trackedRef.current.add(next.id)\n if (next.status === 'done') {\n trackEvent('ai_job_completed', { kind: next.kind, credits: next.creditsSpent })\n } else if (next.status === 'failed') {\n trackEvent('ai_job_failed', { kind: next.kind })\n }\n }\n }, [])\n\n const load = useCallback(async () => {\n if (!orgId) return\n setLoading(true)\n setNotice(null)\n try {\n const response = await authorizedFetch(\n user,\n `/api/ai/jobs?orgId=${encodeURIComponent(orgId)}&limit=${LIST_LIMIT}`,\n )\n if (!response.ok) {\n const payload = await response.json().catch(() => null)\n setNotice(String(payload?.error ?? 'The AI jobs could not be loaded — try again.'))\n return\n }\n const payload = (await response.json()) as { jobs: AiJobSummary[] }\n // Every job that arrives already terminal is one the drawer did not\n // watch finish, so its outcome is not this session's to count.\n for (const job of payload.jobs) {\n if (AI_JOB_TERMINAL_STATUSES.includes(job.status)) trackedRef.current.add(job.id)\n // A job the indicator still counts that has settled since leaves it.\n publishAiJob(job)\n }\n setJobs(payload.jobs)\n } catch {\n setNotice('The AI jobs could not be loaded — try again.')\n } finally {\n setLoading(false)\n }\n }, [orgId, user])\n\n useEffect(() => {\n if (expanded) void load()\n }, [expanded, load])\n\n // Reset when the panel's org changes: a list from one workspace must not\n // show under another's key while the new one loads.\n useEffect(() => {\n setJobs([])\n setExpanded(false)\n toggledRef.current = false\n watchingRef.current = null\n }, [orgId])\n\n // Expanded by default while anything is moving or waiting (AGL-3593): a\n // plan waiting to be confirmed behind a collapsed row is a site that never\n // gets built. Otherwise collapsed, which reads nothing until asked.\n const anyInFlight = (inFlight?.length ?? 0) > 0\n useEffect(() => {\n if (anyInFlight && !toggledRef.current) setExpanded(true)\n }, [anyInFlight])\n\n // A request to open AI jobs (AGL-3593): expand, read the list again so a\n // job created a moment ago is in it, and highlight the job named.\n const focusSeq = focus?.seq ?? 0\n const focusJobId = focus?.jobId ?? null\n const expandedRef = useRef(expanded)\n expandedRef.current = expanded\n useEffect(() => {\n if (!focusSeq) return\n toggledRef.current = true\n setHighlight(focusJobId)\n // An open list does not re-run the expand effect's read, so it reads here.\n if (expandedRef.current) void load()\n else setExpanded(true)\n // Only a new request runs this; `load` and the job are read as they stand.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [focusSeq])\n\n // Scroll to the highlighted job once it is listed, then let it fade.\n const highlightListed = highlight !== null && jobs.some((job) => job.id === highlight)\n useEffect(() => {\n if (!highlight || !highlightListed) return undefined\n const row = Array.from(\n listRef.current?.querySelectorAll<HTMLElement>('[data-ai-job-id]') ?? [],\n ).find((element) => element.dataset['aiJobId'] === highlight)\n row?.scrollIntoView?.({ block: 'nearest', behavior: 'smooth' })\n const timer = setTimeout(() => setHighlight(null), HIGHLIGHT_MS)\n return () => clearTimeout(timer)\n }, [highlight, highlightListed])\n\n // Watch the most recent job that is still moving. One stream at a time:\n // the route re-reads a document every two seconds per open stream, and a\n // drawer with three running jobs does not need three of them.\n const watched = jobs.find((job) => !AI_JOB_TERMINAL_STATUSES.includes(job.status))\n const watchedId = watched?.id ?? null\n useEffect(() => {\n if (!expanded || !orgId || !watchedId || watchingRef.current === watchedId) return\n watchingRef.current = watchedId\n const controller = new AbortController()\n const watch = async () => {\n // The server closes a stream at its deadline with `reconnect`; the\n // loop here re-opens it until the job settles or the drawer unmounts.\n let again = true\n while (again && !controller.signal.aborted) {\n again = false\n try {\n const response = await authorizedFetch(\n user,\n `/api/ai/jobs/${encodeURIComponent(watchedId)}/events?orgId=${encodeURIComponent(orgId)}`,\n { signal: controller.signal },\n )\n if (!response.ok || !response.body) return\n await readEventFrames(response.body, (event) => {\n if (event['type'] === 'state') patchJob(event['job'] as AiJobSummary)\n else if (event['type'] === 'reconnect') again = true\n else if (event['type'] === 'gone') {\n setJobs((prior) => prior.filter((job) => job.id !== watchedId))\n }\n })\n } catch {\n // The stream ended without a terminal state — a network blip or\n // the drawer closing. The next expand reloads the list.\n return\n }\n }\n }\n void watch().finally(() => {\n if (watchingRef.current === watchedId) watchingRef.current = null\n })\n return () => {\n controller.abort()\n if (watchingRef.current === watchedId) watchingRef.current = null\n }\n }, [expanded, orgId, watchedId, user, patchJob])\n\n // The same door the dialog that started the job cancels through (AGL-3593),\n // behind the one confirm every Cancel shows (AGL-3616).\n const canceling = useAiJobCancel({ user, orgId, onJob: patchJob })\n\n /** The job whose resume is in flight, so its button cannot send twice. */\n const [resuming, setResuming] = useState<string | null>(null)\n // A Free Try again past what is left (AGL-3722): its prompt, by job, until chosen.\n const [retryPrompt, setRetryPrompt] = useState<{ jobId: string; prompt: AiCreditsPrompt } | null>(null)\n\n // Confirms a plan, or tries again a step whose answer broke a building\n // rule (AGL-2935). The door runs the next step inline and answers with the\n // job, so the row moves on without waiting for the stream.\n const resume = useCallback(\n async (job: AiJobSummary, options?: AiJobResumeOptions) => {\n if (!orgId) return\n setResuming(job.id)\n setNotice(null)\n setRetryPrompt(null)\n // The same door the dialog that started the job confirms through (AGL-3593).\n const { job: next, error, credits } = await resumeAiJobRequest(user, orgId, job, options)\n if (next) patchJob(next)\n // A Free job past what is left asks with its choices (AGL-3722): a\n // retry here, a plan on its own card from the job the door answered with.\n if (credits && options?.retry) setRetryPrompt({ jobId: job.id, prompt: credits })\n else if (error && !(credits && job.status === 'needs_review')) setNotice(error)\n setResuming(null)\n },\n [orgId, user, patchJob],\n )\n\n if (!visible || !orgId || !entitled) return null\n\n // Counted by state, never as one \"running\" figure (AGL-3593): a plan waiting\n // to be confirmed needs the person, and a stopped job is not moving.\n const chips = aiJobsHeaderChips(aiJobActivityCounts(inFlight ?? jobs))\n\n return (\n <Box sx={{ mb: 2, borderBottom: 1, borderColor: 'divider', pb: 1 }}>\n <Stack direction=\"row\" spacing={1} sx={{ alignItems: 'center' }}>\n <Typography variant=\"subtitle2\" sx={{ flexGrow: 1 }}>\n AI jobs\n {chips.map((chip) => (\n <Chip\n key={chip.state}\n size=\"small\"\n color={STATE_COLOR[chip.state]}\n label={chip.label}\n sx={{ ml: 1 }}\n />\n ))}\n </Typography>\n <HelpTip\n {...pluginDocsHelp('aiJobs', {\n anchor: '#ai-jobs-in-assist',\n excerpt:\n 'Every AI job in this workspace, newest first: where it stands, the credits it used, and its plan to confirm, cancel or try again.',\n })}\n />\n {/* A question about the page's figures (AGL-2915). */}\n {insight && (\n <Button size=\"small\" onClick={() => setInsightOpen('ask')}>\n Ask about your numbers\n </Button>\n )}\n {/* A page from a brief (AGL-2907), on a site's own routes. */}\n {hostId && (\n <Button size=\"small\" onClick={() => setDescribing(true)}>\n Describe a page\n </Button>\n )}\n <IconButton\n size=\"small\"\n aria-label={expanded ? 'Hide AI jobs' : 'Show AI jobs'}\n aria-expanded={expanded}\n onClick={() => {\n toggledRef.current = true\n setExpanded((prior) => !prior)\n }}\n >\n <MdiIcon\n path={expanded ? mdiChevronUp.path : mdiChevronDown.path}\n sx={{ fontSize: 18 }}\n />\n </IconButton>\n </Stack>\n <Collapse in={expanded} unmountOnExit>\n {notice && (\n <Typography variant=\"caption\" color=\"error\" component=\"div\" sx={{ mt: 0.5 }}>\n {notice}\n </Typography>\n )}\n {loading && !jobs.length && (\n <CircularProgress size={16} sx={{ mt: 1 }} aria-label=\"Loading AI jobs\" />\n )}\n {!loading && !jobs.length && !notice && (\n <Typography variant=\"caption\" color=\"text.secondary\" component=\"div\" sx={{ mt: 0.5 }}>\n No AI jobs yet.\n </Typography>\n )}\n {canceling.dialog}\n <Stack ref={listRef} spacing={1} sx={{ mt: 1 }} role=\"list\" aria-label=\"AI jobs\">\n {jobs.map((job) => {\n const restartHref = (row: AiJobSummary) =>\n aiJobRestartHref(row, {\n orgSlug,\n hostId,\n pathname: typeof window === 'undefined' ? '' : window.location.pathname,\n })\n const stepsDone = job.steps.filter((step) => step.status === 'done').length\n const current = job.steps.find((step) => step.status === 'running')\n const terminal = AI_JOB_TERMINAL_STATUSES.includes(job.status)\n const phase = aiJobPhase(job)\n const primary = aiJobPrimaryLink(job, orgSlug)\n const highlighted = highlight === job.id\n return (\n <Box\n key={job.id}\n role=\"listitem\"\n data-ai-job-id={job.id}\n aria-current={highlighted ? 'true' : undefined}\n sx={{\n borderRadius: 1,\n bgcolor: highlighted ? 'action.selected' : 'action.hover',\n outline: 2,\n outlineColor: highlighted ? 'primary.main' : 'transparent',\n transition: (theme) =>\n theme.transitions.create(['background-color', 'outline-color'], {\n duration: theme.transitions.duration.standard,\n }),\n px: 1.5,\n py: 1,\n }}\n >\n <Stack direction=\"row\" spacing={1} sx={{ alignItems: 'center' }}>\n <Chip size=\"small\" variant=\"outlined\" label={job.kind} />\n <Chip size=\"small\" color={PHASE_COLOR[phase]} label={AI_JOB_PHASE_LABELS[phase]} />\n <Typography variant=\"caption\" color=\"text.secondary\" sx={{ flexGrow: 1 }}>\n {stepsDone}/{job.steps.length} steps\n {current ? ` — ${current.name}` : ''}\n {/* Net of what a failure on our side gave back (AGL-3594). */}\n {netCredits(job) > 0 ? ` · ${netCredits(job)} credits` : ''}\n </Typography>\n {!terminal && (\n <Button\n size=\"small\"\n disabled={Boolean(job.cancelRequested) || canceling.busyJobId === job.id}\n onClick={() => canceling.ask(job)}\n >\n {job.cancelRequested ? 'Stopping…' : 'Cancel'}\n </Button>\n )}\n </Stack>\n <Typography variant=\"body2\" sx={{ mt: 0.5, wordBreak: 'break-word' }}>\n {job.brief.length > BRIEF_PREVIEW_CHARS\n ? `${job.brief.slice(0, BRIEF_PREVIEW_CHARS)}…`\n : job.brief}\n </Typography>\n {job.error && (\n <Typography variant=\"caption\" color={job.status === 'failed' ? 'error' : 'warning.main'} component=\"div\">\n {job.error}\n </Typography>\n )}\n {/* What became of its credits, from the job's recorded give-back (AGL-3596). */}\n {aiJobRefundCopy(job) && (\n <Typography variant=\"caption\" color=\"text.secondary\" component=\"div\">\n {aiJobRefundCopy(job)}\n </Typography>\n )}\n {/* A site that built part of itself says what, and that the rest was on us (AGL-3616). */}\n {aiSitePartialCopy(job) && (\n <Typography variant=\"caption\" color=\"text.secondary\" component=\"div\">\n {aiSitePartialCopy(job)}\n </Typography>\n )}\n {/* A build, item by item: where each stands, and what became of its credits (AGL-3616). */}\n {job.items?.length ? (\n <Box component=\"ul\" aria-label=\"Items\" sx={{ m: 0, mt: 0.5, pl: 2 }}>\n {aiBuildItemRows(job).map((row) => (\n <Typography key={row.slot} component=\"li\" variant=\"caption\" data-item-state={row.state}>\n {`${row.label} — ${ITEM_STATE_LABELS[row.state]}`}\n {row.detail ? `. ${row.detail}` : ''}\n </Typography>\n ))}\n </Box>\n ) : null}\n {aiBuildCanRetry(job) ? (\n <Button\n size=\"small\"\n variant=\"contained\"\n disabled={resuming === job.id}\n onClick={() => void resume(job, { retry: 'failed-items' })}\n sx={{ mt: 0.5 }}\n >\n {aiBuildRetryLabel(job)}\n </Button>\n ) : null}\n {retryPrompt?.jobId === job.id ? (\n <AiCreditsPromptNotice\n prompt={retryPrompt.prompt}\n noun=\"build\"\n orgSlug={orgSlug}\n busy={resuming === job.id}\n onBuildWhatFits={() => void resume(job, { retry: 'failed-items', creditsConfirmed: true })}\n />\n ) : null}\n {/* Paused by the meter (AGL-3722): Resume carries on from where it stopped. */}\n {job.status === 'needs_input' ? (\n <Stack direction=\"row\" spacing={1} sx={{ mt: 0.5 }}>\n <Button size=\"small\" variant=\"contained\" disabled={resuming === job.id} onClick={() => void resume(job)}>\n {'Resume'}\n </Button>\n <Button size=\"small\" component={AppLink} href={aiCreditsBillingHref(orgSlug)}>\n {'Upgrade'}\n </Button>\n </Stack>\n ) : null}\n {job.siteRemoved ? (\n // Its empty site was removed (AGL-3936): Create site, with the same answers.\n <>\n <Typography variant=\"caption\" color=\"text.secondary\" component=\"div\">\n {AI_SITE_REMOVED_ROW_COPY}\n </Typography>\n {aiCreateSiteHref(orgSlug) && job.siteInputs ? (\n <Button\n size=\"small\"\n variant=\"contained\"\n component={AppLink}\n href={aiCreateSiteHref(orgSlug) as string}\n onClick={() => stashAiSiteStartAnswers(job.siteInputs)}\n sx={{ mt: 0.5 }}\n >\n {AI_SITE_START_AGAIN_LABEL}\n </Button>\n ) : null}\n </>\n ) : restartHref(job) ? (\n <Button size=\"small\" variant=\"contained\" component={AppLink} href={restartHref(job) as string} sx={{ mt: 0.5 }}>\n {'Try again'}\n </Button>\n ) : null}\n {/* What a finished job built, first (AGL-3593). */}\n {primary ? (\n <Button\n size=\"small\"\n variant=\"contained\"\n component={AppLink}\n href={primary.href}\n sx={{ mt: 0.5 }}\n >\n {primary.label}\n </Button>\n ) : null}\n {job.outputs.map((output, index) => {\n const href = aiJobOutputHref(output, orgSlug)\n const navigation = aiJobNavigationProposal(output)\n return (\n <Box key={`${output.resource}:${output.id}:${index}`} sx={{ mt: 0.5 }}>\n {output.resource === 'insight' ? (\n <Button size=\"small\" onClick={() => setInsightOpen(output.id)}>\n View answer\n </Button>\n ) : href ? (\n <AppLink componentVariant=\"naked\" href={href}>\n Open draft — {output.label}\n </AppLink>\n ) : output.text ? (\n <Typography\n variant=\"body2\"\n component=\"pre\"\n sx={{ whiteSpace: 'pre-wrap', fontFamily: 'inherit', m: 0 }}\n >\n {output.text}\n </Typography>\n ) : (\n <Typography variant=\"caption\" color=\"text.secondary\">\n {output.label}\n </Typography>\n )}\n {output.load ? (\n <Typography variant=\"caption\" color=\"text.secondary\" component=\"div\">\n About {formatBytes(output.load.totalBytes)} on a first visit\n </Typography>\n ) : null}\n {output.note ? (\n <Typography variant=\"caption\" color=\"text.secondary\" component=\"div\">\n {output.note}\n </Typography>\n ) : null}\n {navigation ? (\n <Typography variant=\"caption\" color=\"text.secondary\" component=\"div\">\n Add “{navigation}” to your navigation once the page is live.\n </Typography>\n ) : null}\n </Box>\n )\n })}\n <AiJobPlan\n job={job}\n onResume={(target, options) => void resume(target, options)}\n busy={resuming === job.id}\n staff={isStaff}\n user={user}\n orgSlug={orgSlug}\n />\n </Box>\n )\n })}\n </Stack>\n </Collapse>\n {/*\n The brief dialog (AGL-2907). It starts a job and closes; the list\n below it is the only place the job is watched, so an open list reads\n the new job back as soon as the dialog hands it over.\n */}\n {insightOpen !== null && (\n <AiInsightDialog\n open\n onClose={() => {\n setInsightOpen(null)\n if (expanded) void load()\n }}\n orgId={orgId}\n orgSlug={orgSlug}\n hostId={insight?.host ? (hostId ?? null) : null}\n host={insight?.host ?? null}\n surface={insight?.surface ?? 'analytics'}\n user={user}\n uid={(user as { uid?: string } | null | undefined)?.uid ?? null}\n jobId={insightOpen === 'ask' ? null : insightOpen}\n />\n )}\n {hostId && (\n <AiPageBriefDialog\n open={describing}\n onClose={() => {\n setDescribing(false)\n if (expanded) void load()\n }}\n orgId={orgId}\n hostId={hostId}\n user={user}\n orgSlug={orgSlug}\n isStaff={isStaff}\n />\n )}\n </Box>\n )\n}\n\nexport default AssistJobsDrawer\n"],"names":["checkEntitlement","trackEvent","formatBytes","AI_JOB_TERMINAL_STATUSES","mdiChevronDown","mdiChevronUp","pluginDocsHelp","AppLink","HelpTip","MdiIcon","authorizedFetch","Box","Button","Chip","CircularProgress","Collapse","IconButton","Stack","Typography","useCallback","useEffect","useRef","useState","AI_JOB_PHASE_LABELS","aiJobActivityCounts","aiJobPhase","aiJobsHeaderChips","resumeAiJobRequest","useAiJobCancel","aiBuildCanRetry","aiBuildItemRows","aiBuildRetryCreditRange","aiSitePartialCopy","aiCreditRangeText","AiCreditsPromptNotice","publishAiJob","AiPageBriefDialog","AiInsightDialog","AiJobPlan","aiCreditsBillingHref","aiJobOutputHref","aiJobPrimaryLink","aiSiteBuildHref","aiJobRefundCopy","AI_SITE_REMOVED_ROW_COPY","AI_SITE_START_AGAIN_LABEL","aiCreateSiteHref","stashAiSiteStartAnswers","readEventFrames","aiBuildRetryLabel","job","range","LIST_LIMIT","BRIEF_PREVIEW_CHARS","PHASE_COLOR","queued","planning","building","attention","done","failed","canceled","STATE_COLOR","running","ITEM_STATE_LABELS","active","waiting","skipped","HIGHLIGHT_MS","aiJobRestartHref","input","kind","status","siteInputs","hostId","subdomain","exec","pathname","href","orgSlug","id","netCredits","Math","max","creditsSpent","refundedCredits","aiJobNavigationProposal","output","resource","navigation","proposal","label","trim","AssistJobsDrawer","orgId","org","orgReady","user","visible","isStaff","insight","inFlight","focus","entitled","expanded","setExpanded","toggledRef","highlight","setHighlight","listRef","jobs","setJobs","loading","setLoading","notice","setNotice","describing","setDescribing","insightOpen","setInsightOpen","trackedRef","Set","watchingRef","patchJob","next","prior","index","findIndex","slice","copy","includes","current","has","add","credits","load","response","encodeURIComponent","ok","payload","json","catch","String","error","anyInFlight","length","focusSeq","seq","focusJobId","jobId","expandedRef","highlightListed","some","row","undefined","Array","from","querySelectorAll","find","element","dataset","scrollIntoView","block","behavior","timer","setTimeout","clearTimeout","watched","watchedId","controller","AbortController","watch","again","signal","aborted","body","event","filter","finally","abort","canceling","onJob","resuming","setResuming","retryPrompt","setRetryPrompt","resume","options","retry","prompt","chips","sx","mb","borderBottom","borderColor","pb","direction","spacing","alignItems","variant","flexGrow","map","chip","size","color","state","ml","anchor","excerpt","onClick","aria-label","aria-expanded","path","fontSize","in","unmountOnExit","component","mt","dialog","ref","role","restartHref","window","location","stepsDone","steps","step","terminal","phase","primary","highlighted","data-ai-job-id","aria-current","borderRadius","bgcolor","outline","outlineColor","transition","theme","transitions","create","duration","standard","px","py","name","disabled","Boolean","cancelRequested","busyJobId","ask","wordBreak","brief","items","m","pl","data-item-state","detail","slot","noun","busy","onBuildWhatFits","creditsConfirmed","siteRemoved","outputs","componentVariant","text","whiteSpace","fontFamily","totalBytes","note","onResume","target","staff","open","onClose","host","surface","uid"],"mappings":"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"}
1
+ {"version":3,"sources":["../../../../../../../libs/plugins/ai/src/lib/components/assist-jobs-drawer.component.tsx"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { checkEntitlement } from '@aglyn/aglyn'\nimport { trackEvent } from '@aglyn/aglyn/app-utils/analytics-events'\nimport { formatBytes } from '@aglyn/aglyn/app-utils/measure-node-map'\nimport {\n AI_JOB_TERMINAL_STATUSES,\n type AiJobOutput,\n type AiJobSummary,\n} from '../model/ai-jobs.types'\nimport type { AglynOrgBilling } from '@aglyn/aglyn/foundation/definitions/org-billing.types'\nimport { mdiChevronDown, mdiChevronUp } from '@aglyn/shared-data-mdi'\nimport { pluginDocsHelp } from '@aglyn/aglyn/app-utils/docs-help'\nimport { AppLink, HelpTip, MdiIcon } from '@aglyn/shared-ui-jsx'\nimport { authorizedFetch } from '@aglyn/shared-util-http/authorized-token'\nimport {\n Box,\n Button,\n Chip,\n CircularProgress,\n Collapse,\n IconButton,\n Stack,\n Typography,\n} from '@mui/material'\nimport { useCallback, useEffect, useRef, useState } from 'react'\nimport {\n AI_JOB_PHASE_LABELS,\n aiJobActivityCounts,\n aiJobPhase,\n aiJobsHeaderChips,\n type AiJobActivityState,\n type AiJobPhase,\n} from '../model/ai-job-activity'\nimport type { AiInsightSurface } from '../model/ai-insight'\nimport { AiJobInputForm } from './ai-job-input-form.component'\nimport { resumeAiJobRequest, type AiJobResumeOptions } from './ai-job-requests'\nimport { useAiJobCancel } from './ai-job-cancel.component'\nimport { aiBuildCanRetry, aiBuildItemRows, aiBuildRetryCreditRange, aiSitePartialCopy } from '../model/ai-build-progress'\nimport { aiCreditRangeText, type AiCreditsPrompt } from '../model/ai-credit-estimate'\nimport { AiCreditsPromptNotice } from './ai-credits-prompt.component'\nimport { publishAiJob, type AiJobsOpenRequest } from './ai-jobs-store'\nimport { AiPageBriefDialog } from './ai-page-brief-dialog.component'\nimport { AiInsightDialog } from './ai-insight-dialog.component'\nimport { AiJobPlan } from './ai-job-plan.component'\nimport { aiCreditsBillingHref, aiJobOutputHref, aiJobPrimaryLink, aiSiteBuildHref } from './ai-job-links'\nimport { aiJobRefundCopy } from '../model/ai-job-failure-copy'\nimport {\n AI_SITE_REMOVED_ROW_COPY,\n AI_SITE_START_AGAIN_LABEL,\n aiCreateSiteHref,\n stashAiSiteStartAnswers,\n} from '../model/ai-site-start-handoff'\nimport { readEventFrames } from './ai-job-events'\n\n/** Try again, with what it is likely to cost (AGL-3722). */\nfunction aiBuildRetryLabel(job: AiJobSummary): string {\n const range = aiBuildRetryCreditRange(job)\n return range ? `Try again what failed · ${aiCreditRangeText(range)}` : 'Try again what failed'\n}\n\n// Where an output opens, and the stream reader, live beside the dialogs that\n// share them (AGL-3593); this module has always exported them.\nexport { aiJobOutputHref, aiJobPrimaryLink, readEventFrames }\n\n/**\n * The AI jobs drawer inside the Assist panel (AGL-2904): the workspace's\n * running and recent generation jobs, each step's progress, an \"open\n * draft\" link per output, and cancel.\n *\n * Reads through the routes, never Firestore directly, so the same\n * membership, flag and entitlement rungs answer every read; progress comes\n * from the events route's server-sent stream, re-opened when the server\n * says `reconnect`. Everything loads on EXPAND rather than on mount: the\n * panel opens on every console page, and a list nobody asked for is a read\n * on every page view.\n *\n * It opens EXPANDED while any of the workspace's jobs is moving or waiting\n * for the person (AGL-3593) — the shared list the top-bar indicator reads\n * says so — because a plan waiting behind a collapsed row is a site that\n * never gets built. An \"Open AI jobs\" anywhere in the console expands it,\n * scrolls to the job it names and highlights it for a moment.\n *\n * Hidden — not disabled — unless the flag shows it AND the plan carries\n * `aiGenerative`: a released-off feature does not exist, and a plan without\n * it is sold the add-on on the Billing page, not here.\n */\n\n/** Jobs the drawer lists; the route caps higher, the drawer is a glance. */\nconst LIST_LIMIT = 10\n\n/** How much of a brief a row shows. */\nconst BRIEF_PREVIEW_CHARS = 90\n\n/**\n * A row's chip says where the job stands in the words every AI surface uses\n * (AGL-3593): a plan waiting to be confirmed is \"Plan ready\", never \"Running\"\n * and never the machine's `needs_review`.\n */\nconst PHASE_COLOR: Record<AiJobPhase, 'default' | 'primary' | 'success' | 'error' | 'warning'> = {\n queued: 'default',\n planning: 'primary',\n 'plan-ready': 'warning',\n building: 'primary',\n attention: 'warning',\n done: 'success',\n failed: 'error',\n canceled: 'default',\n}\n\n/** The header's count chips, colored as the rows they count. */\nconst STATE_COLOR: Record<AiJobActivityState, 'primary' | 'warning'> = {\n 'needs-you': 'warning',\n attention: 'warning',\n running: 'primary',\n}\n\n/** What each item state reads as in a row (AGL-3616). */\nconst ITEM_STATE_LABELS = {\n done: 'built',\n active: 'building',\n waiting: 'waiting',\n failed: 'failed',\n skipped: 'not built',\n} as const\n\n/** How long a job AI jobs was opened on stays highlighted. */\nconst HIGHLIGHT_MS = 2_500\n\n/**\n * Where a guided start that ended unbuilt is tried again (AGL-3596): its\n * \"Building your site\" page, opened on its own answers (`?retry=1`). Only for\n * a job of the site the console is on, whose subdomain the address names;\n * `null` otherwise.\n */\nexport function aiJobRestartHref(\n job: Pick<AiJobSummary, 'id' | 'kind' | 'status' | 'hostId' | 'siteInputs'>,\n input: { orgSlug: string; hostId?: string | null; pathname: string },\n): string | null {\n if (job.kind !== 'site' || (job.status !== 'failed' && job.status !== 'canceled')) return null\n if (!job.siteInputs || !job.hostId || job.hostId !== input.hostId) return null\n const subdomain = /^\\/[^/]+\\/hosts\\/([^/?#]+)/.exec(input.pathname)?.[1] ?? null\n const href = aiSiteBuildHref(input.orgSlug, subdomain, job.id)\n return href ? `${href}?retry=1` : null\n}\n\n/** What a job cost the person: what it spent, less what we refunded. */\nfunction netCredits(job: Pick<AiJobSummary, 'creditsSpent' | 'refundedCredits'>): number {\n return Math.max(0, (job.creditsSpent ?? 0) - (job.refundedCredits ?? 0))\n}\n\n/**\n * The navigation entry a page job proposes for the page it built (AGL-2907),\n * or `null`. The job writes no menu: the member adds the entry once the page\n * is live.\n */\nexport function aiJobNavigationProposal(output: AiJobOutput): string | null {\n if (output.resource !== 'screen') return null\n const navigation = output.proposal?.['navigation']\n if (!navigation || typeof navigation !== 'object') return null\n const label = (navigation as Record<string, unknown>)['label']\n return typeof label === 'string' && label.trim() ? label.trim() : null\n}\n\n\nexport interface AssistJobsDrawerProps {\n /** The org the panel is scoped to — `undefined` where the page named none. */\n orgId: string | undefined\n org: Partial<AglynOrgBilling> | undefined\n orgReady: boolean\n orgSlug: string\n user: Parameters<typeof authorizedFetch>[0]\n /** The `release_ai_generative` verdict, staff bypass applied (the shell's). */\n visible: boolean\n /**\n * The viewer is staff (AGL-3078): a job that stopped for a broken rule shows\n * them where the refused answer broke it. Who may read a job is unchanged.\n */\n isStaff?: boolean\n /** The site the console page is on, when it is on one: a page is described for a site. */\n hostId?: string | null\n /**\n * The page's insight surface (AGL-2915) — a site's Analytics, Data or CRM\n * Reports page, or the workspace's Data page — with the site's subdomain;\n * `null` elsewhere, where no question about the figures is offered.\n */\n insight?: { surface: Exclude<AiInsightSurface, 'digest'>; host: string | null } | null\n /**\n * The workspace's jobs that are not yet settled, from the shared store the\n * top-bar indicator reads (AGL-3593). The header counts them, and the\n * drawer opens expanded while there is any. Absent, the drawer counts what\n * it loaded itself.\n */\n inFlight?: readonly AiJobSummary[]\n /**\n * The latest request to open AI jobs (AGL-3593): a new `seq` expands the\n * drawer, and a named job is scrolled to and highlighted.\n */\n focus?: AiJobsOpenRequest | null\n}\n\nexport function AssistJobsDrawer({\n orgId,\n org,\n orgReady,\n orgSlug,\n user,\n visible,\n isStaff = false,\n hostId,\n insight,\n inFlight,\n focus,\n}: AssistJobsDrawerProps): JSX.Element | null {\n const entitled = orgReady && checkEntitlement(org as never, 'aiGenerative')\n const [expanded, setExpanded] = useState(false)\n /**\n * The person opened or closed the list themselves: from then on the\n * expanded-by-default rule leaves their choice alone until the workspace\n * changes.\n */\n const toggledRef = useRef(false)\n /** The job AI jobs was opened on, highlighted for a moment once it is listed. */\n const [highlight, setHighlight] = useState<string | null>(null)\n const listRef = useRef<HTMLDivElement | null>(null)\n const [jobs, setJobs] = useState<AiJobSummary[]>([])\n const [loading, setLoading] = useState(false)\n const [notice, setNotice] = useState<string | null>(null)\n /** Whether the page brief dialog is open (AGL-2907). */\n const [describing, setDescribing] = useState(false)\n /**\n * The insight dialog (AGL-2915): `'ask'` for a new question, a job id for an\n * answer a job already wrote, `null` when closed.\n */\n const [insightOpen, setInsightOpen] = useState<string | null>(null)\n /** Job ids whose terminal event has been tracked, so a re-read does not count twice. */\n const trackedRef = useRef(new Set<string>())\n /** The job whose stream is open, so a re-render does not open a second. */\n const watchingRef = useRef<string | null>(null)\n\n const patchJob = useCallback((next: AiJobSummary) => {\n // Every counting surface moves with the row (AGL-3593).\n publishAiJob(next)\n setJobs((prior) => {\n const index = prior.findIndex((job) => job.id === next.id)\n if (index === -1) return [next, ...prior].slice(0, LIST_LIMIT)\n const copy = [...prior]\n copy[index] = next\n return copy\n })\n if (\n AI_JOB_TERMINAL_STATUSES.includes(next.status) &&\n !trackedRef.current.has(next.id)\n ) {\n trackedRef.current.add(next.id)\n if (next.status === 'done') {\n trackEvent('ai_job_completed', { kind: next.kind, credits: next.creditsSpent })\n } else if (next.status === 'failed') {\n trackEvent('ai_job_failed', { kind: next.kind })\n }\n }\n }, [])\n\n const load = useCallback(async () => {\n if (!orgId) return\n setLoading(true)\n setNotice(null)\n try {\n const response = await authorizedFetch(\n user,\n `/api/ai/jobs?orgId=${encodeURIComponent(orgId)}&limit=${LIST_LIMIT}`,\n )\n if (!response.ok) {\n const payload = await response.json().catch(() => null)\n setNotice(String(payload?.error ?? 'The AI jobs could not be loaded — try again.'))\n return\n }\n const payload = (await response.json()) as { jobs: AiJobSummary[] }\n // Every job that arrives already terminal is one the drawer did not\n // watch finish, so its outcome is not this session's to count.\n for (const job of payload.jobs) {\n if (AI_JOB_TERMINAL_STATUSES.includes(job.status)) trackedRef.current.add(job.id)\n // A job the indicator still counts that has settled since leaves it.\n publishAiJob(job)\n }\n setJobs(payload.jobs)\n } catch {\n setNotice('The AI jobs could not be loaded — try again.')\n } finally {\n setLoading(false)\n }\n }, [orgId, user])\n\n useEffect(() => {\n if (expanded) void load()\n }, [expanded, load])\n\n // Reset when the panel's org changes: a list from one workspace must not\n // show under another's key while the new one loads.\n useEffect(() => {\n setJobs([])\n setExpanded(false)\n toggledRef.current = false\n watchingRef.current = null\n }, [orgId])\n\n // Expanded by default while anything is moving or waiting (AGL-3593): a\n // plan waiting to be confirmed behind a collapsed row is a site that never\n // gets built. Otherwise collapsed, which reads nothing until asked.\n const anyInFlight = (inFlight?.length ?? 0) > 0\n useEffect(() => {\n if (anyInFlight && !toggledRef.current) setExpanded(true)\n }, [anyInFlight])\n\n // A request to open AI jobs (AGL-3593): expand, read the list again so a\n // job created a moment ago is in it, and highlight the job named.\n const focusSeq = focus?.seq ?? 0\n const focusJobId = focus?.jobId ?? null\n const expandedRef = useRef(expanded)\n expandedRef.current = expanded\n useEffect(() => {\n if (!focusSeq) return\n toggledRef.current = true\n setHighlight(focusJobId)\n // An open list does not re-run the expand effect's read, so it reads here.\n if (expandedRef.current) void load()\n else setExpanded(true)\n // Only a new request runs this; `load` and the job are read as they stand.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [focusSeq])\n\n // Scroll to the highlighted job once it is listed, then let it fade.\n const highlightListed = highlight !== null && jobs.some((job) => job.id === highlight)\n useEffect(() => {\n if (!highlight || !highlightListed) return undefined\n const row = Array.from(\n listRef.current?.querySelectorAll<HTMLElement>('[data-ai-job-id]') ?? [],\n ).find((element) => element.dataset['aiJobId'] === highlight)\n row?.scrollIntoView?.({ block: 'nearest', behavior: 'smooth' })\n const timer = setTimeout(() => setHighlight(null), HIGHLIGHT_MS)\n return () => clearTimeout(timer)\n }, [highlight, highlightListed])\n\n // Watch the most recent job that is still moving. One stream at a time:\n // the route re-reads a document every two seconds per open stream, and a\n // drawer with three running jobs does not need three of them.\n const watched = jobs.find((job) => !AI_JOB_TERMINAL_STATUSES.includes(job.status))\n const watchedId = watched?.id ?? null\n useEffect(() => {\n if (!expanded || !orgId || !watchedId || watchingRef.current === watchedId) return\n watchingRef.current = watchedId\n const controller = new AbortController()\n const watch = async () => {\n // The server closes a stream at its deadline with `reconnect`; the\n // loop here re-opens it until the job settles or the drawer unmounts.\n let again = true\n while (again && !controller.signal.aborted) {\n again = false\n try {\n const response = await authorizedFetch(\n user,\n `/api/ai/jobs/${encodeURIComponent(watchedId)}/events?orgId=${encodeURIComponent(orgId)}`,\n { signal: controller.signal },\n )\n if (!response.ok || !response.body) return\n await readEventFrames(response.body, (event) => {\n if (event['type'] === 'state') patchJob(event['job'] as AiJobSummary)\n else if (event['type'] === 'reconnect') again = true\n else if (event['type'] === 'gone') {\n setJobs((prior) => prior.filter((job) => job.id !== watchedId))\n }\n })\n } catch {\n // The stream ended without a terminal state — a network blip or\n // the drawer closing. The next expand reloads the list.\n return\n }\n }\n }\n void watch().finally(() => {\n if (watchingRef.current === watchedId) watchingRef.current = null\n })\n return () => {\n controller.abort()\n if (watchingRef.current === watchedId) watchingRef.current = null\n }\n }, [expanded, orgId, watchedId, user, patchJob])\n\n // The same door the dialog that started the job cancels through (AGL-3593),\n // behind the one confirm every Cancel shows (AGL-3616).\n const canceling = useAiJobCancel({ user, orgId, onJob: patchJob })\n\n /** The job whose resume is in flight, so its button cannot send twice. */\n const [resuming, setResuming] = useState<string | null>(null)\n // A Free Try again past what is left (AGL-3722): its prompt, by job, until chosen.\n const [retryPrompt, setRetryPrompt] = useState<{ jobId: string; prompt: AiCreditsPrompt } | null>(null)\n\n // Confirms a plan, or tries again a step whose answer broke a building\n // rule (AGL-2935). The door runs the next step inline and answers with the\n // job, so the row moves on without waiting for the stream.\n const resume = useCallback(\n async (job: AiJobSummary, options?: AiJobResumeOptions) => {\n if (!orgId) return\n setResuming(job.id)\n setNotice(null)\n setRetryPrompt(null)\n // The same door the dialog that started the job confirms through (AGL-3593).\n const { job: next, error, credits } = await resumeAiJobRequest(user, orgId, job, options)\n if (next) patchJob(next)\n // A Free job past what is left asks with its choices (AGL-3722): a\n // retry here, a plan on its own card from the job the door answered with.\n if (credits && options?.retry) setRetryPrompt({ jobId: job.id, prompt: credits })\n else if (error && !(credits && job.status === 'needs_review')) setNotice(error)\n setResuming(null)\n },\n [orgId, user, patchJob],\n )\n\n if (!visible || !orgId || !entitled) return null\n\n // Counted by state, never as one \"running\" figure (AGL-3593): a plan waiting\n // to be confirmed needs the person, and a stopped job is not moving.\n const chips = aiJobsHeaderChips(aiJobActivityCounts(inFlight ?? jobs))\n\n return (\n <Box sx={{ mb: 2, borderBottom: 1, borderColor: 'divider', pb: 1 }}>\n <Stack direction=\"row\" spacing={1} sx={{ alignItems: 'center' }}>\n <Typography variant=\"subtitle2\" sx={{ flexGrow: 1 }}>\n AI jobs\n {chips.map((chip) => (\n <Chip\n key={chip.state}\n size=\"small\"\n color={STATE_COLOR[chip.state]}\n label={chip.label}\n sx={{ ml: 1 }}\n />\n ))}\n </Typography>\n <HelpTip\n {...pluginDocsHelp('aiJobs', {\n anchor: '#ai-jobs-in-assist',\n excerpt:\n 'Every AI job in this workspace, newest first: where it stands, the credits it used, and its plan to confirm, cancel or try again.',\n })}\n />\n {/* A question about the page's figures (AGL-2915). */}\n {insight && (\n <Button size=\"small\" onClick={() => setInsightOpen('ask')}>\n Ask about your numbers\n </Button>\n )}\n {/* A page from a brief (AGL-2907), on a site's own routes. */}\n {hostId && (\n <Button size=\"small\" onClick={() => setDescribing(true)}>\n Describe a page\n </Button>\n )}\n <IconButton\n size=\"small\"\n aria-label={expanded ? 'Hide AI jobs' : 'Show AI jobs'}\n aria-expanded={expanded}\n onClick={() => {\n toggledRef.current = true\n setExpanded((prior) => !prior)\n }}\n >\n <MdiIcon\n path={expanded ? mdiChevronUp.path : mdiChevronDown.path}\n sx={{ fontSize: 18 }}\n />\n </IconButton>\n </Stack>\n <Collapse in={expanded} unmountOnExit>\n {notice && (\n <Typography variant=\"caption\" color=\"error\" component=\"div\" sx={{ mt: 0.5 }}>\n {notice}\n </Typography>\n )}\n {loading && !jobs.length && (\n <CircularProgress size={16} sx={{ mt: 1 }} aria-label=\"Loading AI jobs\" />\n )}\n {!loading && !jobs.length && !notice && (\n <Typography variant=\"caption\" color=\"text.secondary\" component=\"div\" sx={{ mt: 0.5 }}>\n No AI jobs yet.\n </Typography>\n )}\n {canceling.dialog}\n <Stack ref={listRef} spacing={1} sx={{ mt: 1 }} role=\"list\" aria-label=\"AI jobs\">\n {jobs.map((job) => {\n const restartHref = (row: AiJobSummary) =>\n aiJobRestartHref(row, {\n orgSlug,\n hostId,\n pathname: typeof window === 'undefined' ? '' : window.location.pathname,\n })\n const stepsDone = job.steps.filter((step) => step.status === 'done').length\n const current = job.steps.find((step) => step.status === 'running')\n const terminal = AI_JOB_TERMINAL_STATUSES.includes(job.status)\n const phase = aiJobPhase(job)\n const primary = aiJobPrimaryLink(job, orgSlug)\n const highlighted = highlight === job.id\n return (\n <Box\n key={job.id}\n role=\"listitem\"\n data-ai-job-id={job.id}\n aria-current={highlighted ? 'true' : undefined}\n sx={{\n borderRadius: 1,\n bgcolor: highlighted ? 'action.selected' : 'action.hover',\n outline: 2,\n outlineColor: highlighted ? 'primary.main' : 'transparent',\n transition: (theme) =>\n theme.transitions.create(['background-color', 'outline-color'], {\n duration: theme.transitions.duration.standard,\n }),\n px: 1.5,\n py: 1,\n }}\n >\n <Stack direction=\"row\" spacing={1} sx={{ alignItems: 'center' }}>\n <Chip size=\"small\" variant=\"outlined\" label={job.kind} />\n <Chip size=\"small\" color={PHASE_COLOR[phase]} label={AI_JOB_PHASE_LABELS[phase]} />\n <Typography variant=\"caption\" color=\"text.secondary\" sx={{ flexGrow: 1 }}>\n {stepsDone}/{job.steps.length} steps\n {current ? ` — ${current.name}` : ''}\n {/* Net of what a failure on our side gave back (AGL-3594). */}\n {netCredits(job) > 0 ? ` · ${netCredits(job)} credits` : ''}\n </Typography>\n {!terminal && (\n <Button\n size=\"small\"\n disabled={Boolean(job.cancelRequested) || canceling.busyJobId === job.id}\n onClick={() => canceling.ask(job)}\n >\n {job.cancelRequested ? 'Stopping…' : 'Cancel'}\n </Button>\n )}\n </Stack>\n <Typography variant=\"body2\" sx={{ mt: 0.5, wordBreak: 'break-word' }}>\n {job.brief.length > BRIEF_PREVIEW_CHARS\n ? `${job.brief.slice(0, BRIEF_PREVIEW_CHARS)}…`\n : job.brief}\n </Typography>\n {job.error && (\n <Typography variant=\"caption\" color={job.status === 'failed' ? 'error' : 'warning.main'} component=\"div\">\n {job.error}\n </Typography>\n )}\n {/* What became of its credits, from the job's recorded give-back (AGL-3596). */}\n {aiJobRefundCopy(job) && (\n <Typography variant=\"caption\" color=\"text.secondary\" component=\"div\">\n {aiJobRefundCopy(job)}\n </Typography>\n )}\n {/* A site that built part of itself says what, and that the rest was on us (AGL-3616). */}\n {aiSitePartialCopy(job) && (\n <Typography variant=\"caption\" color=\"text.secondary\" component=\"div\">\n {aiSitePartialCopy(job)}\n </Typography>\n )}\n {/* A build, item by item: where each stands, and what became of its credits (AGL-3616). */}\n {job.items?.length ? (\n <Box component=\"ul\" aria-label=\"Items\" sx={{ m: 0, mt: 0.5, pl: 2 }}>\n {aiBuildItemRows(job).map((row) => (\n <Typography key={row.slot} component=\"li\" variant=\"caption\" data-item-state={row.state}>\n {`${row.label} — ${ITEM_STATE_LABELS[row.state]}`}\n {row.detail ? `. ${row.detail}` : ''}\n </Typography>\n ))}\n </Box>\n ) : null}\n {aiBuildCanRetry(job) ? (\n <Button\n size=\"small\"\n variant=\"contained\"\n disabled={resuming === job.id}\n onClick={() => void resume(job, { retry: 'failed-items' })}\n sx={{ mt: 0.5 }}\n >\n {aiBuildRetryLabel(job)}\n </Button>\n ) : null}\n {retryPrompt?.jobId === job.id ? (\n <AiCreditsPromptNotice\n prompt={retryPrompt.prompt}\n noun=\"build\"\n orgSlug={orgSlug}\n busy={resuming === job.id}\n onBuildWhatFits={() => void resume(job, { retry: 'failed-items', creditsConfirmed: true })}\n />\n ) : null}\n {/* Waiting for an ID only the person has (AGL-3978): asked here, answered onto the plan. */}\n {job.status === 'needs_input' && job.input ? (\n <AiJobInputForm job={{ ...job, input: job.input }} orgId={orgId} user={user} onJob={patchJob} />\n ) : /* Paused by the meter (AGL-3722): Resume carries on from where it stopped. */\n job.status === 'needs_input' ? (\n <Stack direction=\"row\" spacing={1} sx={{ mt: 0.5 }}>\n <Button size=\"small\" variant=\"contained\" disabled={resuming === job.id} onClick={() => void resume(job)}>\n {'Resume'}\n </Button>\n <Button size=\"small\" component={AppLink} href={aiCreditsBillingHref(orgSlug)}>\n {'Upgrade'}\n </Button>\n </Stack>\n ) : null}\n {job.siteRemoved ? (\n // Its empty site was removed (AGL-3936): Create site, with the same answers.\n <>\n <Typography variant=\"caption\" color=\"text.secondary\" component=\"div\">\n {AI_SITE_REMOVED_ROW_COPY}\n </Typography>\n {aiCreateSiteHref(orgSlug) && job.siteInputs ? (\n <Button\n size=\"small\"\n variant=\"contained\"\n component={AppLink}\n href={aiCreateSiteHref(orgSlug) as string}\n onClick={() => stashAiSiteStartAnswers(job.siteInputs)}\n sx={{ mt: 0.5 }}\n >\n {AI_SITE_START_AGAIN_LABEL}\n </Button>\n ) : null}\n </>\n ) : restartHref(job) ? (\n <Button size=\"small\" variant=\"contained\" component={AppLink} href={restartHref(job) as string} sx={{ mt: 0.5 }}>\n {'Try again'}\n </Button>\n ) : null}\n {/* What a finished job built, first (AGL-3593). */}\n {primary ? (\n <Button\n size=\"small\"\n variant=\"contained\"\n component={AppLink}\n href={primary.href}\n sx={{ mt: 0.5 }}\n >\n {primary.label}\n </Button>\n ) : null}\n {job.outputs.map((output, index) => {\n const href = aiJobOutputHref(output, orgSlug)\n const navigation = aiJobNavigationProposal(output)\n return (\n <Box key={`${output.resource}:${output.id}:${index}`} sx={{ mt: 0.5 }}>\n {output.resource === 'insight' ? (\n <Button size=\"small\" onClick={() => setInsightOpen(output.id)}>\n View answer\n </Button>\n ) : href ? (\n <AppLink componentVariant=\"naked\" href={href}>\n Open draft — {output.label}\n </AppLink>\n ) : output.text ? (\n <Typography\n variant=\"body2\"\n component=\"pre\"\n sx={{ whiteSpace: 'pre-wrap', fontFamily: 'inherit', m: 0 }}\n >\n {output.text}\n </Typography>\n ) : (\n <Typography variant=\"caption\" color=\"text.secondary\">\n {output.label}\n </Typography>\n )}\n {output.load ? (\n <Typography variant=\"caption\" color=\"text.secondary\" component=\"div\">\n About {formatBytes(output.load.totalBytes)} on a first visit\n </Typography>\n ) : null}\n {output.note ? (\n <Typography variant=\"caption\" color=\"text.secondary\" component=\"div\">\n {output.note}\n </Typography>\n ) : null}\n {navigation ? (\n <Typography variant=\"caption\" color=\"text.secondary\" component=\"div\">\n Add “{navigation}” to your navigation once the page is live.\n </Typography>\n ) : null}\n </Box>\n )\n })}\n <AiJobPlan\n job={job}\n onResume={(target, options) => void resume(target, options)}\n busy={resuming === job.id}\n staff={isStaff}\n user={user}\n orgSlug={orgSlug}\n />\n </Box>\n )\n })}\n </Stack>\n </Collapse>\n {/*\n The brief dialog (AGL-2907). It starts a job and closes; the list\n below it is the only place the job is watched, so an open list reads\n the new job back as soon as the dialog hands it over.\n */}\n {insightOpen !== null && (\n <AiInsightDialog\n open\n onClose={() => {\n setInsightOpen(null)\n if (expanded) void load()\n }}\n orgId={orgId}\n orgSlug={orgSlug}\n hostId={insight?.host ? (hostId ?? null) : null}\n host={insight?.host ?? null}\n surface={insight?.surface ?? 'analytics'}\n user={user}\n uid={(user as { uid?: string } | null | undefined)?.uid ?? null}\n jobId={insightOpen === 'ask' ? null : insightOpen}\n />\n )}\n {hostId && (\n <AiPageBriefDialog\n open={describing}\n onClose={() => {\n setDescribing(false)\n if (expanded) void load()\n }}\n orgId={orgId}\n hostId={hostId}\n user={user}\n orgSlug={orgSlug}\n isStaff={isStaff}\n />\n )}\n </Box>\n )\n}\n\nexport default AssistJobsDrawer\n"],"names":["checkEntitlement","trackEvent","formatBytes","AI_JOB_TERMINAL_STATUSES","mdiChevronDown","mdiChevronUp","pluginDocsHelp","AppLink","HelpTip","MdiIcon","authorizedFetch","Box","Button","Chip","CircularProgress","Collapse","IconButton","Stack","Typography","useCallback","useEffect","useRef","useState","AI_JOB_PHASE_LABELS","aiJobActivityCounts","aiJobPhase","aiJobsHeaderChips","AiJobInputForm","resumeAiJobRequest","useAiJobCancel","aiBuildCanRetry","aiBuildItemRows","aiBuildRetryCreditRange","aiSitePartialCopy","aiCreditRangeText","AiCreditsPromptNotice","publishAiJob","AiPageBriefDialog","AiInsightDialog","AiJobPlan","aiCreditsBillingHref","aiJobOutputHref","aiJobPrimaryLink","aiSiteBuildHref","aiJobRefundCopy","AI_SITE_REMOVED_ROW_COPY","AI_SITE_START_AGAIN_LABEL","aiCreateSiteHref","stashAiSiteStartAnswers","readEventFrames","aiBuildRetryLabel","job","range","LIST_LIMIT","BRIEF_PREVIEW_CHARS","PHASE_COLOR","queued","planning","building","attention","done","failed","canceled","STATE_COLOR","running","ITEM_STATE_LABELS","active","waiting","skipped","HIGHLIGHT_MS","aiJobRestartHref","input","kind","status","siteInputs","hostId","subdomain","exec","pathname","href","orgSlug","id","netCredits","Math","max","creditsSpent","refundedCredits","aiJobNavigationProposal","output","resource","navigation","proposal","label","trim","AssistJobsDrawer","orgId","org","orgReady","user","visible","isStaff","insight","inFlight","focus","entitled","expanded","setExpanded","toggledRef","highlight","setHighlight","listRef","jobs","setJobs","loading","setLoading","notice","setNotice","describing","setDescribing","insightOpen","setInsightOpen","trackedRef","Set","watchingRef","patchJob","next","prior","index","findIndex","slice","copy","includes","current","has","add","credits","load","response","encodeURIComponent","ok","payload","json","catch","String","error","anyInFlight","length","focusSeq","seq","focusJobId","jobId","expandedRef","highlightListed","some","row","undefined","Array","from","querySelectorAll","find","element","dataset","scrollIntoView","block","behavior","timer","setTimeout","clearTimeout","watched","watchedId","controller","AbortController","watch","again","signal","aborted","body","event","filter","finally","abort","canceling","onJob","resuming","setResuming","retryPrompt","setRetryPrompt","resume","options","retry","prompt","chips","sx","mb","borderBottom","borderColor","pb","direction","spacing","alignItems","variant","flexGrow","map","chip","size","color","state","ml","anchor","excerpt","onClick","aria-label","aria-expanded","path","fontSize","in","unmountOnExit","component","mt","dialog","ref","role","restartHref","window","location","stepsDone","steps","step","terminal","phase","primary","highlighted","data-ai-job-id","aria-current","borderRadius","bgcolor","outline","outlineColor","transition","theme","transitions","create","duration","standard","px","py","name","disabled","Boolean","cancelRequested","busyJobId","ask","wordBreak","brief","items","m","pl","data-item-state","detail","slot","noun","busy","onBuildWhatFits","creditsConfirmed","siteRemoved","outputs","componentVariant","text","whiteSpace","fontFamily","totalBytes","note","onResume","target","staff","open","onClose","host","surface","uid"],"mappings":"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"}
@@ -16,7 +16,7 @@
16
16
  */ 'use client';
17
17
  import { _ as _extends } from "@swc/helpers/_/_extends";
18
18
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
19
- import { canvas, checkEntitlement, lockdownRefusalText, parseLockdownRefusal } from "@aglyn/aglyn";
19
+ import { canvas, checkEntitlement, lockdownRefusalText, parseLockdownRefusal, planLabelGrantingFeature } from "@aglyn/aglyn";
20
20
  import { editorSessionsRevision, openEditorSession, subscribeEditorSessions } from "@aglyn/aglyn/plugin-manager/editor-sessions";
21
21
  import { trackEvent } from "@aglyn/aglyn/app-utils/analytics-events";
22
22
  import { CANVAS_ROOT_ELEMENT_ID } from "@aglyn/aglyn/foundation/constants/canvas";
@@ -507,7 +507,7 @@ function saveThread(orgId, messages) {
507
507
  });
508
508
  });
509
509
  export function AssistPanelComponent(props) {
510
- var _ref, _ref1;
510
+ var _ref, _ref1, _planLabelGrantingFeature;
511
511
  const { org, orgId, orgReady, scopedOrgId, orgSlug, hostId, productName, assistVisible, assistStaffPreview, generativeVisible, isStaff, aiPermissions: ai } = props;
512
512
  const verdict = {
513
513
  visible: assistVisible,
@@ -1174,8 +1174,12 @@ export function AssistPanelComponent(props) {
1174
1174
  'link the docs and the console page to use.',
1175
1175
  orgReady && !entitled && !isStaff && /*#__PURE__*/ _jsxs(_Fragment, {
1176
1176
  children: [
1177
- ' ',
1178
- "Free workspaces get a limited number of messages a day; Pro adds page-aware guidance."
1177
+ ' Free workspaces get a limited number of messages a day. ',
1178
+ `Page-aware guidance is included from ${(_planLabelGrantingFeature = planLabelGrantingFeature('aiAssist')) != null ? _planLabelGrantingFeature : 'a paid plan'}. `,
1179
+ billingSlug ? /*#__PURE__*/ _jsx(AppLink, {
1180
+ href: `/${billingSlug}/billing#plans`,
1181
+ children: 'Upgrade'
1182
+ }) : null
1179
1183
  ]
1180
1184
  })
1181
1185
  ]