@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/model/ai-build-job.ts"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n pluginAiCapabilityArgsProblems,\n type PluginAiCapability,\n} from '@aglyn/aglyn/plugin-manager/plugin-ai-capabilities'\nimport type { PluginDraftRecord } from '@aglyn/aglyn/plugin-manager/plugin-resource-drafts'\nimport {\n AI_PLAN_NEW_REF_PREFIX,\n isAiPlanNewRef,\n type AiBuildItem,\n type AiBuildPlan,\n type AiBuildPlanCreate,\n type AiBuildPlanCreateKind,\n type AiBuildPlanScreen,\n} from './ai-build-plan'\nimport type { AiJobItemLedger, AiJobItemStatus } from './ai-jobs.types'\nimport {\n AI_BUILD_STORE_OP,\n AI_BUILD_STORE_PAGES_LABEL,\n AI_BUILD_STORE_SLOT,\n aiBuildMakesStore,\n aiBuildStorePagesAdded,\n} from './ai-build-store-pages'\nimport {\n AI_SITE_HOME_FIRST_LABEL,\n AI_SITE_MAX_SECTIONS,\n AI_SITE_PASS_CREDITS,\n aiCreationMeasuredCredits,\n aiJobPlanCreditEstimate,\n aiJobPlanCreditRange,\n aiSitePlanIsHome,\n aiStandaloneScreenCreditRange,\n} from './ai-site-job'\nimport {\n AI_CREDIT_RANGE_ZERO,\n AI_MEASURED_PASS_CREDITS,\n aiCreditRangeAdd,\n aiCreditRangeOf,\n aiCreditRangeOrdered,\n type AiCreditRange,\n type AiCreditsSmaller,\n} from './ai-credit-estimate'\n\n/**\n * What a `build` job is (AGL-3616): one request — \"a few pages, a contact\n * form and a way to book me\" — planned as creations, pages and items, built\n * one UNIT a pass in dependency order, and settled ITEM BY ITEM.\n *\n * A build is a generalized site scaffold. Every unit is handed to what\n * already builds that kind of thing — a page to the page step, a form to the\n * form step, another plugin's resource to that plugin's draft writer — so a\n * build cannot drift from what it builds. What is new is the settlement: one\n * failed unit does not end the job. It gives back its own spend, the units\n * that depended on it are built without it (or skipped, when they cannot\n * stand without it), and the job is `done` when anything was delivered.\n *\n * This module is the build's MODEL — its units, their order, how a failure\n * travels to what depends on it, what it is estimated to cost, and the\n * ledger arithmetic — and does no I/O, so the step, the machine, the doors\n * and the console read one vocabulary.\n */\n\n/** How much one build holds: what one proposal can describe and one person can read. */\nexport const AI_BUILD_LIMITS = {\n /** Creations, pages and items together. */\n units: 16,\n pages: 8,\n /** A Free workspace's pages. */\n freePages: 2,\n} as const\n\n/**\n * What a Free build's plan card says when it holds as many pages as a Free\n * build makes (AGL-3722): the plan is told the cap and plans the first pages\n * a request asks for, so a request for three — \"About us, Custom cakes and\n * Catering\", 2026-10-10 — came back as two with nothing saying why. `null`\n * when the plan holds fewer, or on a paid workspace.\n */\nexport function aiBuildFreePageCapNote(plan: Pick<AiBuildPlan, 'screens'>, freeTaste: boolean): string | null {\n const cap = AI_BUILD_LIMITS.freePages\n if (!freeTaste || plan.screens.length < cap) return null\n return `A Free workspace’s build makes up to ${cap} pages at a time. If you asked for more, ask Assist for the rest once this build is done.`\n}\n\n/** What a build creates through its `create` list; everything else beyond pages is an item. */\nexport const AI_BUILD_CREATE_KINDS: readonly AiBuildPlanCreateKind[] = ['layout', 'form', 'component', 'email']\n\n/**\n * The operations a build plans through `create` and `screens` rather than\n * `items`: an item naming one is a plan that put it in the wrong list.\n */\nexport const AI_BUILD_STRUCTURAL_OPS: readonly string[] = ['page', ...AI_BUILD_CREATE_KINDS]\n\n/**\n * What a build hands an item it made before it (AGL-3728): its pages, by the\n * title the plan gave each and the id it was written under, and its layouts,\n * by name. An item's `new:<title>` destinations are read against it.\n */\nexport const AI_BUILD_MADE_INPUT = 'buildMade'\n\nexport interface AiBuildMade {\n pages: Array<{ title: string; id: string }>\n layouts: Array<{ name: string; id: string }>\n}\n\n/** The job input a build's Assist proposal sets when the brief asked to publish. */\nexport const AI_BUILD_PUBLISH_INPUT = 'publish'\n\n/** A unit of a build: a creation, a page, or an item. */\nexport interface AiBuildUnit {\n slot: string\n /** The capability operation that builds it. */\n op: string\n label: string\n creation?: AiBuildPlanCreate\n screen?: AiBuildPlanScreen\n item?: AiBuildItem\n /** The slots it is built after, in plan order. */\n deps: string[]\n}\n\n/** The operation a creation is built as. */\nfunction creationOp(creation: AiBuildPlanCreate): string {\n return creation.kind\n}\n\n/** A plan's `new:<name>` names, each to the slot that builds it. */\nfunction namedSlots(plan: AiBuildPlan): Map<string, string> {\n const slots = new Map<string, string>()\n plan.create.forEach((creation, index) => {\n if (AI_BUILD_CREATE_KINDS.includes(creation.kind)) slots.set(creation.name.toLowerCase(), `c${index}`)\n })\n for (const item of plan.items ?? []) slots.set(item.name.toLowerCase(), item.slot)\n return slots\n}\n\n/** The name a `new:<name>` reference gives, lowercased. */\nexport function aiBuildRefName(ref: string): string {\n return ref.slice(AI_PLAN_NEW_REF_PREFIX.length).trim().toLowerCase()\n}\n\n/**\n * The `new:<name>` references an item's arguments make (AGL-3728): an\n * argument that is one, or the destination after `=>` in an entry such as a\n * menu item's `About => new:About`. Read from the arguments, never from the\n * model's `dependsOn`, so what an item links is always built before it.\n */\nexport function aiBuildItemArgRefs(args: Readonly<Record<string, unknown>> | null | undefined): string[] {\n const refs: string[] = []\n const take = (value: unknown) => {\n if (typeof value !== 'string') return\n for (const part of [value, value.split('=>').slice(-1)[0] ?? '']) {\n const ref = part.trim()\n if (isAiPlanNewRef(ref) && !refs.includes(ref)) refs.push(ref)\n }\n }\n for (const value of Object.values(args ?? {})) {\n if (Array.isArray(value)) value.forEach(take)\n else take(value)\n }\n return refs\n}\n\n/** Every reference a page makes: its layout, template, starting page and what its sections place. */\nexport function aiBuildScreenRefs(screen: AiBuildPlanScreen): string[] {\n return [\n screen.layout,\n screen.template,\n screen.duplicateOf,\n ...screen.sections.flatMap((section) => section.uses),\n ].filter((ref): ref is string => typeof ref === 'string' && ref.length > 0)\n}\n\n/**\n * The units a plan implies, in plan order: creations, then items, then\n * pages — the order a member reads them in, and the one a page that places\n * a creation or an item is built after anyway. `aiBuildOrder` sorts them on\n * their dependencies.\n */\nexport function aiBuildUnits(plan: AiBuildPlan): AiBuildUnit[] {\n const slots = namedSlots(plan)\n // A page, by the title the plan gave it: what an item's arguments may link\n // as `new:<title>` (a menu item, AGL-3728), built before the item.\n const pageSlots = new Map<string, string>()\n plan.screens.forEach((screen, index) => {\n const title = screen.title.trim().toLowerCase()\n if (title && !pageSlots.has(title)) pageSlots.set(title, `p${index}`)\n })\n const depsOf = (refs: readonly (string | null)[], self: string, pages = false): string[] => {\n const deps: string[] = []\n for (const ref of refs) {\n if (!isAiPlanNewRef(ref)) continue\n const slot = slots.get(aiBuildRefName(ref)) ?? (pages ? pageSlots.get(aiBuildRefName(ref)) : undefined)\n if (slot && slot !== self && !deps.includes(slot)) deps.push(slot)\n }\n return deps\n }\n const units: AiBuildUnit[] = []\n plan.create.forEach((creation, index) => {\n if (!AI_BUILD_CREATE_KINDS.includes(creation.kind)) return\n const slot = `c${index}`\n // A form is built after the dataset it writes to (AGL-3616).\n units.push({\n slot,\n op: creationOp(creation),\n label: creation.name,\n creation,\n deps: depsOf([creation.duplicateOf, creation.kind === 'form' ? (creation.writesTo ?? null) : null], slot),\n })\n })\n for (const item of plan.items ?? []) {\n units.push({\n slot: item.slot,\n op: item.op,\n label: item.name,\n item,\n // What it depends on, and what its arguments link as `new:` (AGL-3728).\n deps: depsOf([...item.dependsOn, ...aiBuildItemArgRefs(item.args)], item.slot, true),\n })\n }\n plan.screens.forEach((screen, index) => {\n const slot = `p${index}`\n units.push({ slot, op: 'page', label: screen.title, screen, deps: depsOf(aiBuildScreenRefs(screen), slot) })\n })\n // A store's own pages (AGL-3676), added by the platform: last, so every\n // planned page keeps the first claim on the site's pages allowance.\n if (aiBuildStorePagesAdded(plan).length) {\n units.push({ slot: AI_BUILD_STORE_SLOT, op: AI_BUILD_STORE_OP, label: AI_BUILD_STORE_PAGES_LABEL, deps: [] })\n }\n return units\n}\n\n/** Whether a unit is one the platform adds rather than the plan (AGL-3676): a store's own pages. */\nexport function aiBuildUnitIsPlatform(unit: Pick<AiBuildUnit, 'op'>): boolean {\n return unit.op === AI_BUILD_STORE_OP\n}\n\n/**\n * The units in an order that builds every dependency before what depends on\n * it, plan order otherwise; `null` when the dependencies hold a cycle.\n */\nexport function aiBuildOrder(units: readonly AiBuildUnit[]): AiBuildUnit[] | null {\n const ordered: AiBuildUnit[] = []\n const placed = new Set<string>()\n const known = new Set(units.map((unit) => unit.slot))\n while (ordered.length < units.length) {\n const next = units.find(\n (unit) => !placed.has(unit.slot) && unit.deps.every((dep) => placed.has(dep) || !known.has(dep)),\n )\n if (!next) return null\n ordered.push(next)\n placed.add(next.slot)\n }\n return ordered\n}\n\n/**\n * What is wrong with a plan's references as a build reads them: a\n * `new:<name>` an item depends on that nothing in the plan makes, and a\n * cycle. Each is a sentence the plan's one re-ask carries.\n */\nexport function aiBuildGraphProblems(plan: AiBuildPlan): string[] {\n const problems: string[] = []\n const slots = namedSlots(plan)\n for (const item of plan.items ?? []) {\n for (const ref of item.dependsOn) {\n if (!isAiPlanNewRef(ref)) continue\n if (!slots.has(aiBuildRefName(ref))) {\n problems.push(`The item \"${item.name}\" depends on ${ref}, which the plan never makes. Declare it, or take it out of dependsOn.`)\n } else if (aiBuildRefName(ref) === item.name.toLowerCase()) {\n problems.push(`The item \"${item.name}\" depends on itself. Take it out of its own dependsOn.`)\n }\n }\n }\n if (!aiBuildOrder(aiBuildUnits(plan))) {\n problems.push('The plan’s dependencies go round in a circle, so nothing in the circle can be built first. Make one of them depend on nothing.')\n }\n return problems\n}\n\n/** The operations a build may plan, as the registry and the gates left them, by op. */\nexport type AiBuildOps = ReadonlyMap<string, PluginAiCapability>\n\n/** How many pages a build may hold on this workspace. */\nexport function aiBuildPageLimit(freeTaste: boolean | null | undefined): number {\n return freeTaste ? AI_BUILD_LIMITS.freePages : AI_BUILD_LIMITS.pages\n}\n\n/**\n * Why a build cannot build a plan of this shape, in a sentence a member\n * reads; `null` when it can. Held to the plan with the one re-ask (the plan\n * step's scope), and again by the doors before a confirmed plan runs.\n * `ops` is what may be planned on this site; absent, items are not judged\n * against the registry (a console reading a kept plan).\n */\nexport function aiBuildPlanShapeRefusal(\n plan: AiBuildPlan,\n options: { freeTaste?: boolean; ops?: AiBuildOps } = {},\n): string | null {\n // What the platform adds beside the plan (a store's own pages) is no part of its size.\n const units = aiBuildUnits(plan).filter((unit) => !aiBuildUnitIsPlatform(unit))\n if (!units.length) return 'This plan builds nothing. Describe what to build again.'\n if (units.length > AI_BUILD_LIMITS.units) {\n return `This plan builds ${units.length} things, and one build holds ${AI_BUILD_LIMITS.units}. Ask for the rest in a second request.`\n }\n const pages = aiBuildPageLimit(options.freeTaste)\n if (plan.screens.length > pages) {\n return options.freeTaste\n ? `This plan builds ${plan.screens.length} pages, and a Free workspace's build makes at most ${pages}. Paid plans can build more.`\n : `This plan builds ${plan.screens.length} pages, and one build makes at most ${pages}.`\n }\n const slugs = new Set<string>()\n for (const screen of plan.screens) {\n if (!screen.sections.length) return `The page “${screen.title}” has no sections to build.`\n if (screen.sections.length > AI_SITE_MAX_SECTIONS) {\n return `The page “${screen.title}” has ${screen.sections.length} sections, and a built page holds ${AI_SITE_MAX_SECTIONS}.`\n }\n const slug = screen.slug.trim().toLowerCase()\n if (slugs.has(slug)) return `Two pages in this plan share the address ${screen.slug}.`\n slugs.add(slug)\n }\n for (const creation of plan.create) {\n if (!AI_BUILD_CREATE_KINDS.includes(creation.kind)) {\n return `A build does not create ${creation.kind === 'theme-change' ? 'theme changes' : `${creation.kind}s`} (“${creation.name}”). Take it out of create.`\n }\n }\n const graph = aiBuildGraphProblems(plan)\n if (graph.length) return graph[0]\n const ops = options.ops\n const counts = new Map<string, number>()\n for (const unit of units) counts.set(unit.op, (counts.get(unit.op) ?? 0) + 1)\n for (const item of plan.items ?? []) {\n if (AI_BUILD_STRUCTURAL_OPS.includes(item.op)) {\n return item.op === 'page'\n ? `“${item.name}” is a page: plan it in screens, not items.`\n : `“${item.name}” is ${item.op === 'email' ? 'an' : 'a'} ${item.op}: plan it in create, not items.`\n }\n if (!ops) continue\n const capability = ops.get(item.op)\n if (!capability) return `Nothing on this site can make “${item.name}” (${item.op}). Take it out of items.`\n if (options.freeTaste && !capability.freeAllowed) {\n return `A Free workspace cannot have ${aiArticle(capability.noun)} made (“${item.name}”). Take it out of items.`\n }\n const problems = pluginAiCapabilityArgsProblems(capability.argsSchema, item.args)\n if (problems.length) return `The arguments of “${item.name}” do not read: ${problems.join('; ')}.`\n }\n if (ops) {\n for (const [op, count] of counts) {\n const capability = ops.get(op)\n if (capability && count > capability.maxPerPlan) {\n return `This plan makes ${count} of “${capability.noun}”, and one build makes at most ${capability.maxPerPlan}.`\n }\n }\n }\n return null\n}\n\n/**\n * What the person must still say before this plan can be built, as the\n * questions its operations ask (`missingInput`), or `null` when nothing is\n * missing: an item the planner kept with nothing it may build from — a\n * tracking change naming no id, AGL-3751 — is asked about, never built\n * empty or from a value the planner made up. Not a plan rule: a re-ask\n * cannot supply what only the person knows, so the plan is not kept and\n * the build answers with the question.\n */\nexport function aiBuildPlanMissingInput(plan: AiBuildPlan, ops: AiBuildOps | null | undefined): string | null {\n if (!ops) return null\n const questions: string[] = []\n for (const item of plan.items ?? []) {\n const question = ops.get(item.op)?.missingInput?.({ name: item.name, why: item.why, args: item.args })\n if (question && !questions.includes(question)) questions.push(question)\n }\n return questions.length ? questions.join(' ') : null\n}\n\n/** \"a booking service\", \"an email design\". */\nexport function aiArticle(noun: string): string {\n return `${/^[aeiou]/i.test(noun) ? 'an' : 'a'} ${noun}`\n}\n\n/** The passes one unit is estimated at: a page's sections and its listing, one for a creation. */\nfunction unitPasses(unit: AiBuildUnit): number {\n if (unit.screen) return unit.screen.sections.length + 1\n return 1\n}\n\n/**\n * About what one unit costs, in credits: a page or a creation by the passes\n * it implies at the nominal credits a pass is held against, as a site's are;\n * an item by its capability's own estimate, recorded on the plan when it was\n * kept.\n */\nexport function aiBuildUnitCreditEstimate(unit: AiBuildUnit, ops?: AiBuildOps): number {\n // A store's own pages are written by code, with no model: no credits (AGL-3676).\n if (aiBuildUnitIsPlatform(unit)) return 0\n if (unit.item) {\n if (typeof unit.item.credits === 'number') return unit.item.credits\n const capability = ops?.get(unit.item.op)\n if (capability) return Math.max(0, Math.floor(capability.estimateCredits(unit.item.args)))\n return AI_SITE_PASS_CREDITS\n }\n return unitPasses(unit) * AI_SITE_PASS_CREDITS\n}\n\n/**\n * About what a build costs, in credits: every unit's estimate, or only the\n * units named in `slots` — what Try again shows. The ceiling a member\n * confirms; the meter charges what actually runs.\n */\nexport function aiBuildCreditEstimate(\n plan: AiBuildPlan,\n options: { ops?: AiBuildOps; slots?: ReadonlySet<string> } = {},\n): number {\n return aiBuildUnits(plan)\n .filter((unit) => !options.slots || options.slots.has(unit.slot))\n .reduce((total, unit) => total + aiBuildUnitCreditEstimate(unit, options.ops), 0)\n}\n\n/**\n * About what a job of this kind costs to build from its plan: a build's\n * units, every other planned kind as `aiJobPlanCreditEstimate` counts it.\n */\nexport function aiJobCreditEstimate(kind: string, plan: AiBuildPlan): number {\n return kind === 'build' ? aiBuildCreditEstimate(plan) : aiJobPlanCreditEstimate(kind, plan)\n}\n\n/**\n * What one unit is likely to cost, its p90 and its ceiling (AGL-3722): a page\n * as a page written on its own measured (a fixed cost and one per section), a creation at what its kind\n * measured, an item at the measured pass times the passes its capability\n * estimates (none for a draft another plugin writes, which asks no model).\n * The ceiling is `aiBuildUnitCreditEstimate`, unchanged.\n */\nexport function aiBuildUnitCreditRange(unit: AiBuildUnit, ops?: AiBuildOps): AiCreditRange {\n const ceiling = aiBuildUnitCreditEstimate(unit, ops)\n // A build writes each page on its own, never in a site start's warm run (AGL-3722).\n if (unit.screen) return aiStandaloneScreenCreditRange(unit.screen.sections.length)\n if (unit.creation) return aiCreditRangeOf(aiCreationMeasuredCredits(unit.creation.kind, { standalone: true }), ceiling)\n const passes = Math.ceil(ceiling / AI_SITE_PASS_CREDITS)\n return aiCreditRangeOf(\n { median: passes * AI_MEASURED_PASS_CREDITS.median, p90: passes * AI_MEASURED_PASS_CREDITS.p90 },\n ceiling,\n )\n}\n\n/**\n * What a build is likely to cost, its p90 and its ceiling (AGL-3722): every\n * unit's range, or only the units named in `slots` — what Try again runs.\n * The plan card, Try again and the Free admission all read this; the meter\n * charges what actually runs.\n */\nexport function aiBuildCreditRange(\n plan: AiBuildPlan,\n options: { ops?: AiBuildOps; slots?: ReadonlySet<string> } = {},\n): AiCreditRange {\n return aiCreditRangeOrdered(\n aiBuildUnits(plan)\n .filter((unit) => !options.slots || options.slots.has(unit.slot))\n .reduce((total, unit) => aiCreditRangeAdd(total, aiBuildUnitCreditRange(unit, options.ops)), AI_CREDIT_RANGE_ZERO),\n )\n}\n\n/** `aiJobCreditEstimate` as a range (AGL-3722). */\nexport function aiJobCreditRange(kind: string, plan: AiBuildPlan): AiCreditRange {\n return kind === 'build' ? aiBuildCreditRange(plan) : aiJobPlanCreditRange(kind, plan)\n}\n\n/**\n * A smaller first build (AGL-3722): the plan's home page — its first page\n * where it has no home — and only what that page needs, transitively: the\n * layout it is drawn in, the form and anything else its sections place.\n * Every other page, and what only they needed, waits for a later request.\n * `null` when the plan has no page, or when the smaller plan is the whole one.\n */\nexport function aiBuildFirstPagePlan<T extends AiBuildPlan>(plan: T): T | null {\n if (!plan.screens.length) return null\n const index = Math.max(0, plan.screens.findIndex(aiSitePlanIsHome))\n const units = aiBuildUnits(plan).filter((unit) => !aiBuildUnitIsPlatform(unit))\n const bySlot = new Map(units.map((unit) => [unit.slot, unit]))\n const keep = new Set<string>()\n const queue = [`p${index}`]\n while (queue.length) {\n const slot = queue.shift() as string\n if (keep.has(slot)) continue\n keep.add(slot)\n for (const dep of bySlot.get(slot)?.deps ?? []) queue.push(dep)\n }\n if (keep.size === units.length) return null\n const screen = plan.screens[index]\n const create = plan.create.filter((creation, at) => !AI_BUILD_CREATE_KINDS.includes(creation.kind) || keep.has(`c${at}`))\n const items = (plan.items ?? []).filter((item) => keep.has(item.slot))\n const kept = new Set([screen.slug, ...create.map((entry) => `${AI_PLAN_NEW_REF_PREFIX}${entry.name}`)])\n const smaller: T = {\n ...plan,\n create,\n screens: [screen],\n ...(plan.items ? { items } : {}),\n ...(plan.embeds ? { embeds: plan.embeds.filter((embed) => kept.has(embed.where)) } : {}),\n }\n // The store's own pages stay only while the smaller build still makes a store (AGL-3676).\n if (smaller.storePages && !aiBuildMakesStore(smaller)) delete smaller.storePages\n return smaller\n}\n\n/** The smaller first build a build that does not fit is offered (AGL-3722), with its range; `null` when there is none. */\nexport function aiBuildSmaller(plan: AiBuildPlan, ops?: AiBuildOps): AiCreditsSmaller | null {\n const smaller = aiBuildFirstPagePlan(plan)\n if (!smaller) return null\n const screen = smaller.screens[0]\n const label = aiSitePlanIsHome(screen) ? AI_SITE_HOME_FIRST_LABEL : `Build the ${screen.title} page first`\n return { label, ...aiBuildCreditRange(smaller, { ops }) }\n}\n\n/** A fresh ledger: one pending row per unit, first attempt. */\nexport function aiBuildInitialLedger(units: readonly AiBuildUnit[]): AiJobItemLedger[] {\n return units.map((unit) => ({\n slot: unit.slot,\n op: unit.op,\n label: unit.label,\n status: 'pending',\n attempt: 1,\n creditsSpent: 0,\n attemptCredits: 0,\n creditsRefunded: 0,\n failure: null,\n outputs: [],\n }))\n}\n\nconst OPEN: readonly AiJobItemStatus[] = ['pending', 'running']\n\n/** Whether an item is still to be built. */\nexport function aiBuildItemOpen(row: Pick<AiJobItemLedger, 'status'>): boolean {\n return OPEN.includes(row.status)\n}\n\n/** Whether an item delivered: built as planned, or built without something that failed. */\nexport function aiBuildItemDelivered(row: Pick<AiJobItemLedger, 'status'>): boolean {\n return row.status === 'succeeded' || row.status === 'degraded'\n}\n\n/**\n * The next unit to build: the first in build order whose row is still open.\n * Its dependencies come before it, so by then each is settled one way or the\n * other. `null` when nothing is left.\n */\nexport function aiBuildNextUnit(\n ordered: readonly AiBuildUnit[],\n ledger: readonly AiJobItemLedger[],\n): AiBuildUnit | null {\n const rows = new Map(ledger.map((row) => [row.slot, row]))\n return ordered.find((unit) => {\n const row = rows.get(unit.slot)\n return !row || aiBuildItemOpen(row)\n }) ?? null\n}\n\n/** How a unit is built given what its dependencies came to. */\nexport interface AiBuildDegradation {\n /** The unit is not built at all, with the sentence why; nothing is spent. */\n skip: string | null\n /** The failed dependencies that change how it is built. */\n degradedBy: string[]\n /** What the person reads about the change; one per failed dependency. */\n notes: string[]\n /** `new:<name>` references (lowercased names) to leave out. */\n dropped: Set<string>\n /** Brief lines for the unit's own job: what to leave out, and what to place. */\n briefLines: string[]\n}\n\n/**\n * How a unit is built when some of what it depends on failed (AGL-3616).\n *\n * A PAGE is always built: a failed layout falls back to the site's own, a\n * failed form or component is left out of its section, and a failed item a\n * section places (a booking service) takes its block out of the page — each\n * with a note. Any OTHER unit whose dependency failed is skipped when that\n * dependency's capability says `omit` (a campaign whose email design failed\n * has nothing to send), and built without it when it says `fallback`.\n */\nexport function aiBuildDegradation(\n unit: AiBuildUnit,\n context: {\n units: readonly AiBuildUnit[]\n ledger: readonly AiJobItemLedger[]\n ops?: AiBuildOps\n },\n): AiBuildDegradation {\n const rows = new Map(context.ledger.map((row) => [row.slot, row]))\n const bySlot = new Map(context.units.map((one) => [one.slot, one]))\n const result: AiBuildDegradation = { skip: null, degradedBy: [], notes: [], dropped: new Set(), briefLines: [] }\n for (const slot of unit.deps) {\n const dep = bySlot.get(slot)\n const row = rows.get(slot)\n if (!dep || !row || aiBuildItemDelivered(row)) continue\n const noun = dep.creation\n ? aiBuildCreationNoun(dep.creation.kind)\n : (context.ops?.get(dep.op)?.noun ?? dep.op)\n const capability = dep.item ? context.ops?.get(dep.op) : undefined\n const degrade = dep.item?.degrade ?? capability?.degrade ?? (dep.creation?.kind === 'layout' ? 'fallback' : 'omit')\n // A form whose dataset could not be made is built without it (AGL-3616):\n // its submissions reach the Inbox, as any form's do.\n if (aiBuildUnitWritesTo(unit) === dep.label.toLowerCase()) {\n result.degradedBy.push(slot)\n result.notes.push(`Its submissions arrive in the Inbox only: the dataset “${dep.label}” could not be created.`)\n continue\n }\n // An item that links pages this build makes (a menu's entries, AGL-3728)\n // is built with the ones it made and without the ones it could not\n // (AGL-3832), and skipped only when it made none of them.\n const madeAPage = unit.deps.some((one) => {\n const made = rows.get(one)\n return !!bySlot.get(one)?.screen && !!made && aiBuildItemDelivered(made)\n })\n if (!unit.screen && dep.screen && madeAPage) {\n result.degradedBy.push(slot)\n result.dropped.add(dep.label.toLowerCase())\n result.notes.push(`Built without the ${noun} “${dep.label}”: it could not be created.`)\n continue\n }\n if (!unit.screen && degrade === 'omit') {\n result.skip = `Not built: the ${noun} “${dep.label}” it needs could not be created.`\n result.degradedBy.push(slot)\n return result\n }\n result.degradedBy.push(slot)\n result.dropped.add(dep.label.toLowerCase())\n if (dep.creation?.kind === 'layout') {\n result.notes.push(`Built inside the site’s own layout: the layout “${dep.label}” could not be created.`)\n continue\n }\n if (unit.screen) {\n const section = unit.screen.sections.find((one) =>\n one.uses.some((ref) => isAiPlanNewRef(ref) && aiBuildRefName(ref) === dep.label.toLowerCase()),\n )\n // Another item this section places with the same block was built (one\n // of several events, AGL-3743): the block stays, and only this item is\n // missing from what it shows.\n const blockStays = Boolean(\n section &&\n capability?.pageBlocks?.length &&\n aiBuildSectionDeliveredBlocks(section, { ...context, rows, except: slot }).has(aiBuildBlocksKey(capability.pageBlocks)),\n )\n if (blockStays) {\n result.notes.push(`Built without the ${noun} “${dep.label}”: it could not be created.`)\n result.briefLines.push(`Leave the ${noun} “${dep.label}” out of the “${section?.name}” section: it could not be created.`)\n continue\n }\n const blocks = capability?.pageBlocks?.length ? ` the ${capability.pageBlocks.join(' or ')} block` : ''\n result.notes.push(\n `Built without${blocks || ` the ${noun}`}: the ${noun} “${dep.label}” could not be created.`,\n )\n result.briefLines.push(\n `${section ? `Build the “${section.name}” section` : 'Build the page'} without the ${noun} “${dep.label}”${blocks ? ` and without${blocks}` : ''}: it could not be created.`,\n )\n } else {\n result.notes.push(`Built without the ${noun} “${dep.label}”: it could not be created.`)\n }\n }\n return result\n}\n\n/** The dataset a form unit writes to, by its `new:` name lowercased; `null` for any other unit (AGL-3616). */\nexport function aiBuildUnitWritesTo(unit: Pick<AiBuildUnit, 'creation'>): string | null {\n const ref = unit.creation?.kind === 'form' ? unit.creation.writesTo : null\n return isAiPlanNewRef(ref) ? aiBuildRefName(ref) : null\n}\n\n/** What each creation is called in a note. */\nexport function aiBuildCreationNoun(kind: AiBuildPlanCreateKind): string {\n return kind === 'email' ? 'email design' : kind === 'theme-change' ? 'theme change' : kind\n}\n\n/**\n * The brief lines a page is told about the items its sections place and\n * that were built: the block to put there, in the owner's words.\n */\nexport function aiBuildPlacedItemLines(\n unit: AiBuildUnit,\n context: {\n units: readonly AiBuildUnit[]\n ledger: readonly AiJobItemLedger[]\n ops?: AiBuildOps\n /** Operations whose items the platform places itself (a listing), so the page is told nothing of them. */\n placedByCode?: readonly string[]\n },\n): string[] {\n if (!unit.screen) return []\n const rows = new Map(context.ledger.map((row) => [row.slot, row]))\n const lines: string[] = []\n for (const section of unit.screen.sections) {\n // One line per block a section places, naming every built item it shows:\n // a section listing four events places the Event List once (AGL-3743).\n const placed = new Map<string, { blocks: readonly string[]; noun: string; labels: string[] }>()\n for (const { dep, capability } of aiBuildSectionItems(section, context.units, context.ops)) {\n const row = rows.get(dep.slot)\n if (!row || !aiBuildItemDelivered(row)) continue\n if (context.placedByCode?.includes(dep.op)) continue\n const blocks = capability?.pageBlocks ?? []\n if (!blocks.length) continue\n const key = aiBuildBlocksKey(blocks)\n const entry = placed.get(key) ?? { blocks, noun: capability?.noun ?? dep.op, labels: [] }\n entry.labels.push(`“${dep.label}”`)\n placed.set(key, entry)\n }\n for (const { blocks, noun, labels } of placed.values()) {\n const named =\n labels.length === 1\n ? `the ${noun} ${labels[0]}`\n : `the ${noun}s ${labels.slice(0, -1).join(', ')} and ${labels[labels.length - 1]}`\n lines.push(`In the “${section.name}” section, place the ${blocks.join(' or ')} block for ${named}.`)\n }\n }\n return lines\n}\n\n/** The items a page section places, each with its capability, in the order its uses name them. */\nfunction aiBuildSectionItems(\n section: { uses: readonly string[] },\n units: readonly AiBuildUnit[],\n ops: AiBuildOps | undefined,\n): Array<{ dep: AiBuildUnit; capability: PluginAiCapability | undefined }> {\n const found: Array<{ dep: AiBuildUnit; capability: PluginAiCapability | undefined }> = []\n for (const ref of section.uses) {\n if (!isAiPlanNewRef(ref)) continue\n const dep = units.find((one) => one.item && one.item.name.toLowerCase() === aiBuildRefName(ref))\n if (dep?.item) found.push({ dep, capability: ops?.get(dep.op) })\n }\n return found\n}\n\n/** The blocks a section's built items place, each set as one key; `except` leaves one item out. */\nfunction aiBuildSectionDeliveredBlocks(\n section: { uses: readonly string[] },\n context: { units: readonly AiBuildUnit[]; rows: ReadonlyMap<string, AiJobItemLedger>; ops?: AiBuildOps; except: string },\n): Set<string> {\n const keys = new Set<string>()\n for (const { dep, capability } of aiBuildSectionItems(section, context.units, context.ops)) {\n if (dep.slot === context.except || !capability?.pageBlocks?.length) continue\n const row = context.rows.get(dep.slot)\n if (row && aiBuildItemDelivered(row)) keys.add(aiBuildBlocksKey(capability.pageBlocks))\n }\n return keys\n}\n\nfunction aiBuildBlocksKey(blocks: readonly string[]): string {\n return [...blocks].sort().join('|')\n}\n\n/** What a build came to: whether anything was delivered, and whether anything is left. */\nexport function aiBuildSettlement(ledger: readonly AiJobItemLedger[]): {\n delivered: boolean\n open: boolean\n failed: number\n} {\n return {\n delivered: ledger.some(aiBuildItemDelivered),\n open: ledger.some(aiBuildItemOpen),\n failed: ledger.filter((row) => row.status === 'failed').length,\n }\n}\n\n/**\n * The ledger Try again runs (AGL-3616): every failed item back to `pending`\n * on its next attempt, with the items left unbuilt because of it — skipped,\n * or degraded with no draft — and every item the build never reached. An\n * item that succeeded is never run again, and a degraded page that has its\n * draft keeps it, with a note that the page needs an edit. `retried` names\n * the slots that will run, which is what the estimate is shown for.\n */\nexport function aiBuildRetryLedger(\n ledger: readonly AiJobItemLedger[],\n units: readonly AiBuildUnit[],\n): { ledger: AiJobItemLedger[]; retried: string[] } {\n const failed = new Set(ledger.filter((row) => row.status === 'failed').map((row) => row.slot))\n const dependents = new Map<string, string[]>()\n for (const unit of units) {\n for (const dep of unit.deps) dependents.set(dep, [...(dependents.get(dep) ?? []), unit.slot])\n }\n // Everything downstream of a failed item, transitively.\n const downstream = new Set<string>()\n const queue = [...failed]\n while (queue.length) {\n const slot = queue.shift() as string\n for (const next of dependents.get(slot) ?? []) {\n if (downstream.has(next)) continue\n downstream.add(next)\n queue.push(next)\n }\n }\n const retried: string[] = []\n const next = ledger.map((row): AiJobItemLedger => {\n const again =\n row.status === 'failed' ||\n (row.status === 'skipped' && (downstream.has(row.slot) || !(row.degradedBy ?? []).length)) ||\n (row.status === 'degraded' && downstream.has(row.slot) && !row.outputs.length)\n if (again) {\n retried.push(row.slot)\n return {\n ...row,\n status: 'pending',\n attempt: row.attempt + 1,\n attemptCredits: 0,\n failure: null,\n note: null,\n degradedBy: [],\n settledAt: null,\n }\n }\n if (row.status === 'degraded' && downstream.has(row.slot) && row.outputs.length) {\n return {\n ...row,\n note: `${row.note ? `${row.note} ` : ''}It keeps its draft: once the rest is built, edit this page to add what it is missing.`,\n }\n }\n return row\n })\n return { ledger: next, retried }\n}\n\n/**\n * Units read back off a ledger alone (AGL-3616), for a job whose units are\n * not a build plan's — a site scaffold's: each row as its unit, and every\n * page built after the layouts and forms the ledger holds.\n */\nexport function aiLedgerUnits(ledger: readonly AiJobItemLedger[]): AiBuildUnit[] {\n const creations = ledger.filter((row) => row.op === 'layout' || row.op === 'form').map((row) => row.slot)\n return ledger.map((row) => ({\n slot: row.slot,\n op: row.op,\n label: row.label,\n deps: row.op === 'page' ? creations : [],\n }))\n}\n\n/**\n * What the job drawer says under an item another plugin's writer made: a\n * draft, or, for setup its writer saves live (`live`, a CRM pipeline or\n * field, AGL-3746), that it was saved. A writer that went live only when the\n * member may (an event the publishing role publishes, AGL-3755) reports\n * `live: false` for one it kept as a draft, with its `notice` saying why.\n */\nexport function aiBuildItemOutputNote(\n capability: Pick<PluginAiCapability, 'where' | 'live'>,\n written?: Pick<PluginDraftRecord, 'live' | 'notice'>,\n): string {\n const live = written?.live ?? capability.live\n const said = live ? `Live now, in ${capability.where}.` : `A draft, in ${capability.where}.`\n const notice = written?.notice?.trim()\n return notice ? `${said} ${notice}` : said\n}\n"],"names":["pluginAiCapabilityArgsProblems","AI_PLAN_NEW_REF_PREFIX","isAiPlanNewRef","AI_BUILD_STORE_OP","AI_BUILD_STORE_PAGES_LABEL","AI_BUILD_STORE_SLOT","aiBuildMakesStore","aiBuildStorePagesAdded","AI_SITE_HOME_FIRST_LABEL","AI_SITE_MAX_SECTIONS","AI_SITE_PASS_CREDITS","aiCreationMeasuredCredits","aiJobPlanCreditEstimate","aiJobPlanCreditRange","aiSitePlanIsHome","aiStandaloneScreenCreditRange","AI_CREDIT_RANGE_ZERO","AI_MEASURED_PASS_CREDITS","aiCreditRangeAdd","aiCreditRangeOf","aiCreditRangeOrdered","AI_BUILD_LIMITS","units","pages","freePages","aiBuildFreePageCapNote","plan","freeTaste","cap","screens","length","AI_BUILD_CREATE_KINDS","AI_BUILD_STRUCTURAL_OPS","AI_BUILD_MADE_INPUT","AI_BUILD_PUBLISH_INPUT","creationOp","creation","kind","namedSlots","slots","Map","create","forEach","index","includes","set","name","toLowerCase","item","items","slot","aiBuildRefName","ref","slice","trim","aiBuildItemArgRefs","args","refs","take","value","part","split","push","Object","values","Array","isArray","aiBuildScreenRefs","screen","layout","template","duplicateOf","sections","flatMap","section","uses","filter","aiBuildUnits","pageSlots","title","has","depsOf","self","deps","get","undefined","op","label","writesTo","dependsOn","aiBuildUnitIsPlatform","unit","aiBuildOrder","ordered","placed","Set","known","map","next","find","every","dep","add","aiBuildGraphProblems","problems","aiBuildPageLimit","aiBuildPlanShapeRefusal","options","counts","slugs","slug","graph","ops","capability","freeAllowed","aiArticle","noun","argsSchema","join","count","maxPerPlan","aiBuildPlanMissingInput","questions","question","missingInput","why","test","unitPasses","aiBuildUnitCreditEstimate","credits","Math","max","floor","estimateCredits","aiBuildCreditEstimate","reduce","total","aiJobCreditEstimate","aiBuildUnitCreditRange","ceiling","standalone","passes","ceil","median","p90","aiBuildCreditRange","aiJobCreditRange","aiBuildFirstPagePlan","findIndex","bySlot","keep","queue","shift","size","at","kept","entry","smaller","embeds","embed","where","storePages","aiBuildSmaller","aiBuildInitialLedger","status","attempt","creditsSpent","attemptCredits","creditsRefunded","failure","outputs","OPEN","aiBuildItemOpen","row","aiBuildItemDelivered","aiBuildNextUnit","ledger","rows","aiBuildDegradation","context","one","result","skip","degradedBy","notes","dropped","briefLines","aiBuildCreationNoun","degrade","aiBuildUnitWritesTo","madeAPage","some","made","blockStays","Boolean","pageBlocks","aiBuildSectionDeliveredBlocks","except","aiBuildBlocksKey","blocks","aiBuildPlacedItemLines","lines","aiBuildSectionItems","placedByCode","key","labels","named","found","keys","sort","aiBuildSettlement","delivered","open","failed","aiBuildRetryLedger","dependents","downstream","retried","again","note","settledAt","aiLedgerUnits","creations","aiBuildItemOutputNote","written","live","said","notice"],"mappings":"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"}
1
+ {"version":3,"sources":["../../../../../../../libs/plugins/ai/src/lib/model/ai-build-job.ts"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n pluginAiCapabilityArgsProblems,\n type PluginAiCapability,\n} from '@aglyn/aglyn/plugin-manager/plugin-ai-capabilities'\nimport type { PluginDraftRecord } from '@aglyn/aglyn/plugin-manager/plugin-resource-drafts'\nimport {\n AI_PLAN_NEW_REF_PREFIX,\n isAiPlanNewRef,\n type AiBuildItem,\n type AiBuildPlan,\n type AiBuildPlanCreate,\n type AiBuildPlanCreateKind,\n type AiBuildPlanScreen,\n} from './ai-build-plan'\nimport type { AiJobInputField, AiJobItemLedger, AiJobItemStatus } from './ai-jobs.types'\nimport {\n AI_BUILD_STORE_OP,\n AI_BUILD_STORE_PAGES_LABEL,\n AI_BUILD_STORE_SLOT,\n aiBuildMakesStore,\n aiBuildStorePagesAdded,\n} from './ai-build-store-pages'\nimport {\n AI_SITE_HOME_FIRST_LABEL,\n AI_SITE_MAX_SECTIONS,\n AI_SITE_PASS_CREDITS,\n aiCreationMeasuredCredits,\n aiJobPlanCreditEstimate,\n aiJobPlanCreditRange,\n aiSitePlanIsHome,\n aiStandaloneScreenCreditRange,\n} from './ai-site-job'\nimport {\n AI_CREDIT_RANGE_ZERO,\n AI_MEASURED_PASS_CREDITS,\n aiCreditRangeAdd,\n aiCreditRangeOf,\n aiCreditRangeOrdered,\n type AiCreditRange,\n type AiCreditsSmaller,\n} from './ai-credit-estimate'\n\n/**\n * What a `build` job is (AGL-3616): one request — \"a few pages, a contact\n * form and a way to book me\" — planned as creations, pages and items, built\n * one UNIT a pass in dependency order, and settled ITEM BY ITEM.\n *\n * A build is a generalized site scaffold. Every unit is handed to what\n * already builds that kind of thing — a page to the page step, a form to the\n * form step, another plugin's resource to that plugin's draft writer — so a\n * build cannot drift from what it builds. What is new is the settlement: one\n * failed unit does not end the job. It gives back its own spend, the units\n * that depended on it are built without it (or skipped, when they cannot\n * stand without it), and the job is `done` when anything was delivered.\n *\n * This module is the build's MODEL — its units, their order, how a failure\n * travels to what depends on it, what it is estimated to cost, and the\n * ledger arithmetic — and does no I/O, so the step, the machine, the doors\n * and the console read one vocabulary.\n */\n\n/** How much one build holds: what one proposal can describe and one person can read. */\nexport const AI_BUILD_LIMITS = {\n /** Creations, pages and items together. */\n units: 16,\n pages: 8,\n /** A Free workspace's pages. */\n freePages: 2,\n} as const\n\n/**\n * What a Free build's plan card says when it holds as many pages as a Free\n * build makes (AGL-3722): the plan is told the cap and plans the first pages\n * a request asks for, so a request for three — \"About us, Custom cakes and\n * Catering\", 2026-10-10 — came back as two with nothing saying why. `null`\n * when the plan holds fewer, or on a paid workspace.\n */\nexport function aiBuildFreePageCapNote(plan: Pick<AiBuildPlan, 'screens'>, freeTaste: boolean): string | null {\n const cap = AI_BUILD_LIMITS.freePages\n if (!freeTaste || plan.screens.length < cap) return null\n return `A Free workspace’s build makes up to ${cap} pages at a time. If you asked for more, ask Assist for the rest once this build is done.`\n}\n\n/** What a build creates through its `create` list; everything else beyond pages is an item. */\nexport const AI_BUILD_CREATE_KINDS: readonly AiBuildPlanCreateKind[] = ['layout', 'form', 'component', 'email']\n\n/**\n * The operations a build plans through `create` and `screens` rather than\n * `items`: an item naming one is a plan that put it in the wrong list.\n */\nexport const AI_BUILD_STRUCTURAL_OPS: readonly string[] = ['page', ...AI_BUILD_CREATE_KINDS]\n\n/**\n * What a build hands an item it made before it (AGL-3728): its pages, by the\n * title the plan gave each and the id it was written under, and its layouts,\n * by name. An item's `new:<title>` destinations are read against it.\n */\nexport const AI_BUILD_MADE_INPUT = 'buildMade'\n\nexport interface AiBuildMade {\n pages: Array<{ title: string; id: string }>\n layouts: Array<{ name: string; id: string }>\n}\n\n/** The job input a build's Assist proposal sets when the brief asked to publish. */\nexport const AI_BUILD_PUBLISH_INPUT = 'publish'\n\n/** A unit of a build: a creation, a page, or an item. */\nexport interface AiBuildUnit {\n slot: string\n /** The capability operation that builds it. */\n op: string\n label: string\n creation?: AiBuildPlanCreate\n screen?: AiBuildPlanScreen\n item?: AiBuildItem\n /** The slots it is built after, in plan order. */\n deps: string[]\n}\n\n/** The operation a creation is built as. */\nfunction creationOp(creation: AiBuildPlanCreate): string {\n return creation.kind\n}\n\n/** A plan's `new:<name>` names, each to the slot that builds it. */\nfunction namedSlots(plan: AiBuildPlan): Map<string, string> {\n const slots = new Map<string, string>()\n plan.create.forEach((creation, index) => {\n if (AI_BUILD_CREATE_KINDS.includes(creation.kind)) slots.set(creation.name.toLowerCase(), `c${index}`)\n })\n for (const item of plan.items ?? []) slots.set(item.name.toLowerCase(), item.slot)\n return slots\n}\n\n/** The name a `new:<name>` reference gives, lowercased. */\nexport function aiBuildRefName(ref: string): string {\n return ref.slice(AI_PLAN_NEW_REF_PREFIX.length).trim().toLowerCase()\n}\n\n/**\n * The `new:<name>` references an item's arguments make (AGL-3728): an\n * argument that is one, or the destination after `=>` in an entry such as a\n * menu item's `About => new:About`. Read from the arguments, never from the\n * model's `dependsOn`, so what an item links is always built before it.\n */\nexport function aiBuildItemArgRefs(args: Readonly<Record<string, unknown>> | null | undefined): string[] {\n const refs: string[] = []\n const take = (value: unknown) => {\n if (typeof value !== 'string') return\n for (const part of [value, value.split('=>').slice(-1)[0] ?? '']) {\n const ref = part.trim()\n if (isAiPlanNewRef(ref) && !refs.includes(ref)) refs.push(ref)\n }\n }\n for (const value of Object.values(args ?? {})) {\n if (Array.isArray(value)) value.forEach(take)\n else take(value)\n }\n return refs\n}\n\n/** Every reference a page makes: its layout, template, starting page and what its sections place. */\nexport function aiBuildScreenRefs(screen: AiBuildPlanScreen): string[] {\n return [\n screen.layout,\n screen.template,\n screen.duplicateOf,\n ...screen.sections.flatMap((section) => section.uses),\n ].filter((ref): ref is string => typeof ref === 'string' && ref.length > 0)\n}\n\n/**\n * The units a plan implies, in plan order: creations, then items, then\n * pages — the order a member reads them in, and the one a page that places\n * a creation or an item is built after anyway. `aiBuildOrder` sorts them on\n * their dependencies.\n */\nexport function aiBuildUnits(plan: AiBuildPlan): AiBuildUnit[] {\n const slots = namedSlots(plan)\n // A page, by the title the plan gave it: what an item's arguments may link\n // as `new:<title>` (a menu item, AGL-3728), built before the item.\n const pageSlots = new Map<string, string>()\n plan.screens.forEach((screen, index) => {\n const title = screen.title.trim().toLowerCase()\n if (title && !pageSlots.has(title)) pageSlots.set(title, `p${index}`)\n })\n const depsOf = (refs: readonly (string | null)[], self: string, pages = false): string[] => {\n const deps: string[] = []\n for (const ref of refs) {\n if (!isAiPlanNewRef(ref)) continue\n const slot = slots.get(aiBuildRefName(ref)) ?? (pages ? pageSlots.get(aiBuildRefName(ref)) : undefined)\n if (slot && slot !== self && !deps.includes(slot)) deps.push(slot)\n }\n return deps\n }\n const units: AiBuildUnit[] = []\n plan.create.forEach((creation, index) => {\n if (!AI_BUILD_CREATE_KINDS.includes(creation.kind)) return\n const slot = `c${index}`\n // A form is built after the dataset it writes to (AGL-3616).\n units.push({\n slot,\n op: creationOp(creation),\n label: creation.name,\n creation,\n deps: depsOf([creation.duplicateOf, creation.kind === 'form' ? (creation.writesTo ?? null) : null], slot),\n })\n })\n for (const item of plan.items ?? []) {\n units.push({\n slot: item.slot,\n op: item.op,\n label: item.name,\n item,\n // What it depends on, and what its arguments link as `new:` (AGL-3728).\n deps: depsOf([...item.dependsOn, ...aiBuildItemArgRefs(item.args)], item.slot, true),\n })\n }\n plan.screens.forEach((screen, index) => {\n const slot = `p${index}`\n units.push({ slot, op: 'page', label: screen.title, screen, deps: depsOf(aiBuildScreenRefs(screen), slot) })\n })\n // A store's own pages (AGL-3676), added by the platform: last, so every\n // planned page keeps the first claim on the site's pages allowance.\n if (aiBuildStorePagesAdded(plan).length) {\n units.push({ slot: AI_BUILD_STORE_SLOT, op: AI_BUILD_STORE_OP, label: AI_BUILD_STORE_PAGES_LABEL, deps: [] })\n }\n return units\n}\n\n/** Whether a unit is one the platform adds rather than the plan (AGL-3676): a store's own pages. */\nexport function aiBuildUnitIsPlatform(unit: Pick<AiBuildUnit, 'op'>): boolean {\n return unit.op === AI_BUILD_STORE_OP\n}\n\n/**\n * The units in an order that builds every dependency before what depends on\n * it, plan order otherwise; `null` when the dependencies hold a cycle.\n */\nexport function aiBuildOrder(units: readonly AiBuildUnit[]): AiBuildUnit[] | null {\n const ordered: AiBuildUnit[] = []\n const placed = new Set<string>()\n const known = new Set(units.map((unit) => unit.slot))\n while (ordered.length < units.length) {\n const next = units.find(\n (unit) => !placed.has(unit.slot) && unit.deps.every((dep) => placed.has(dep) || !known.has(dep)),\n )\n if (!next) return null\n ordered.push(next)\n placed.add(next.slot)\n }\n return ordered\n}\n\n/**\n * What is wrong with a plan's references as a build reads them: a\n * `new:<name>` an item depends on that nothing in the plan makes, and a\n * cycle. Each is a sentence the plan's one re-ask carries.\n */\nexport function aiBuildGraphProblems(plan: AiBuildPlan): string[] {\n const problems: string[] = []\n const slots = namedSlots(plan)\n for (const item of plan.items ?? []) {\n for (const ref of item.dependsOn) {\n if (!isAiPlanNewRef(ref)) continue\n if (!slots.has(aiBuildRefName(ref))) {\n problems.push(`The item \"${item.name}\" depends on ${ref}, which the plan never makes. Declare it, or take it out of dependsOn.`)\n } else if (aiBuildRefName(ref) === item.name.toLowerCase()) {\n problems.push(`The item \"${item.name}\" depends on itself. Take it out of its own dependsOn.`)\n }\n }\n }\n if (!aiBuildOrder(aiBuildUnits(plan))) {\n problems.push('The plan’s dependencies go round in a circle, so nothing in the circle can be built first. Make one of them depend on nothing.')\n }\n return problems\n}\n\n/** The operations a build may plan, as the registry and the gates left them, by op. */\nexport type AiBuildOps = ReadonlyMap<string, PluginAiCapability>\n\n/** How many pages a build may hold on this workspace. */\nexport function aiBuildPageLimit(freeTaste: boolean | null | undefined): number {\n return freeTaste ? AI_BUILD_LIMITS.freePages : AI_BUILD_LIMITS.pages\n}\n\n/**\n * Why a build cannot build a plan of this shape, in a sentence a member\n * reads; `null` when it can. Held to the plan with the one re-ask (the plan\n * step's scope), and again by the doors before a confirmed plan runs.\n * `ops` is what may be planned on this site; absent, items are not judged\n * against the registry (a console reading a kept plan).\n */\nexport function aiBuildPlanShapeRefusal(\n plan: AiBuildPlan,\n options: { freeTaste?: boolean; ops?: AiBuildOps } = {},\n): string | null {\n // What the platform adds beside the plan (a store's own pages) is no part of its size.\n const units = aiBuildUnits(plan).filter((unit) => !aiBuildUnitIsPlatform(unit))\n if (!units.length) return 'This plan builds nothing. Describe what to build again.'\n if (units.length > AI_BUILD_LIMITS.units) {\n return `This plan builds ${units.length} things, and one build holds ${AI_BUILD_LIMITS.units}. Ask for the rest in a second request.`\n }\n const pages = aiBuildPageLimit(options.freeTaste)\n if (plan.screens.length > pages) {\n return options.freeTaste\n ? `This plan builds ${plan.screens.length} pages, and a Free workspace's build makes at most ${pages}. Paid plans can build more.`\n : `This plan builds ${plan.screens.length} pages, and one build makes at most ${pages}.`\n }\n const slugs = new Set<string>()\n for (const screen of plan.screens) {\n if (!screen.sections.length) return `The page “${screen.title}” has no sections to build.`\n if (screen.sections.length > AI_SITE_MAX_SECTIONS) {\n return `The page “${screen.title}” has ${screen.sections.length} sections, and a built page holds ${AI_SITE_MAX_SECTIONS}.`\n }\n const slug = screen.slug.trim().toLowerCase()\n if (slugs.has(slug)) return `Two pages in this plan share the address ${screen.slug}.`\n slugs.add(slug)\n }\n for (const creation of plan.create) {\n if (!AI_BUILD_CREATE_KINDS.includes(creation.kind)) {\n return `A build does not create ${creation.kind === 'theme-change' ? 'theme changes' : `${creation.kind}s`} (“${creation.name}”). Take it out of create.`\n }\n }\n const graph = aiBuildGraphProblems(plan)\n if (graph.length) return graph[0]\n const ops = options.ops\n const counts = new Map<string, number>()\n for (const unit of units) counts.set(unit.op, (counts.get(unit.op) ?? 0) + 1)\n for (const item of plan.items ?? []) {\n if (AI_BUILD_STRUCTURAL_OPS.includes(item.op)) {\n return item.op === 'page'\n ? `“${item.name}” is a page: plan it in screens, not items.`\n : `“${item.name}” is ${item.op === 'email' ? 'an' : 'a'} ${item.op}: plan it in create, not items.`\n }\n if (!ops) continue\n const capability = ops.get(item.op)\n if (!capability) return `Nothing on this site can make “${item.name}” (${item.op}). Take it out of items.`\n if (options.freeTaste && !capability.freeAllowed) {\n return `A Free workspace cannot have ${aiArticle(capability.noun)} made (“${item.name}”). Take it out of items.`\n }\n const problems = pluginAiCapabilityArgsProblems(capability.argsSchema, item.args)\n if (problems.length) return `The arguments of “${item.name}” do not read: ${problems.join('; ')}.`\n }\n if (ops) {\n for (const [op, count] of counts) {\n const capability = ops.get(op)\n if (capability && count > capability.maxPerPlan) {\n return `This plan makes ${count} of “${capability.noun}”, and one build makes at most ${capability.maxPerPlan}.`\n }\n }\n }\n return null\n}\n\n/**\n * What the person must still say before this plan can be built, as the\n * questions its operations ask (`missingInput`), or `null` when nothing is\n * missing: an item the planner kept with nothing it may build from — a\n * tracking change naming no id, AGL-3751 — is asked about, never built\n * empty or from a value the planner made up. Not a plan rule: a re-ask\n * cannot supply what only the person knows, so the plan is not kept and\n * the build answers with the question.\n */\nexport function aiBuildPlanMissingInput(plan: AiBuildPlan, ops: AiBuildOps | null | undefined): string | null {\n if (!ops) return null\n const questions: string[] = []\n for (const item of plan.items ?? []) {\n const question = ops.get(item.op)?.missingInput?.({ name: item.name, why: item.why, args: item.args })\n if (question && !questions.includes(question)) questions.push(question)\n }\n return questions.length ? questions.join(' ') : null\n}\n\n/**\n * The code on the build's admission refusal for a plan only the person can\n * complete (AGL-3978): the plan step keeps such a plan and waits in\n * `needs_input` for the fields `aiBuildPlanInputFields` reads, where the\n * operations describe them.\n */\nexport const AI_BUILD_NEEDS_INPUT_CODE = 'needs-input'\n\n/**\n * The fields the person fills before this plan can be built (AGL-3978), one\n * per id an item asks for, as its operation describes them (`inputFields`).\n * Empty when nothing asks, or when an item asks without fields to fill — a\n * tracking change naming no tag at all — which the build answers with its\n * question instead.\n */\nexport function aiBuildPlanInputFields(plan: AiBuildPlan, ops: AiBuildOps | null | undefined): AiJobInputField[] {\n if (!ops) return []\n const fields: AiJobInputField[] = []\n for (const item of plan.items ?? []) {\n const capability = ops.get(item.op)\n const one = { name: item.name, why: item.why, args: item.args }\n if (!capability?.missingInput?.(one)) continue\n const asked = capability.inputFields?.(one) ?? []\n if (!asked.length) return []\n for (const field of asked) {\n fields.push({ item: item.name, arg: field.arg, label: field.label, shape: field.shape, pattern: field.pattern.source })\n }\n }\n return fields\n}\n\n/** \"a booking service\", \"an email design\". */\nexport function aiArticle(noun: string): string {\n return `${/^[aeiou]/i.test(noun) ? 'an' : 'a'} ${noun}`\n}\n\n/** The passes one unit is estimated at: a page's sections and its listing, one for a creation. */\nfunction unitPasses(unit: AiBuildUnit): number {\n if (unit.screen) return unit.screen.sections.length + 1\n return 1\n}\n\n/**\n * About what one unit costs, in credits: a page or a creation by the passes\n * it implies at the nominal credits a pass is held against, as a site's are;\n * an item by its capability's own estimate, recorded on the plan when it was\n * kept.\n */\nexport function aiBuildUnitCreditEstimate(unit: AiBuildUnit, ops?: AiBuildOps): number {\n // A store's own pages are written by code, with no model: no credits (AGL-3676).\n if (aiBuildUnitIsPlatform(unit)) return 0\n if (unit.item) {\n if (typeof unit.item.credits === 'number') return unit.item.credits\n const capability = ops?.get(unit.item.op)\n if (capability) return Math.max(0, Math.floor(capability.estimateCredits(unit.item.args)))\n return AI_SITE_PASS_CREDITS\n }\n return unitPasses(unit) * AI_SITE_PASS_CREDITS\n}\n\n/**\n * About what a build costs, in credits: every unit's estimate, or only the\n * units named in `slots` — what Try again shows. The ceiling a member\n * confirms; the meter charges what actually runs.\n */\nexport function aiBuildCreditEstimate(\n plan: AiBuildPlan,\n options: { ops?: AiBuildOps; slots?: ReadonlySet<string> } = {},\n): number {\n return aiBuildUnits(plan)\n .filter((unit) => !options.slots || options.slots.has(unit.slot))\n .reduce((total, unit) => total + aiBuildUnitCreditEstimate(unit, options.ops), 0)\n}\n\n/**\n * About what a job of this kind costs to build from its plan: a build's\n * units, every other planned kind as `aiJobPlanCreditEstimate` counts it.\n */\nexport function aiJobCreditEstimate(kind: string, plan: AiBuildPlan): number {\n return kind === 'build' ? aiBuildCreditEstimate(plan) : aiJobPlanCreditEstimate(kind, plan)\n}\n\n/**\n * What one unit is likely to cost, its p90 and its ceiling (AGL-3722): a page\n * as a page written on its own measured (a fixed cost and one per section), a creation at what its kind\n * measured, an item at the measured pass times the passes its capability\n * estimates (none for a draft another plugin writes, which asks no model).\n * The ceiling is `aiBuildUnitCreditEstimate`, unchanged.\n */\nexport function aiBuildUnitCreditRange(unit: AiBuildUnit, ops?: AiBuildOps): AiCreditRange {\n const ceiling = aiBuildUnitCreditEstimate(unit, ops)\n // A build writes each page on its own, never in a site start's warm run (AGL-3722).\n if (unit.screen) return aiStandaloneScreenCreditRange(unit.screen.sections.length)\n if (unit.creation) return aiCreditRangeOf(aiCreationMeasuredCredits(unit.creation.kind, { standalone: true }), ceiling)\n const passes = Math.ceil(ceiling / AI_SITE_PASS_CREDITS)\n return aiCreditRangeOf(\n { median: passes * AI_MEASURED_PASS_CREDITS.median, p90: passes * AI_MEASURED_PASS_CREDITS.p90 },\n ceiling,\n )\n}\n\n/**\n * What a build is likely to cost, its p90 and its ceiling (AGL-3722): every\n * unit's range, or only the units named in `slots` — what Try again runs.\n * The plan card, Try again and the Free admission all read this; the meter\n * charges what actually runs.\n */\nexport function aiBuildCreditRange(\n plan: AiBuildPlan,\n options: { ops?: AiBuildOps; slots?: ReadonlySet<string> } = {},\n): AiCreditRange {\n return aiCreditRangeOrdered(\n aiBuildUnits(plan)\n .filter((unit) => !options.slots || options.slots.has(unit.slot))\n .reduce((total, unit) => aiCreditRangeAdd(total, aiBuildUnitCreditRange(unit, options.ops)), AI_CREDIT_RANGE_ZERO),\n )\n}\n\n/** `aiJobCreditEstimate` as a range (AGL-3722). */\nexport function aiJobCreditRange(kind: string, plan: AiBuildPlan): AiCreditRange {\n return kind === 'build' ? aiBuildCreditRange(plan) : aiJobPlanCreditRange(kind, plan)\n}\n\n/**\n * A smaller first build (AGL-3722): the plan's home page — its first page\n * where it has no home — and only what that page needs, transitively: the\n * layout it is drawn in, the form and anything else its sections place.\n * Every other page, and what only they needed, waits for a later request.\n * `null` when the plan has no page, or when the smaller plan is the whole one.\n */\nexport function aiBuildFirstPagePlan<T extends AiBuildPlan>(plan: T): T | null {\n if (!plan.screens.length) return null\n const index = Math.max(0, plan.screens.findIndex(aiSitePlanIsHome))\n const units = aiBuildUnits(plan).filter((unit) => !aiBuildUnitIsPlatform(unit))\n const bySlot = new Map(units.map((unit) => [unit.slot, unit]))\n const keep = new Set<string>()\n const queue = [`p${index}`]\n while (queue.length) {\n const slot = queue.shift() as string\n if (keep.has(slot)) continue\n keep.add(slot)\n for (const dep of bySlot.get(slot)?.deps ?? []) queue.push(dep)\n }\n if (keep.size === units.length) return null\n const screen = plan.screens[index]\n const create = plan.create.filter((creation, at) => !AI_BUILD_CREATE_KINDS.includes(creation.kind) || keep.has(`c${at}`))\n const items = (plan.items ?? []).filter((item) => keep.has(item.slot))\n const kept = new Set([screen.slug, ...create.map((entry) => `${AI_PLAN_NEW_REF_PREFIX}${entry.name}`)])\n const smaller: T = {\n ...plan,\n create,\n screens: [screen],\n ...(plan.items ? { items } : {}),\n ...(plan.embeds ? { embeds: plan.embeds.filter((embed) => kept.has(embed.where)) } : {}),\n }\n // The store's own pages stay only while the smaller build still makes a store (AGL-3676).\n if (smaller.storePages && !aiBuildMakesStore(smaller)) delete smaller.storePages\n return smaller\n}\n\n/** The smaller first build a build that does not fit is offered (AGL-3722), with its range; `null` when there is none. */\nexport function aiBuildSmaller(plan: AiBuildPlan, ops?: AiBuildOps): AiCreditsSmaller | null {\n const smaller = aiBuildFirstPagePlan(plan)\n if (!smaller) return null\n const screen = smaller.screens[0]\n const label = aiSitePlanIsHome(screen) ? AI_SITE_HOME_FIRST_LABEL : `Build the ${screen.title} page first`\n return { label, ...aiBuildCreditRange(smaller, { ops }) }\n}\n\n/** A fresh ledger: one pending row per unit, first attempt. */\nexport function aiBuildInitialLedger(units: readonly AiBuildUnit[]): AiJobItemLedger[] {\n return units.map((unit) => ({\n slot: unit.slot,\n op: unit.op,\n label: unit.label,\n status: 'pending',\n attempt: 1,\n creditsSpent: 0,\n attemptCredits: 0,\n creditsRefunded: 0,\n failure: null,\n outputs: [],\n }))\n}\n\nconst OPEN: readonly AiJobItemStatus[] = ['pending', 'running']\n\n/** Whether an item is still to be built. */\nexport function aiBuildItemOpen(row: Pick<AiJobItemLedger, 'status'>): boolean {\n return OPEN.includes(row.status)\n}\n\n/** Whether an item delivered: built as planned, or built without something that failed. */\nexport function aiBuildItemDelivered(row: Pick<AiJobItemLedger, 'status'>): boolean {\n return row.status === 'succeeded' || row.status === 'degraded'\n}\n\n/**\n * The next unit to build: the first in build order whose row is still open.\n * Its dependencies come before it, so by then each is settled one way or the\n * other. `null` when nothing is left.\n */\nexport function aiBuildNextUnit(\n ordered: readonly AiBuildUnit[],\n ledger: readonly AiJobItemLedger[],\n): AiBuildUnit | null {\n const rows = new Map(ledger.map((row) => [row.slot, row]))\n return ordered.find((unit) => {\n const row = rows.get(unit.slot)\n return !row || aiBuildItemOpen(row)\n }) ?? null\n}\n\n/** How a unit is built given what its dependencies came to. */\nexport interface AiBuildDegradation {\n /** The unit is not built at all, with the sentence why; nothing is spent. */\n skip: string | null\n /** The failed dependencies that change how it is built. */\n degradedBy: string[]\n /** What the person reads about the change; one per failed dependency. */\n notes: string[]\n /** `new:<name>` references (lowercased names) to leave out. */\n dropped: Set<string>\n /** Brief lines for the unit's own job: what to leave out, and what to place. */\n briefLines: string[]\n}\n\n/**\n * How a unit is built when some of what it depends on failed (AGL-3616).\n *\n * A PAGE is always built: a failed layout falls back to the site's own, a\n * failed form or component is left out of its section, and a failed item a\n * section places (a booking service) takes its block out of the page — each\n * with a note. Any OTHER unit whose dependency failed is skipped when that\n * dependency's capability says `omit` (a campaign whose email design failed\n * has nothing to send), and built without it when it says `fallback`.\n */\nexport function aiBuildDegradation(\n unit: AiBuildUnit,\n context: {\n units: readonly AiBuildUnit[]\n ledger: readonly AiJobItemLedger[]\n ops?: AiBuildOps\n },\n): AiBuildDegradation {\n const rows = new Map(context.ledger.map((row) => [row.slot, row]))\n const bySlot = new Map(context.units.map((one) => [one.slot, one]))\n const result: AiBuildDegradation = { skip: null, degradedBy: [], notes: [], dropped: new Set(), briefLines: [] }\n for (const slot of unit.deps) {\n const dep = bySlot.get(slot)\n const row = rows.get(slot)\n if (!dep || !row || aiBuildItemDelivered(row)) continue\n const noun = dep.creation\n ? aiBuildCreationNoun(dep.creation.kind)\n : (context.ops?.get(dep.op)?.noun ?? dep.op)\n const capability = dep.item ? context.ops?.get(dep.op) : undefined\n const degrade = dep.item?.degrade ?? capability?.degrade ?? (dep.creation?.kind === 'layout' ? 'fallback' : 'omit')\n // A form whose dataset could not be made is built without it (AGL-3616):\n // its submissions reach the Inbox, as any form's do.\n if (aiBuildUnitWritesTo(unit) === dep.label.toLowerCase()) {\n result.degradedBy.push(slot)\n result.notes.push(`Its submissions arrive in the Inbox only: the dataset “${dep.label}” could not be created.`)\n continue\n }\n // An item that links pages this build makes (a menu's entries, AGL-3728)\n // is built with the ones it made and without the ones it could not\n // (AGL-3832), and skipped only when it made none of them.\n const madeAPage = unit.deps.some((one) => {\n const made = rows.get(one)\n return !!bySlot.get(one)?.screen && !!made && aiBuildItemDelivered(made)\n })\n if (!unit.screen && dep.screen && madeAPage) {\n result.degradedBy.push(slot)\n result.dropped.add(dep.label.toLowerCase())\n result.notes.push(`Built without the ${noun} “${dep.label}”: it could not be created.`)\n continue\n }\n if (!unit.screen && degrade === 'omit') {\n result.skip = `Not built: the ${noun} “${dep.label}” it needs could not be created.`\n result.degradedBy.push(slot)\n return result\n }\n result.degradedBy.push(slot)\n result.dropped.add(dep.label.toLowerCase())\n if (dep.creation?.kind === 'layout') {\n result.notes.push(`Built inside the site’s own layout: the layout “${dep.label}” could not be created.`)\n continue\n }\n if (unit.screen) {\n const section = unit.screen.sections.find((one) =>\n one.uses.some((ref) => isAiPlanNewRef(ref) && aiBuildRefName(ref) === dep.label.toLowerCase()),\n )\n // Another item this section places with the same block was built (one\n // of several events, AGL-3743): the block stays, and only this item is\n // missing from what it shows.\n const blockStays = Boolean(\n section &&\n capability?.pageBlocks?.length &&\n aiBuildSectionDeliveredBlocks(section, { ...context, rows, except: slot }).has(aiBuildBlocksKey(capability.pageBlocks)),\n )\n if (blockStays) {\n result.notes.push(`Built without the ${noun} “${dep.label}”: it could not be created.`)\n result.briefLines.push(`Leave the ${noun} “${dep.label}” out of the “${section?.name}” section: it could not be created.`)\n continue\n }\n const blocks = capability?.pageBlocks?.length ? ` the ${capability.pageBlocks.join(' or ')} block` : ''\n result.notes.push(\n `Built without${blocks || ` the ${noun}`}: the ${noun} “${dep.label}” could not be created.`,\n )\n result.briefLines.push(\n `${section ? `Build the “${section.name}” section` : 'Build the page'} without the ${noun} “${dep.label}”${blocks ? ` and without${blocks}` : ''}: it could not be created.`,\n )\n } else {\n result.notes.push(`Built without the ${noun} “${dep.label}”: it could not be created.`)\n }\n }\n return result\n}\n\n/** The dataset a form unit writes to, by its `new:` name lowercased; `null` for any other unit (AGL-3616). */\nexport function aiBuildUnitWritesTo(unit: Pick<AiBuildUnit, 'creation'>): string | null {\n const ref = unit.creation?.kind === 'form' ? unit.creation.writesTo : null\n return isAiPlanNewRef(ref) ? aiBuildRefName(ref) : null\n}\n\n/** What each creation is called in a note. */\nexport function aiBuildCreationNoun(kind: AiBuildPlanCreateKind): string {\n return kind === 'email' ? 'email design' : kind === 'theme-change' ? 'theme change' : kind\n}\n\n/**\n * The brief lines a page is told about the items its sections place and\n * that were built: the block to put there, in the owner's words.\n */\nexport function aiBuildPlacedItemLines(\n unit: AiBuildUnit,\n context: {\n units: readonly AiBuildUnit[]\n ledger: readonly AiJobItemLedger[]\n ops?: AiBuildOps\n /** Operations whose items the platform places itself (a listing), so the page is told nothing of them. */\n placedByCode?: readonly string[]\n },\n): string[] {\n if (!unit.screen) return []\n const rows = new Map(context.ledger.map((row) => [row.slot, row]))\n const lines: string[] = []\n for (const section of unit.screen.sections) {\n // One line per block a section places, naming every built item it shows:\n // a section listing four events places the Event List once (AGL-3743).\n const placed = new Map<string, { blocks: readonly string[]; noun: string; labels: string[] }>()\n for (const { dep, capability } of aiBuildSectionItems(section, context.units, context.ops)) {\n const row = rows.get(dep.slot)\n if (!row || !aiBuildItemDelivered(row)) continue\n if (context.placedByCode?.includes(dep.op)) continue\n const blocks = capability?.pageBlocks ?? []\n if (!blocks.length) continue\n const key = aiBuildBlocksKey(blocks)\n const entry = placed.get(key) ?? { blocks, noun: capability?.noun ?? dep.op, labels: [] }\n entry.labels.push(`“${dep.label}”`)\n placed.set(key, entry)\n }\n for (const { blocks, noun, labels } of placed.values()) {\n const named =\n labels.length === 1\n ? `the ${noun} ${labels[0]}`\n : `the ${noun}s ${labels.slice(0, -1).join(', ')} and ${labels[labels.length - 1]}`\n lines.push(`In the “${section.name}” section, place the ${blocks.join(' or ')} block for ${named}.`)\n }\n }\n return lines\n}\n\n/** The items a page section places, each with its capability, in the order its uses name them. */\nfunction aiBuildSectionItems(\n section: { uses: readonly string[] },\n units: readonly AiBuildUnit[],\n ops: AiBuildOps | undefined,\n): Array<{ dep: AiBuildUnit; capability: PluginAiCapability | undefined }> {\n const found: Array<{ dep: AiBuildUnit; capability: PluginAiCapability | undefined }> = []\n for (const ref of section.uses) {\n if (!isAiPlanNewRef(ref)) continue\n const dep = units.find((one) => one.item && one.item.name.toLowerCase() === aiBuildRefName(ref))\n if (dep?.item) found.push({ dep, capability: ops?.get(dep.op) })\n }\n return found\n}\n\n/** The blocks a section's built items place, each set as one key; `except` leaves one item out. */\nfunction aiBuildSectionDeliveredBlocks(\n section: { uses: readonly string[] },\n context: { units: readonly AiBuildUnit[]; rows: ReadonlyMap<string, AiJobItemLedger>; ops?: AiBuildOps; except: string },\n): Set<string> {\n const keys = new Set<string>()\n for (const { dep, capability } of aiBuildSectionItems(section, context.units, context.ops)) {\n if (dep.slot === context.except || !capability?.pageBlocks?.length) continue\n const row = context.rows.get(dep.slot)\n if (row && aiBuildItemDelivered(row)) keys.add(aiBuildBlocksKey(capability.pageBlocks))\n }\n return keys\n}\n\nfunction aiBuildBlocksKey(blocks: readonly string[]): string {\n return [...blocks].sort().join('|')\n}\n\n/** What a build came to: whether anything was delivered, and whether anything is left. */\nexport function aiBuildSettlement(ledger: readonly AiJobItemLedger[]): {\n delivered: boolean\n open: boolean\n failed: number\n} {\n return {\n delivered: ledger.some(aiBuildItemDelivered),\n open: ledger.some(aiBuildItemOpen),\n failed: ledger.filter((row) => row.status === 'failed').length,\n }\n}\n\n/**\n * The ledger Try again runs (AGL-3616): every failed item back to `pending`\n * on its next attempt, with the items left unbuilt because of it — skipped,\n * or degraded with no draft — and every item the build never reached. An\n * item that succeeded is never run again, and a degraded page that has its\n * draft keeps it, with a note that the page needs an edit. `retried` names\n * the slots that will run, which is what the estimate is shown for.\n */\nexport function aiBuildRetryLedger(\n ledger: readonly AiJobItemLedger[],\n units: readonly AiBuildUnit[],\n): { ledger: AiJobItemLedger[]; retried: string[] } {\n const failed = new Set(ledger.filter((row) => row.status === 'failed').map((row) => row.slot))\n const dependents = new Map<string, string[]>()\n for (const unit of units) {\n for (const dep of unit.deps) dependents.set(dep, [...(dependents.get(dep) ?? []), unit.slot])\n }\n // Everything downstream of a failed item, transitively.\n const downstream = new Set<string>()\n const queue = [...failed]\n while (queue.length) {\n const slot = queue.shift() as string\n for (const next of dependents.get(slot) ?? []) {\n if (downstream.has(next)) continue\n downstream.add(next)\n queue.push(next)\n }\n }\n const retried: string[] = []\n const next = ledger.map((row): AiJobItemLedger => {\n const again =\n row.status === 'failed' ||\n (row.status === 'skipped' && (downstream.has(row.slot) || !(row.degradedBy ?? []).length)) ||\n (row.status === 'degraded' && downstream.has(row.slot) && !row.outputs.length)\n if (again) {\n retried.push(row.slot)\n return {\n ...row,\n status: 'pending',\n attempt: row.attempt + 1,\n attemptCredits: 0,\n failure: null,\n note: null,\n degradedBy: [],\n settledAt: null,\n }\n }\n if (row.status === 'degraded' && downstream.has(row.slot) && row.outputs.length) {\n return {\n ...row,\n note: `${row.note ? `${row.note} ` : ''}It keeps its draft: once the rest is built, edit this page to add what it is missing.`,\n }\n }\n return row\n })\n return { ledger: next, retried }\n}\n\n/**\n * Units read back off a ledger alone (AGL-3616), for a job whose units are\n * not a build plan's — a site scaffold's: each row as its unit, and every\n * page built after the layouts and forms the ledger holds.\n */\nexport function aiLedgerUnits(ledger: readonly AiJobItemLedger[]): AiBuildUnit[] {\n const creations = ledger.filter((row) => row.op === 'layout' || row.op === 'form').map((row) => row.slot)\n return ledger.map((row) => ({\n slot: row.slot,\n op: row.op,\n label: row.label,\n deps: row.op === 'page' ? creations : [],\n }))\n}\n\n/**\n * What the job drawer says under an item another plugin's writer made: a\n * draft, or, for setup its writer saves live (`live`, a CRM pipeline or\n * field, AGL-3746), that it was saved. A writer that went live only when the\n * member may (an event the publishing role publishes, AGL-3755) reports\n * `live: false` for one it kept as a draft, with its `notice` saying why.\n */\nexport function aiBuildItemOutputNote(\n capability: Pick<PluginAiCapability, 'where' | 'live'>,\n written?: Pick<PluginDraftRecord, 'live' | 'notice'>,\n): string {\n const live = written?.live ?? capability.live\n const said = live ? `Live now, in ${capability.where}.` : `A draft, in ${capability.where}.`\n const notice = written?.notice?.trim()\n return notice ? `${said} ${notice}` : said\n}\n"],"names":["pluginAiCapabilityArgsProblems","AI_PLAN_NEW_REF_PREFIX","isAiPlanNewRef","AI_BUILD_STORE_OP","AI_BUILD_STORE_PAGES_LABEL","AI_BUILD_STORE_SLOT","aiBuildMakesStore","aiBuildStorePagesAdded","AI_SITE_HOME_FIRST_LABEL","AI_SITE_MAX_SECTIONS","AI_SITE_PASS_CREDITS","aiCreationMeasuredCredits","aiJobPlanCreditEstimate","aiJobPlanCreditRange","aiSitePlanIsHome","aiStandaloneScreenCreditRange","AI_CREDIT_RANGE_ZERO","AI_MEASURED_PASS_CREDITS","aiCreditRangeAdd","aiCreditRangeOf","aiCreditRangeOrdered","AI_BUILD_LIMITS","units","pages","freePages","aiBuildFreePageCapNote","plan","freeTaste","cap","screens","length","AI_BUILD_CREATE_KINDS","AI_BUILD_STRUCTURAL_OPS","AI_BUILD_MADE_INPUT","AI_BUILD_PUBLISH_INPUT","creationOp","creation","kind","namedSlots","slots","Map","create","forEach","index","includes","set","name","toLowerCase","item","items","slot","aiBuildRefName","ref","slice","trim","aiBuildItemArgRefs","args","refs","take","value","part","split","push","Object","values","Array","isArray","aiBuildScreenRefs","screen","layout","template","duplicateOf","sections","flatMap","section","uses","filter","aiBuildUnits","pageSlots","title","has","depsOf","self","deps","get","undefined","op","label","writesTo","dependsOn","aiBuildUnitIsPlatform","unit","aiBuildOrder","ordered","placed","Set","known","map","next","find","every","dep","add","aiBuildGraphProblems","problems","aiBuildPageLimit","aiBuildPlanShapeRefusal","options","counts","slugs","slug","graph","ops","capability","freeAllowed","aiArticle","noun","argsSchema","join","count","maxPerPlan","aiBuildPlanMissingInput","questions","question","missingInput","why","AI_BUILD_NEEDS_INPUT_CODE","aiBuildPlanInputFields","fields","one","asked","inputFields","field","arg","shape","pattern","source","test","unitPasses","aiBuildUnitCreditEstimate","credits","Math","max","floor","estimateCredits","aiBuildCreditEstimate","reduce","total","aiJobCreditEstimate","aiBuildUnitCreditRange","ceiling","standalone","passes","ceil","median","p90","aiBuildCreditRange","aiJobCreditRange","aiBuildFirstPagePlan","findIndex","bySlot","keep","queue","shift","size","at","kept","entry","smaller","embeds","embed","where","storePages","aiBuildSmaller","aiBuildInitialLedger","status","attempt","creditsSpent","attemptCredits","creditsRefunded","failure","outputs","OPEN","aiBuildItemOpen","row","aiBuildItemDelivered","aiBuildNextUnit","ledger","rows","aiBuildDegradation","context","result","skip","degradedBy","notes","dropped","briefLines","aiBuildCreationNoun","degrade","aiBuildUnitWritesTo","madeAPage","some","made","blockStays","Boolean","pageBlocks","aiBuildSectionDeliveredBlocks","except","aiBuildBlocksKey","blocks","aiBuildPlacedItemLines","lines","aiBuildSectionItems","placedByCode","key","labels","named","found","keys","sort","aiBuildSettlement","delivered","open","failed","aiBuildRetryLedger","dependents","downstream","retried","again","note","settledAt","aiLedgerUnits","creations","aiBuildItemOutputNote","written","live","said","notice"],"mappings":"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"}
@@ -140,6 +140,26 @@ export declare const AI_MEASURED_PAID_SITE_CREDITS: {
140
140
  readonly p90: 66;
141
141
  };
142
142
  };
143
+ /**
144
+ * A page brought in from a person's own website (AGL-3976), priced as an AI
145
+ * page: a paid site start's page as measured above, since an imported page is
146
+ * one answer in the layout language and its listing, written inside one job
147
+ * the way a site start writes its pages. Its site's header and footer, built
148
+ * once in an import's first wave, is that table's layout.
149
+ *
150
+ * Re-measure from done `import` jobs' item ledgers once production has run
151
+ * them: their `page` rows' `creditsSpent`, as the paid table is read.
152
+ */
153
+ export declare const AI_MEASURED_IMPORT_CREDITS: {
154
+ readonly page: {
155
+ readonly median: 27;
156
+ readonly p90: 47;
157
+ };
158
+ readonly frame: {
159
+ readonly median: 29;
160
+ readonly p90: 29;
161
+ };
162
+ };
143
163
  /**
144
164
  * When the table above was read, and from when its jobs ran. Both tables
145
165
  * were measured before AGL-3781 asked a paid site's plan at medium effort and
@@ -136,6 +136,19 @@
136
136
  p90: 66
137
137
  }
138
138
  };
139
+ /**
140
+ * A page brought in from a person's own website (AGL-3976), priced as an AI
141
+ * page: a paid site start's page as measured above, since an imported page is
142
+ * one answer in the layout language and its listing, written inside one job
143
+ * the way a site start writes its pages. Its site's header and footer, built
144
+ * once in an import's first wave, is that table's layout.
145
+ *
146
+ * Re-measure from done `import` jobs' item ledgers once production has run
147
+ * them: their `page` rows' `creditsSpent`, as the paid table is read.
148
+ */ export const AI_MEASURED_IMPORT_CREDITS = {
149
+ page: AI_MEASURED_PAID_SITE_CREDITS.page,
150
+ frame: AI_MEASURED_PAID_SITE_CREDITS.layout
151
+ };
139
152
  /**
140
153
  * When the table above was read, and from when its jobs ran. Both tables
141
154
  * were measured before AGL-3781 asked a paid site's plan at medium effort and
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../../../libs/plugins/ai/src/lib/model/ai-credit-estimate.ts"],"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/**\n * WHAT A JOB REALLY COSTS, NEXT TO WHAT IT CAN COST (AGL-3722).\n *\n * Every job's cost used to be quoted at its CEILING: each pass at the\n * `AI_SITE_PASS_CREDITS` (50) a pass is reserved against. A Free Assist\n * build of two pages, a quote form and a layout was quoted 600 credits and\n * refused with 164 left, when builds like it measure about a fifth of that.\n *\n * So a job is now quoted as a RANGE: what it is likely to cost (the sum of\n * the measured medians of what it builds), what it costs nine times in ten\n * (the measured p90s), and its ceiling (the old figure, unchanged). The\n * meter still charges actual use, and the reservation each pass takes is\n * still the ceiling's 50 — only the words and the Free admission move:\n * a Free job is admitted outright when its p90 fits what is left, and asked\n * to be confirmed when it does not.\n *\n * This module is pure: the console, the doors and the specs read one table.\n */\n\n/** One measured cost: the median and the 90th percentile, in credits. */\nexport interface AiMeasuredCredits {\n median: number\n p90: number\n}\n\n/**\n * MEASURED IN PRODUCTION, credits per unit, over every `done` AI job since\n * 2026-10-01 (read 2026-10-09; a whole Free site job came to 148–160):\n *\n * page item 30 / 40 (a page of about `AI_MEASURED_PAGE_SECTIONS` sections, its listing included)\n * form 29 / 31\n * layout 23 / 24 (header and footer, one answer)\n * theme 4 / 8 (a site start's look)\n * plan step 21 / 70\n *\n * THE FAST TIER'S PART, REPRICED (AGL-3781). A site start's look, a Free\n * start's plan and every page's listing run on the fast tier, measured above\n * on Claude Haiku 4.5 at its cost. They run on Claude Haiku 5.5 at the\n * platform's markup now, so those parts are repriced from what production\n * sent, at the new rates and about 30% more tokens: over October 1–14 a look\n * 4 / 7 → 1 / 2, a Free start's plan 15 / 22 → 3 / 5, a listing 3 / 5 → 1 / 1\n * (2 less on every page), and a whole two-page Free site 148 → 121 at the\n * median. The other rows ran on the balanced tier and do not move.\n *\n * HOW TO RE-MEASURE: a read-only collection-group read of `aiJobs` in\n * production where `status == 'done'` and `createdAt` is in the window; group\n * each ledger row's (`items[]`) `creditsSpent` by its `op` (the site start's\n * look is the `theme` row), take the plan step's `steps[].creditsSpent` for\n * `plan`, and each job's `creditsSpent` for the whole-site band. Put each\n * group's median and 90th percentile here, and the dates in\n * `AI_MEASURED_AT`. `ai-credit-estimate.spec.ts` holds the table, the page\n * scaling and the measured whole-site band together, so a re-measure that\n * moves one moves the spec with it.\n */\nexport const AI_MEASURED_UNIT_CREDITS = {\n // 30 / 40 with its listing at Haiku 4.5's cost.\n page: { median: 28, p90: 38 },\n form: { median: 29, p90: 31 },\n layout: { median: 23, p90: 24 },\n // 4 / 8 on Haiku 4.5.\n theme: { median: 1, p90: 2 },\n // 21 / 70: the median is a Free start's plan, on the fast tier; the p90 a\n // plan on the balanced tier, which does not move.\n plan: { median: 4, p90: 70 },\n} as const satisfies Record<string, AiMeasuredCredits>\n\n/**\n * MEASURED IN PRODUCTION, credits per unit of a PAID site start, whose plan\n * and parts run on the paid routing (Sonnet) rather than a Free start's\n * (Haiku) the table above is mostly made of: every `done` paid site job\n * since 2026-10-01, read 2026-10-12 (6 jobs; products from the 4 stores; AGL-3739).\n *\n * plan step 81 / 86 (a Free start's plan: 20 / 42 on Haiku 4.5, 3 / 5 repriced)\n * page item 29 / 49 (about `AI_MEASURED_PAGE_SECTIONS` sections; 27 / 47 with its listing repriced)\n * form 32 / 39\n * layout 29 / 29\n * theme 4 / 4 (1 / 1 repriced)\n * email 49 / 51\n * products 64 / 66 (a store's first products, one answer)\n *\n * A 5-page store with its welcome email was quoted about 277 off the table\n * above: its plan at a Free start's 21 where paid plans run about 81, and its\n * first products not counted at all where they run about 64. Those stores\n * came to 413-448; this table quotes one at about 404.\n *\n * Re-measure as the table above says, keeping only jobs whose plan step's\n * `tokens.model` is the paid routing's.\n */\nexport const AI_MEASURED_PAID_SITE_CREDITS = {\n plan: { median: 81, p90: 86 },\n page: { median: 27, p90: 47 },\n form: { median: 32, p90: 39 },\n layout: { median: 29, p90: 29 },\n theme: { median: 1, p90: 1 },\n email: { median: 49, p90: 51 },\n products: { median: 64, p90: 66 },\n} as const satisfies Record<string, AiMeasuredCredits>\n\n/**\n * When the table above was read, and from when its jobs ran. Both tables\n * were measured before AGL-3781 asked a paid site's plan at medium effort and\n * the layout language's pages and frames at low. A lower effort draws less,\n * so their plan, page and layout figures stand as the higher reading until\n * the next re-measure: a quote is never under what is drawn.\n */\nexport const AI_MEASURED_AT = { read: '2026-10-09', since: '2026-10-01' } as const\n\n/**\n * What a whole Free two-page site job measured at, in credits, in the same\n * window: 148–160 with its plan, look and listings at Haiku 4.5's cost, 27\n * less at the median with them repriced (AGL-3781).\n */\nexport const AI_MEASURED_FREE_SITE_CREDITS = { low: 121, high: 133 } as const\n\n/** The sections the measured page item is about: a page is scaled around it. */\nexport const AI_MEASURED_PAGE_SECTIONS = 5\n\n/**\n * What a page of this many sections is likely to cost: the measured page\n * scaled by its sections around the ~5-section median — about 6 credits a\n * section, 8 at the p90.\n */\nexport function aiMeasuredPageCredits(sections: number): AiMeasuredCredits {\n const count = Math.max(1, Math.floor(Number.isFinite(sections) ? sections : AI_MEASURED_PAGE_SECTIONS))\n const { median, p90 } = AI_MEASURED_UNIT_CREDITS.page\n return {\n median: Math.ceil((median * count) / AI_MEASURED_PAGE_SECTIONS),\n p90: Math.ceil((p90 * count) / AI_MEASURED_PAGE_SECTIONS),\n }\n}\n\n/**\n * What a page costs when it is written ON ITS OWN — a page an Assist build or\n * a page job writes, rather than one of a site start's pages (AGL-3722).\n *\n * The table's page item is a site start's: its pages are written one after\n * another inside one job, the later ones reading the prompt the first one\n * paid to write, so a 2-section second page measured 19–28. A page written on\n * its own pays that prompt itself and reads the site it lands on, and costs\n * what a site start's FIRST page costs: a 5-section home page measured 39–78\n * (median 40, p90 78), standalone page jobs' writing step 82–105 for a\n * 2-section page, and the Assist build pages of 2026-10-09 22–89 each. Quoting\n * a build's pages at the site start's scaled median told a Free workspace\n * \"about 48 credits\" for two 4-section pages (AGL-3722, 2026-10-10).\n *\n * So it is priced as a fixed cost — the prompt, the site, the listing — and a\n * cost per section: a 4-section page about 38 (p90 76), a 5-section 44 (p90 88).\n * The fixed part was 16 / 30 with its listing at Haiku 4.5's cost (AGL-3781).\n */\nexport const AI_MEASURED_STANDALONE_PAGE = {\n fixed: { median: 14, p90: 28 },\n perSection: { median: 6, p90: 12 },\n} as const satisfies Record<string, AiMeasuredCredits>\n\n/** What a page of this many sections written on its own is likely to cost. */\nexport function aiMeasuredStandalonePageCredits(sections: number): AiMeasuredCredits {\n const count = Math.max(1, Math.floor(Number.isFinite(sections) ? sections : AI_MEASURED_PAGE_SECTIONS))\n const { fixed, perSection } = AI_MEASURED_STANDALONE_PAGE\n return {\n median: fixed.median + perSection.median * count,\n p90: fixed.p90 + perSection.p90 * count,\n }\n}\n\n/**\n * What a creation costs when it is written ON ITS OWN (AGL-3722), where it\n * measured apart from a site start's: an Assist build's layout came to 24–28\n * (2026-10-09/10), against a site start's 23/24 written in its warm prompt.\n * A form measured the same either way (25–30 on its own, 29/31 in a site\n * start), so it keeps the table's figure.\n */\nexport const AI_MEASURED_STANDALONE_CREATION_CREDITS = {\n layout: { median: 26, p90: 30 },\n} as const satisfies Record<string, AiMeasuredCredits>\n\n/**\n * What one pass of a kind with no measurement of its own is likely to cost\n * (a component, an email design, a template, an item another runner\n * builds), written on its own: a component job's writing step measured\n * 52–65, a form job's 37, a layout job's 63, and the Assist build of\n * 2026-10-09 a welcome email at 46 and a products step at 60. Until\n * 2026-10-10 this was a site start's form (29/31), which is written inside a\n * site job's warm prompt and is the cheapest single answer there is.\n */\nexport const AI_MEASURED_PASS_CREDITS: AiMeasuredCredits = { median: 50, p90: 65 }\n\n/** A job's cost as it is quoted: likely, nine times in ten, and at its worst. */\nexport interface AiCreditRange {\n /** The sum of the measured medians: what the job is likely to spend. */\n likely: number\n /** The sum of the measured p90s: what a Free job is admitted on. */\n p90: number\n /** Every pass at its reserve: what it can spend at most. */\n ceiling: number\n}\n\nexport const AI_CREDIT_RANGE_ZERO: AiCreditRange = { likely: 0, p90: 0, ceiling: 0 }\n\n/** Two ranges added. */\nexport function aiCreditRangeAdd(a: AiCreditRange, b: AiCreditRange): AiCreditRange {\n return { likely: a.likely + b.likely, p90: a.p90 + b.p90, ceiling: a.ceiling + b.ceiling }\n}\n\n/** A measured cost as a range with its own ceiling, the likely and p90 never above it. */\nexport function aiCreditRangeOf(measured: AiMeasuredCredits, ceiling: number): AiCreditRange {\n const top = Math.max(0, Math.ceil(ceiling))\n return { likely: Math.min(measured.median, top), p90: Math.min(measured.p90, top), ceiling: top }\n}\n\n/** A range whose likely and p90 are each at least the last, and at most the ceiling. */\nexport function aiCreditRangeOrdered(range: AiCreditRange): AiCreditRange {\n const ceiling = Math.max(0, Math.ceil(range.ceiling))\n const likely = Math.min(Math.max(0, Math.ceil(range.likely)), ceiling)\n const p90 = Math.min(Math.max(likely, Math.ceil(range.p90)), ceiling)\n return { likely, p90, ceiling }\n}\n\nconst n = (value: number) => value.toLocaleString('en-US')\n\n/**\n * The range as every surface quotes it: \"About 106 credits (up to 650)\".\n * A job whose likely figure is its ceiling says one number.\n */\nexport function aiCreditRangeText(range: AiCreditRange): string {\n if (range.likely >= range.ceiling) return `About ${n(range.ceiling)} credits`\n return `About ${n(range.likely)} credits (up to ${n(range.ceiling)})`\n}\n\n/**\n * Whether a Free job of this range needs the person's go-ahead before it\n * starts (AGL-3722): its p90 is more than what is left. A job whose p90\n * fits starts with no prompt; one that does not starts only when confirmed,\n * builds as much as what is left pays for, and pauses with Resume.\n */\nexport function aiCreditsNeedConfirm(range: Pick<AiCreditRange, 'p90'>, left: number): boolean {\n return Number.isFinite(left) && range.p90 > Math.max(0, Math.floor(left))\n}\n\n/** The smaller first build a Free job that does not fit is offered (AGL-3722). */\nexport interface AiCreditsSmaller {\n /** \"Build the home page first\". */\n label: string\n likely: number\n p90: number\n ceiling: number\n}\n\n/**\n * What a Free job that does not fit what is left says before it starts, and\n * the choices it offers: build what fits, a smaller first build, or Upgrade.\n * The door that refuses an unconfirmed start answers with it (status 409,\n * `code: AI_CREDITS_CONFIRM_CODE`), and the plan card and the guided start\n * draw it from the same figures.\n */\nexport interface AiCreditsPrompt extends AiCreditRange {\n left: number\n resetsOn: string\n smaller: AiCreditsSmaller | null\n}\n\n/** The `code` a door answers an unconfirmed Free start with. */\nexport const AI_CREDITS_CONFIRM_CODE = 'credits-confirm'\n\n/** \"Build what fits\": the go-ahead for a Free job past what is left. */\nexport const AI_CREDITS_BUILD_WHAT_FITS = 'Build what fits'\n\n/** The smaller first build's button: \"Build the home page first (about 64 credits)\". */\nexport function aiCreditsSmallerText(smaller: Pick<AiCreditsSmaller, 'label' | 'likely'>): string {\n return `${smaller.label} (about ${n(smaller.likely)} credits)`\n}\n\n/** Which way on a prompt offers, in the order it offers them. */\nexport type AiCreditsChoiceKey = 'fits' | 'smaller' | 'upgrade'\n\n/** One way on, as its option button reads it: a short label and the figure under it (AGL-3722). */\nexport interface AiCreditsChoice {\n key: AiCreditsChoiceKey\n label: string\n detail: string\n /** The one choice drawn as the primary button. */\n recommended: boolean\n}\n\nconst credit = (count: number) => `${n(count)} ${count === 1 ? 'credit' : 'credits'}`\n\n/**\n * The prompt's ways on, as its three option buttons read them (Zach,\n * 2026-10-10: \"more appealing and consistent\"): build what fits, the smaller\n * first build when there is one, and Upgrade when it can be offered — each a\n * short sentence-case label with its figure under it. The smaller build is\n * the recommended one when its p90 fits what is left, since it then finishes;\n * otherwise building what fits is.\n */\nexport function aiCreditsChoices(\n prompt: Pick<AiCreditsPrompt, 'left' | 'smaller'>,\n offers: { smaller: boolean; upgrade: boolean },\n): AiCreditsChoice[] {\n const left = Math.max(0, Math.floor(prompt.left))\n const smaller = offers.smaller ? prompt.smaller : null\n const smallerFits = smaller !== null && smaller.p90 <= left\n const choices: AiCreditsChoice[] = [\n {\n key: 'fits',\n label: AI_CREDITS_BUILD_WHAT_FITS,\n detail: `Uses your ${credit(left)} left, then pauses`,\n recommended: !smallerFits,\n },\n ]\n if (smaller) {\n choices.push({\n key: 'smaller',\n label: smaller.label,\n detail: smallerFits ? `About ${credit(smaller.likely)}, fits what you have left` : `About ${credit(smaller.likely)}`,\n recommended: smallerFits,\n })\n }\n if (offers.upgrade) choices.push({ key: 'upgrade', label: 'Upgrade', detail: 'Get more credits', recommended: false })\n return choices\n}\n\n/** A reset day as a person reads it: \"November 1\". */\nfunction resetLabel(resetsOn: string): string {\n const at = new Date(`${resetsOn}T00:00:00.000Z`)\n return Number.isFinite(at.getTime())\n ? at.toLocaleDateString('en-US', { month: 'long', day: 'numeric', timeZone: 'UTC' })\n : 'the first of next month'\n}\n\n/**\n * The plain sentence (Zach, 2026-10-09): \"This build is about N credits (up\n * to M). You have L left, so it will build as much as it can and pause when\n * your credits run out. You can upgrade or resume when they renew.\"\n */\nexport function aiCreditsPromptText(prompt: AiCreditsPrompt, noun: 'build' | 'site' = 'build'): string {\n const size =\n prompt.likely >= prompt.ceiling\n ? `about ${n(prompt.ceiling)} credits`\n : `about ${n(prompt.likely)} credits (up to ${n(prompt.ceiling)})`\n const left = Math.max(0, Math.floor(prompt.left))\n return (\n `This ${noun} is ${size}. You have ${n(left)} left, so it will build as much as it can and pause ` +\n `when your credits run out. You can upgrade or resume when they renew on ${resetLabel(prompt.resetsOn)}.`\n )\n}\n\n/**\n * The record a confirmed Free start keeps (AGL-3722): who said go, when,\n * what was left then and the range they were shown.\n */\nexport interface AiJobCreditsConfirmation extends AiCreditRange {\n by: string\n at: Date | string\n left: number\n}\n\n/** The confirmation a door keeps on the job for the prompt the person confirmed, or `null` when there was none. */\nexport function aiCreditsConfirmation(\n prompt: AiCreditsPrompt | null,\n by: string,\n at: Date,\n): AiJobCreditsConfirmation | null {\n if (!prompt) return null\n return { by, at, left: prompt.left, likely: prompt.likely, p90: prompt.p90, ceiling: prompt.ceiling }\n}\n\n/** The prompt a range needs against what is left, or `null` when it fits. */\nexport function aiCreditsPromptFor(\n range: AiCreditRange,\n credits: { left: number; resetsOn: string } | null | undefined,\n smaller: AiCreditsSmaller | null = null,\n): AiCreditsPrompt | null {\n if (!credits || !aiCreditsNeedConfirm(range, credits.left)) return null\n return { ...range, left: Math.max(0, Math.floor(credits.left)), resetsOn: credits.resetsOn, smaller }\n}\n"],"names":["AI_MEASURED_UNIT_CREDITS","page","median","p90","form","layout","theme","plan","AI_MEASURED_PAID_SITE_CREDITS","email","products","AI_MEASURED_AT","read","since","AI_MEASURED_FREE_SITE_CREDITS","low","high","AI_MEASURED_PAGE_SECTIONS","aiMeasuredPageCredits","sections","count","Math","max","floor","Number","isFinite","ceil","AI_MEASURED_STANDALONE_PAGE","fixed","perSection","aiMeasuredStandalonePageCredits","AI_MEASURED_STANDALONE_CREATION_CREDITS","AI_MEASURED_PASS_CREDITS","AI_CREDIT_RANGE_ZERO","likely","ceiling","aiCreditRangeAdd","a","b","aiCreditRangeOf","measured","top","min","aiCreditRangeOrdered","range","n","value","toLocaleString","aiCreditRangeText","aiCreditsNeedConfirm","left","AI_CREDITS_CONFIRM_CODE","AI_CREDITS_BUILD_WHAT_FITS","aiCreditsSmallerText","smaller","label","credit","aiCreditsChoices","prompt","offers","smallerFits","choices","key","detail","recommended","push","upgrade","resetLabel","resetsOn","at","Date","getTime","toLocaleDateString","month","day","timeZone","aiCreditsPromptText","noun","size","aiCreditsConfirmation","by","aiCreditsPromptFor","credits"],"mappings":"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"}
1
+ {"version":3,"sources":["../../../../../../../libs/plugins/ai/src/lib/model/ai-credit-estimate.ts"],"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/**\n * WHAT A JOB REALLY COSTS, NEXT TO WHAT IT CAN COST (AGL-3722).\n *\n * Every job's cost used to be quoted at its CEILING: each pass at the\n * `AI_SITE_PASS_CREDITS` (50) a pass is reserved against. A Free Assist\n * build of two pages, a quote form and a layout was quoted 600 credits and\n * refused with 164 left, when builds like it measure about a fifth of that.\n *\n * So a job is now quoted as a RANGE: what it is likely to cost (the sum of\n * the measured medians of what it builds), what it costs nine times in ten\n * (the measured p90s), and its ceiling (the old figure, unchanged). The\n * meter still charges actual use, and the reservation each pass takes is\n * still the ceiling's 50 — only the words and the Free admission move:\n * a Free job is admitted outright when its p90 fits what is left, and asked\n * to be confirmed when it does not.\n *\n * This module is pure: the console, the doors and the specs read one table.\n */\n\n/** One measured cost: the median and the 90th percentile, in credits. */\nexport interface AiMeasuredCredits {\n median: number\n p90: number\n}\n\n/**\n * MEASURED IN PRODUCTION, credits per unit, over every `done` AI job since\n * 2026-10-01 (read 2026-10-09; a whole Free site job came to 148–160):\n *\n * page item 30 / 40 (a page of about `AI_MEASURED_PAGE_SECTIONS` sections, its listing included)\n * form 29 / 31\n * layout 23 / 24 (header and footer, one answer)\n * theme 4 / 8 (a site start's look)\n * plan step 21 / 70\n *\n * THE FAST TIER'S PART, REPRICED (AGL-3781). A site start's look, a Free\n * start's plan and every page's listing run on the fast tier, measured above\n * on Claude Haiku 4.5 at its cost. They run on Claude Haiku 5.5 at the\n * platform's markup now, so those parts are repriced from what production\n * sent, at the new rates and about 30% more tokens: over October 1–14 a look\n * 4 / 7 → 1 / 2, a Free start's plan 15 / 22 → 3 / 5, a listing 3 / 5 → 1 / 1\n * (2 less on every page), and a whole two-page Free site 148 → 121 at the\n * median. The other rows ran on the balanced tier and do not move.\n *\n * HOW TO RE-MEASURE: a read-only collection-group read of `aiJobs` in\n * production where `status == 'done'` and `createdAt` is in the window; group\n * each ledger row's (`items[]`) `creditsSpent` by its `op` (the site start's\n * look is the `theme` row), take the plan step's `steps[].creditsSpent` for\n * `plan`, and each job's `creditsSpent` for the whole-site band. Put each\n * group's median and 90th percentile here, and the dates in\n * `AI_MEASURED_AT`. `ai-credit-estimate.spec.ts` holds the table, the page\n * scaling and the measured whole-site band together, so a re-measure that\n * moves one moves the spec with it.\n */\nexport const AI_MEASURED_UNIT_CREDITS = {\n // 30 / 40 with its listing at Haiku 4.5's cost.\n page: { median: 28, p90: 38 },\n form: { median: 29, p90: 31 },\n layout: { median: 23, p90: 24 },\n // 4 / 8 on Haiku 4.5.\n theme: { median: 1, p90: 2 },\n // 21 / 70: the median is a Free start's plan, on the fast tier; the p90 a\n // plan on the balanced tier, which does not move.\n plan: { median: 4, p90: 70 },\n} as const satisfies Record<string, AiMeasuredCredits>\n\n/**\n * MEASURED IN PRODUCTION, credits per unit of a PAID site start, whose plan\n * and parts run on the paid routing (Sonnet) rather than a Free start's\n * (Haiku) the table above is mostly made of: every `done` paid site job\n * since 2026-10-01, read 2026-10-12 (6 jobs; products from the 4 stores; AGL-3739).\n *\n * plan step 81 / 86 (a Free start's plan: 20 / 42 on Haiku 4.5, 3 / 5 repriced)\n * page item 29 / 49 (about `AI_MEASURED_PAGE_SECTIONS` sections; 27 / 47 with its listing repriced)\n * form 32 / 39\n * layout 29 / 29\n * theme 4 / 4 (1 / 1 repriced)\n * email 49 / 51\n * products 64 / 66 (a store's first products, one answer)\n *\n * A 5-page store with its welcome email was quoted about 277 off the table\n * above: its plan at a Free start's 21 where paid plans run about 81, and its\n * first products not counted at all where they run about 64. Those stores\n * came to 413-448; this table quotes one at about 404.\n *\n * Re-measure as the table above says, keeping only jobs whose plan step's\n * `tokens.model` is the paid routing's.\n */\nexport const AI_MEASURED_PAID_SITE_CREDITS = {\n plan: { median: 81, p90: 86 },\n page: { median: 27, p90: 47 },\n form: { median: 32, p90: 39 },\n layout: { median: 29, p90: 29 },\n theme: { median: 1, p90: 1 },\n email: { median: 49, p90: 51 },\n products: { median: 64, p90: 66 },\n} as const satisfies Record<string, AiMeasuredCredits>\n\n/**\n * A page brought in from a person's own website (AGL-3976), priced as an AI\n * page: a paid site start's page as measured above, since an imported page is\n * one answer in the layout language and its listing, written inside one job\n * the way a site start writes its pages. Its site's header and footer, built\n * once in an import's first wave, is that table's layout.\n *\n * Re-measure from done `import` jobs' item ledgers once production has run\n * them: their `page` rows' `creditsSpent`, as the paid table is read.\n */\nexport const AI_MEASURED_IMPORT_CREDITS = {\n page: AI_MEASURED_PAID_SITE_CREDITS.page,\n frame: AI_MEASURED_PAID_SITE_CREDITS.layout,\n} as const satisfies Record<string, AiMeasuredCredits>\n\n/**\n * When the table above was read, and from when its jobs ran. Both tables\n * were measured before AGL-3781 asked a paid site's plan at medium effort and\n * the layout language's pages and frames at low. A lower effort draws less,\n * so their plan, page and layout figures stand as the higher reading until\n * the next re-measure: a quote is never under what is drawn.\n */\nexport const AI_MEASURED_AT = { read: '2026-10-09', since: '2026-10-01' } as const\n\n/**\n * What a whole Free two-page site job measured at, in credits, in the same\n * window: 148–160 with its plan, look and listings at Haiku 4.5's cost, 27\n * less at the median with them repriced (AGL-3781).\n */\nexport const AI_MEASURED_FREE_SITE_CREDITS = { low: 121, high: 133 } as const\n\n/** The sections the measured page item is about: a page is scaled around it. */\nexport const AI_MEASURED_PAGE_SECTIONS = 5\n\n/**\n * What a page of this many sections is likely to cost: the measured page\n * scaled by its sections around the ~5-section median — about 6 credits a\n * section, 8 at the p90.\n */\nexport function aiMeasuredPageCredits(sections: number): AiMeasuredCredits {\n const count = Math.max(1, Math.floor(Number.isFinite(sections) ? sections : AI_MEASURED_PAGE_SECTIONS))\n const { median, p90 } = AI_MEASURED_UNIT_CREDITS.page\n return {\n median: Math.ceil((median * count) / AI_MEASURED_PAGE_SECTIONS),\n p90: Math.ceil((p90 * count) / AI_MEASURED_PAGE_SECTIONS),\n }\n}\n\n/**\n * What a page costs when it is written ON ITS OWN — a page an Assist build or\n * a page job writes, rather than one of a site start's pages (AGL-3722).\n *\n * The table's page item is a site start's: its pages are written one after\n * another inside one job, the later ones reading the prompt the first one\n * paid to write, so a 2-section second page measured 19–28. A page written on\n * its own pays that prompt itself and reads the site it lands on, and costs\n * what a site start's FIRST page costs: a 5-section home page measured 39–78\n * (median 40, p90 78), standalone page jobs' writing step 82–105 for a\n * 2-section page, and the Assist build pages of 2026-10-09 22–89 each. Quoting\n * a build's pages at the site start's scaled median told a Free workspace\n * \"about 48 credits\" for two 4-section pages (AGL-3722, 2026-10-10).\n *\n * So it is priced as a fixed cost — the prompt, the site, the listing — and a\n * cost per section: a 4-section page about 38 (p90 76), a 5-section 44 (p90 88).\n * The fixed part was 16 / 30 with its listing at Haiku 4.5's cost (AGL-3781).\n */\nexport const AI_MEASURED_STANDALONE_PAGE = {\n fixed: { median: 14, p90: 28 },\n perSection: { median: 6, p90: 12 },\n} as const satisfies Record<string, AiMeasuredCredits>\n\n/** What a page of this many sections written on its own is likely to cost. */\nexport function aiMeasuredStandalonePageCredits(sections: number): AiMeasuredCredits {\n const count = Math.max(1, Math.floor(Number.isFinite(sections) ? sections : AI_MEASURED_PAGE_SECTIONS))\n const { fixed, perSection } = AI_MEASURED_STANDALONE_PAGE\n return {\n median: fixed.median + perSection.median * count,\n p90: fixed.p90 + perSection.p90 * count,\n }\n}\n\n/**\n * What a creation costs when it is written ON ITS OWN (AGL-3722), where it\n * measured apart from a site start's: an Assist build's layout came to 24–28\n * (2026-10-09/10), against a site start's 23/24 written in its warm prompt.\n * A form measured the same either way (25–30 on its own, 29/31 in a site\n * start), so it keeps the table's figure.\n */\nexport const AI_MEASURED_STANDALONE_CREATION_CREDITS = {\n layout: { median: 26, p90: 30 },\n} as const satisfies Record<string, AiMeasuredCredits>\n\n/**\n * What one pass of a kind with no measurement of its own is likely to cost\n * (a component, an email design, a template, an item another runner\n * builds), written on its own: a component job's writing step measured\n * 52–65, a form job's 37, a layout job's 63, and the Assist build of\n * 2026-10-09 a welcome email at 46 and a products step at 60. Until\n * 2026-10-10 this was a site start's form (29/31), which is written inside a\n * site job's warm prompt and is the cheapest single answer there is.\n */\nexport const AI_MEASURED_PASS_CREDITS: AiMeasuredCredits = { median: 50, p90: 65 }\n\n/** A job's cost as it is quoted: likely, nine times in ten, and at its worst. */\nexport interface AiCreditRange {\n /** The sum of the measured medians: what the job is likely to spend. */\n likely: number\n /** The sum of the measured p90s: what a Free job is admitted on. */\n p90: number\n /** Every pass at its reserve: what it can spend at most. */\n ceiling: number\n}\n\nexport const AI_CREDIT_RANGE_ZERO: AiCreditRange = { likely: 0, p90: 0, ceiling: 0 }\n\n/** Two ranges added. */\nexport function aiCreditRangeAdd(a: AiCreditRange, b: AiCreditRange): AiCreditRange {\n return { likely: a.likely + b.likely, p90: a.p90 + b.p90, ceiling: a.ceiling + b.ceiling }\n}\n\n/** A measured cost as a range with its own ceiling, the likely and p90 never above it. */\nexport function aiCreditRangeOf(measured: AiMeasuredCredits, ceiling: number): AiCreditRange {\n const top = Math.max(0, Math.ceil(ceiling))\n return { likely: Math.min(measured.median, top), p90: Math.min(measured.p90, top), ceiling: top }\n}\n\n/** A range whose likely and p90 are each at least the last, and at most the ceiling. */\nexport function aiCreditRangeOrdered(range: AiCreditRange): AiCreditRange {\n const ceiling = Math.max(0, Math.ceil(range.ceiling))\n const likely = Math.min(Math.max(0, Math.ceil(range.likely)), ceiling)\n const p90 = Math.min(Math.max(likely, Math.ceil(range.p90)), ceiling)\n return { likely, p90, ceiling }\n}\n\nconst n = (value: number) => value.toLocaleString('en-US')\n\n/**\n * The range as every surface quotes it: \"About 106 credits (up to 650)\".\n * A job whose likely figure is its ceiling says one number.\n */\nexport function aiCreditRangeText(range: AiCreditRange): string {\n if (range.likely >= range.ceiling) return `About ${n(range.ceiling)} credits`\n return `About ${n(range.likely)} credits (up to ${n(range.ceiling)})`\n}\n\n/**\n * Whether a Free job of this range needs the person's go-ahead before it\n * starts (AGL-3722): its p90 is more than what is left. A job whose p90\n * fits starts with no prompt; one that does not starts only when confirmed,\n * builds as much as what is left pays for, and pauses with Resume.\n */\nexport function aiCreditsNeedConfirm(range: Pick<AiCreditRange, 'p90'>, left: number): boolean {\n return Number.isFinite(left) && range.p90 > Math.max(0, Math.floor(left))\n}\n\n/** The smaller first build a Free job that does not fit is offered (AGL-3722). */\nexport interface AiCreditsSmaller {\n /** \"Build the home page first\". */\n label: string\n likely: number\n p90: number\n ceiling: number\n}\n\n/**\n * What a Free job that does not fit what is left says before it starts, and\n * the choices it offers: build what fits, a smaller first build, or Upgrade.\n * The door that refuses an unconfirmed start answers with it (status 409,\n * `code: AI_CREDITS_CONFIRM_CODE`), and the plan card and the guided start\n * draw it from the same figures.\n */\nexport interface AiCreditsPrompt extends AiCreditRange {\n left: number\n resetsOn: string\n smaller: AiCreditsSmaller | null\n}\n\n/** The `code` a door answers an unconfirmed Free start with. */\nexport const AI_CREDITS_CONFIRM_CODE = 'credits-confirm'\n\n/** \"Build what fits\": the go-ahead for a Free job past what is left. */\nexport const AI_CREDITS_BUILD_WHAT_FITS = 'Build what fits'\n\n/** The smaller first build's button: \"Build the home page first (about 64 credits)\". */\nexport function aiCreditsSmallerText(smaller: Pick<AiCreditsSmaller, 'label' | 'likely'>): string {\n return `${smaller.label} (about ${n(smaller.likely)} credits)`\n}\n\n/** Which way on a prompt offers, in the order it offers them. */\nexport type AiCreditsChoiceKey = 'fits' | 'smaller' | 'upgrade'\n\n/** One way on, as its option button reads it: a short label and the figure under it (AGL-3722). */\nexport interface AiCreditsChoice {\n key: AiCreditsChoiceKey\n label: string\n detail: string\n /** The one choice drawn as the primary button. */\n recommended: boolean\n}\n\nconst credit = (count: number) => `${n(count)} ${count === 1 ? 'credit' : 'credits'}`\n\n/**\n * The prompt's ways on, as its three option buttons read them (Zach,\n * 2026-10-10: \"more appealing and consistent\"): build what fits, the smaller\n * first build when there is one, and Upgrade when it can be offered — each a\n * short sentence-case label with its figure under it. The smaller build is\n * the recommended one when its p90 fits what is left, since it then finishes;\n * otherwise building what fits is.\n */\nexport function aiCreditsChoices(\n prompt: Pick<AiCreditsPrompt, 'left' | 'smaller'>,\n offers: { smaller: boolean; upgrade: boolean },\n): AiCreditsChoice[] {\n const left = Math.max(0, Math.floor(prompt.left))\n const smaller = offers.smaller ? prompt.smaller : null\n const smallerFits = smaller !== null && smaller.p90 <= left\n const choices: AiCreditsChoice[] = [\n {\n key: 'fits',\n label: AI_CREDITS_BUILD_WHAT_FITS,\n detail: `Uses your ${credit(left)} left, then pauses`,\n recommended: !smallerFits,\n },\n ]\n if (smaller) {\n choices.push({\n key: 'smaller',\n label: smaller.label,\n detail: smallerFits ? `About ${credit(smaller.likely)}, fits what you have left` : `About ${credit(smaller.likely)}`,\n recommended: smallerFits,\n })\n }\n if (offers.upgrade) choices.push({ key: 'upgrade', label: 'Upgrade', detail: 'Get more credits', recommended: false })\n return choices\n}\n\n/** A reset day as a person reads it: \"November 1\". */\nfunction resetLabel(resetsOn: string): string {\n const at = new Date(`${resetsOn}T00:00:00.000Z`)\n return Number.isFinite(at.getTime())\n ? at.toLocaleDateString('en-US', { month: 'long', day: 'numeric', timeZone: 'UTC' })\n : 'the first of next month'\n}\n\n/**\n * The plain sentence (Zach, 2026-10-09): \"This build is about N credits (up\n * to M). You have L left, so it will build as much as it can and pause when\n * your credits run out. You can upgrade or resume when they renew.\"\n */\nexport function aiCreditsPromptText(prompt: AiCreditsPrompt, noun: 'build' | 'site' = 'build'): string {\n const size =\n prompt.likely >= prompt.ceiling\n ? `about ${n(prompt.ceiling)} credits`\n : `about ${n(prompt.likely)} credits (up to ${n(prompt.ceiling)})`\n const left = Math.max(0, Math.floor(prompt.left))\n return (\n `This ${noun} is ${size}. You have ${n(left)} left, so it will build as much as it can and pause ` +\n `when your credits run out. You can upgrade or resume when they renew on ${resetLabel(prompt.resetsOn)}.`\n )\n}\n\n/**\n * The record a confirmed Free start keeps (AGL-3722): who said go, when,\n * what was left then and the range they were shown.\n */\nexport interface AiJobCreditsConfirmation extends AiCreditRange {\n by: string\n at: Date | string\n left: number\n}\n\n/** The confirmation a door keeps on the job for the prompt the person confirmed, or `null` when there was none. */\nexport function aiCreditsConfirmation(\n prompt: AiCreditsPrompt | null,\n by: string,\n at: Date,\n): AiJobCreditsConfirmation | null {\n if (!prompt) return null\n return { by, at, left: prompt.left, likely: prompt.likely, p90: prompt.p90, ceiling: prompt.ceiling }\n}\n\n/** The prompt a range needs against what is left, or `null` when it fits. */\nexport function aiCreditsPromptFor(\n range: AiCreditRange,\n credits: { left: number; resetsOn: string } | null | undefined,\n smaller: AiCreditsSmaller | null = null,\n): AiCreditsPrompt | null {\n if (!credits || !aiCreditsNeedConfirm(range, credits.left)) return null\n return { ...range, left: Math.max(0, Math.floor(credits.left)), resetsOn: credits.resetsOn, smaller }\n}\n"],"names":["AI_MEASURED_UNIT_CREDITS","page","median","p90","form","layout","theme","plan","AI_MEASURED_PAID_SITE_CREDITS","email","products","AI_MEASURED_IMPORT_CREDITS","frame","AI_MEASURED_AT","read","since","AI_MEASURED_FREE_SITE_CREDITS","low","high","AI_MEASURED_PAGE_SECTIONS","aiMeasuredPageCredits","sections","count","Math","max","floor","Number","isFinite","ceil","AI_MEASURED_STANDALONE_PAGE","fixed","perSection","aiMeasuredStandalonePageCredits","AI_MEASURED_STANDALONE_CREATION_CREDITS","AI_MEASURED_PASS_CREDITS","AI_CREDIT_RANGE_ZERO","likely","ceiling","aiCreditRangeAdd","a","b","aiCreditRangeOf","measured","top","min","aiCreditRangeOrdered","range","n","value","toLocaleString","aiCreditRangeText","aiCreditsNeedConfirm","left","AI_CREDITS_CONFIRM_CODE","AI_CREDITS_BUILD_WHAT_FITS","aiCreditsSmallerText","smaller","label","credit","aiCreditsChoices","prompt","offers","smallerFits","choices","key","detail","recommended","push","upgrade","resetLabel","resetsOn","at","Date","getTime","toLocaleDateString","month","day","timeZone","aiCreditsPromptText","noun","size","aiCreditsConfirmation","by","aiCreditsPromptFor","credits"],"mappings":"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"}
@@ -133,8 +133,8 @@ export declare function aiJobsHeaderChips(counts: AiJobActivityCounts): Array<{
133
133
  /** The noun for what a job of this kind makes, or `AI job` for a kind with none. */
134
134
  export declare function aiJobKindNoun(kind: AiJobKind): string;
135
135
  /**
136
- * The job kinds that build a site's pages (AGL-3765): a page, a guided start
137
- * and a build from the Assist chat. Two at once on one site each plan against
136
+ * The job kinds that build a site's pages (AGL-3765): a page, a guided start,
137
+ * a build from the Assist chat and a site import (AGL-3976). Two at once on one site each plan against
138
138
  * the site as it was, and race for what its plan holds one of.
139
139
  */
140
140
  export declare const AI_PAGE_BUILDING_JOB_KINDS: readonly AiJobKind[];
@@ -163,20 +163,22 @@ export function aiJobsActivity(jobs) {
163
163
  duplicate: 'copy',
164
164
  settings: 'settings',
165
165
  media: 'media library change',
166
- tracking: 'tracking'
166
+ tracking: 'tracking',
167
+ import: 'site import'
167
168
  };
168
169
  /** The noun for what a job of this kind makes, or `AI job` for a kind with none. */ export function aiJobKindNoun(kind) {
169
170
  var _KIND_NOUNS_kind;
170
171
  return (_KIND_NOUNS_kind = KIND_NOUNS[kind]) != null ? _KIND_NOUNS_kind : 'AI job';
171
172
  }
172
173
  /**
173
- * The job kinds that build a site's pages (AGL-3765): a page, a guided start
174
- * and a build from the Assist chat. Two at once on one site each plan against
174
+ * The job kinds that build a site's pages (AGL-3765): a page, a guided start,
175
+ * a build from the Assist chat and a site import (AGL-3976). Two at once on one site each plan against
175
176
  * the site as it was, and race for what its plan holds one of.
176
177
  */ export const AI_PAGE_BUILDING_JOB_KINDS = [
177
178
  'page',
178
179
  'site',
179
- 'build'
180
+ 'build',
181
+ 'import'
180
182
  ];
181
183
  /**
182
184
  * How long a plan waiting for its confirmation still counts as a build on its