@aglyn/plugins-ai 1.0.0-beta.143

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 (717) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +25 -0
  3. package/package.json +60 -0
  4. package/src/index.d.ts +21 -0
  5. package/src/index.js +22 -0
  6. package/src/index.js.map +1 -0
  7. package/src/lib/activity/ai-activity-actions.d.ts +106 -0
  8. package/src/lib/activity/ai-activity-actions.js +209 -0
  9. package/src/lib/activity/ai-activity-actions.js.map +1 -0
  10. package/src/lib/activity/ai-activity.d.ts +219 -0
  11. package/src/lib/activity/ai-activity.js +251 -0
  12. package/src/lib/activity/ai-activity.js.map +1 -0
  13. package/src/lib/billing/ai-overage-charge.d.ts +102 -0
  14. package/src/lib/billing/ai-overage-charge.js +258 -0
  15. package/src/lib/billing/ai-overage-charge.js.map +1 -0
  16. package/src/lib/billing/ai-overage-close.d.ts +62 -0
  17. package/src/lib/billing/ai-overage-close.js +129 -0
  18. package/src/lib/billing/ai-overage-close.js.map +1 -0
  19. package/src/lib/billing/ai-overage-cutover.d.ts +63 -0
  20. package/src/lib/billing/ai-overage-cutover.js +114 -0
  21. package/src/lib/billing/ai-overage-cutover.js.map +1 -0
  22. package/src/lib/billing/ai-overage-events.d.ts +77 -0
  23. package/src/lib/billing/ai-overage-events.js +174 -0
  24. package/src/lib/billing/ai-overage-events.js.map +1 -0
  25. package/src/lib/billing/ai-overage-gate.d.ts +147 -0
  26. package/src/lib/billing/ai-overage-gate.js +177 -0
  27. package/src/lib/billing/ai-overage-gate.js.map +1 -0
  28. package/src/lib/billing/ai-overage-ledger.d.ts +135 -0
  29. package/src/lib/billing/ai-overage-ledger.js +278 -0
  30. package/src/lib/billing/ai-overage-ledger.js.map +1 -0
  31. package/src/lib/billing/ai-overage-standing-writes.d.ts +110 -0
  32. package/src/lib/billing/ai-overage-standing-writes.js +205 -0
  33. package/src/lib/billing/ai-overage-standing-writes.js.map +1 -0
  34. package/src/lib/billing/ai-overage-standing.d.ts +168 -0
  35. package/src/lib/billing/ai-overage-standing.js +215 -0
  36. package/src/lib/billing/ai-overage-standing.js.map +1 -0
  37. package/src/lib/billing/ai-overage-trigger.d.ts +30 -0
  38. package/src/lib/billing/ai-overage-trigger.js +76 -0
  39. package/src/lib/billing/ai-overage-trigger.js.map +1 -0
  40. package/src/lib/components/ai-allotment-editor.component.d.ts +40 -0
  41. package/src/lib/components/ai-allotment-editor.component.js +213 -0
  42. package/src/lib/components/ai-allotment-editor.component.js.map +1 -0
  43. package/src/lib/components/ai-assist-actions-context.d.ts +13 -0
  44. package/src/lib/components/ai-assist-actions-context.js +21 -0
  45. package/src/lib/components/ai-assist-actions-context.js.map +1 -0
  46. package/src/lib/components/ai-assist-provider.component.d.ts +51 -0
  47. package/src/lib/components/ai-assist-provider.component.js +519 -0
  48. package/src/lib/components/ai-assist-provider.component.js.map +1 -0
  49. package/src/lib/components/ai-brief-dialog.component.d.ts +56 -0
  50. package/src/lib/components/ai-brief-dialog.component.js +319 -0
  51. package/src/lib/components/ai-brief-dialog.component.js.map +1 -0
  52. package/src/lib/components/ai-collaborator-permissions-column.component.d.ts +32 -0
  53. package/src/lib/components/ai-collaborator-permissions-column.component.js +132 -0
  54. package/src/lib/components/ai-collaborator-permissions-column.component.js.map +1 -0
  55. package/src/lib/components/ai-credits-card.component.d.ts +34 -0
  56. package/src/lib/components/ai-credits-card.component.js +131 -0
  57. package/src/lib/components/ai-credits-card.component.js.map +1 -0
  58. package/src/lib/components/ai-credits-columns.component.d.ts +56 -0
  59. package/src/lib/components/ai-credits-columns.component.js +118 -0
  60. package/src/lib/components/ai-credits-columns.component.js.map +1 -0
  61. package/src/lib/components/ai-crm-email-draft.component.d.ts +17 -0
  62. package/src/lib/components/ai-crm-email-draft.component.js +159 -0
  63. package/src/lib/components/ai-crm-email-draft.component.js.map +1 -0
  64. package/src/lib/components/ai-crm-import-mapping.component.d.ts +20 -0
  65. package/src/lib/components/ai-crm-import-mapping.component.js +167 -0
  66. package/src/lib/components/ai-crm-import-mapping.component.js.map +1 -0
  67. package/src/lib/components/ai-crm-record-card.component.d.ts +27 -0
  68. package/src/lib/components/ai-crm-record-card.component.js +263 -0
  69. package/src/lib/components/ai-crm-record-card.component.js.map +1 -0
  70. package/src/lib/components/ai-describe-automation.component.d.ts +31 -0
  71. package/src/lib/components/ai-describe-automation.component.js +226 -0
  72. package/src/lib/components/ai-describe-automation.component.js.map +1 -0
  73. package/src/lib/components/ai-describe-button.component.d.ts +39 -0
  74. package/src/lib/components/ai-describe-button.component.js +87 -0
  75. package/src/lib/components/ai-describe-button.component.js.map +1 -0
  76. package/src/lib/components/ai-describe-page.component.d.ts +26 -0
  77. package/src/lib/components/ai-describe-page.component.js +18 -0
  78. package/src/lib/components/ai-describe-page.component.js.map +1 -0
  79. package/src/lib/components/ai-experiment-cards.component.d.ts +75 -0
  80. package/src/lib/components/ai-experiment-cards.component.js +573 -0
  81. package/src/lib/components/ai-experiment-cards.component.js.map +1 -0
  82. package/src/lib/components/ai-explain-automation.component.d.ts +31 -0
  83. package/src/lib/components/ai-explain-automation.component.js +265 -0
  84. package/src/lib/components/ai-explain-automation.component.js.map +1 -0
  85. package/src/lib/components/ai-insight-dialog.component.d.ts +37 -0
  86. package/src/lib/components/ai-insight-dialog.component.js +441 -0
  87. package/src/lib/components/ai-insight-dialog.component.js.map +1 -0
  88. package/src/lib/components/ai-job-plan.component.d.ts +46 -0
  89. package/src/lib/components/ai-job-plan.component.js +192 -0
  90. package/src/lib/components/ai-job-plan.component.js.map +1 -0
  91. package/src/lib/components/ai-model-selector.component.d.ts +21 -0
  92. package/src/lib/components/ai-model-selector.component.js +109 -0
  93. package/src/lib/components/ai-model-selector.component.js.map +1 -0
  94. package/src/lib/components/ai-page-brief-dialog.component.d.ts +29 -0
  95. package/src/lib/components/ai-page-brief-dialog.component.js +27 -0
  96. package/src/lib/components/ai-page-brief-dialog.component.js.map +1 -0
  97. package/src/lib/components/ai-permissions-on-host.component.d.ts +55 -0
  98. package/src/lib/components/ai-permissions-on-host.component.js +91 -0
  99. package/src/lib/components/ai-permissions-on-host.component.js.map +1 -0
  100. package/src/lib/components/ai-product-copy-card.component.d.ts +25 -0
  101. package/src/lib/components/ai-product-copy-card.component.js +328 -0
  102. package/src/lib/components/ai-product-copy-card.component.js.map +1 -0
  103. package/src/lib/components/ai-product-import-option.component.d.ts +14 -0
  104. package/src/lib/components/ai-product-import-option.component.js +58 -0
  105. package/src/lib/components/ai-product-import-option.component.js.map +1 -0
  106. package/src/lib/components/ai-products-hub-card.component.d.ts +15 -0
  107. package/src/lib/components/ai-products-hub-card.component.js +418 -0
  108. package/src/lib/components/ai-products-hub-card.component.js.map +1 -0
  109. package/src/lib/components/ai-products-proposals.component.d.ts +19 -0
  110. package/src/lib/components/ai-products-proposals.component.js +547 -0
  111. package/src/lib/components/ai-products-proposals.component.js.map +1 -0
  112. package/src/lib/components/ai-save-as-component.component.d.ts +38 -0
  113. package/src/lib/components/ai-save-as-component.component.js +231 -0
  114. package/src/lib/components/ai-save-as-component.component.js.map +1 -0
  115. package/src/lib/components/ai-seo-audit-card.component.d.ts +9 -0
  116. package/src/lib/components/ai-seo-audit-card.component.js +620 -0
  117. package/src/lib/components/ai-seo-audit-card.component.js.map +1 -0
  118. package/src/lib/components/ai-seo-fields-card.component.d.ts +10 -0
  119. package/src/lib/components/ai-seo-fields-card.component.js +453 -0
  120. package/src/lib/components/ai-seo-fields-card.component.js.map +1 -0
  121. package/src/lib/components/ai-site-batch-card.component.d.ts +32 -0
  122. package/src/lib/components/ai-site-batch-card.component.js +531 -0
  123. package/src/lib/components/ai-site-batch-card.component.js.map +1 -0
  124. package/src/lib/components/ai-site-seo-start-card.component.d.ts +26 -0
  125. package/src/lib/components/ai-site-seo-start-card.component.js +178 -0
  126. package/src/lib/components/ai-site-seo-start-card.component.js.map +1 -0
  127. package/src/lib/components/ai-site-start-card.component.d.ts +19 -0
  128. package/src/lib/components/ai-site-start-card.component.js +348 -0
  129. package/src/lib/components/ai-site-start-card.component.js.map +1 -0
  130. package/src/lib/components/ai-template-collection-field.component.d.ts +32 -0
  131. package/src/lib/components/ai-template-collection-field.component.js +63 -0
  132. package/src/lib/components/ai-template-collection-field.component.js.map +1 -0
  133. package/src/lib/components/ai-theme-proposal-card.component.d.ts +6 -0
  134. package/src/lib/components/ai-theme-proposal-card.component.js +619 -0
  135. package/src/lib/components/ai-theme-proposal-card.component.js.map +1 -0
  136. package/src/lib/components/ai-usage-strip.component.d.ts +27 -0
  137. package/src/lib/components/ai-usage-strip.component.js +145 -0
  138. package/src/lib/components/ai-usage-strip.component.js.map +1 -0
  139. package/src/lib/components/assist-edit-canvas.d.ts +169 -0
  140. package/src/lib/components/assist-edit-canvas.js +636 -0
  141. package/src/lib/components/assist-edit-canvas.js.map +1 -0
  142. package/src/lib/components/assist-edit-card.component.d.ts +16 -0
  143. package/src/lib/components/assist-edit-card.component.js +181 -0
  144. package/src/lib/components/assist-edit-card.component.js.map +1 -0
  145. package/src/lib/components/assist-jobs-drawer.component.d.ts +72 -0
  146. package/src/lib/components/assist-jobs-drawer.component.js +626 -0
  147. package/src/lib/components/assist-jobs-drawer.component.js.map +1 -0
  148. package/src/lib/components/assist-panel.component.d.ts +136 -0
  149. package/src/lib/components/assist-panel.component.js +1099 -0
  150. package/src/lib/components/assist-panel.component.js.map +1 -0
  151. package/src/lib/components/assist-signals-page.component.d.ts +3 -0
  152. package/src/lib/components/assist-signals-page.component.js +1017 -0
  153. package/src/lib/components/assist-signals-page.component.js.map +1 -0
  154. package/src/lib/components/besigner-ai-controls.component.d.ts +29 -0
  155. package/src/lib/components/besigner-ai-controls.component.js +81 -0
  156. package/src/lib/components/besigner-ai-controls.component.js.map +1 -0
  157. package/src/lib/components/billing-ai-allotments.component.d.ts +36 -0
  158. package/src/lib/components/billing-ai-allotments.component.js +486 -0
  159. package/src/lib/components/billing-ai-allotments.component.js.map +1 -0
  160. package/src/lib/components/billing-ai-top-users.component.d.ts +44 -0
  161. package/src/lib/components/billing-ai-top-users.component.js +304 -0
  162. package/src/lib/components/billing-ai-top-users.component.js.map +1 -0
  163. package/src/lib/components/billing-assist-overage-card.component.d.ts +69 -0
  164. package/src/lib/components/billing-assist-overage-card.component.js +437 -0
  165. package/src/lib/components/billing-assist-overage-card.component.js.map +1 -0
  166. package/src/lib/components/host-ai-allotments.component.d.ts +40 -0
  167. package/src/lib/components/host-ai-allotments.component.js +239 -0
  168. package/src/lib/components/host-ai-allotments.component.js.map +1 -0
  169. package/src/lib/components/member-ai-allotment-card.component.d.ts +28 -0
  170. package/src/lib/components/member-ai-allotment-card.component.js +172 -0
  171. package/src/lib/components/member-ai-allotment-card.component.js.map +1 -0
  172. package/src/lib/components/member-ai-usage-card.component.d.ts +28 -0
  173. package/src/lib/components/member-ai-usage-card.component.js +240 -0
  174. package/src/lib/components/member-ai-usage-card.component.js.map +1 -0
  175. package/src/lib/components/staff-org-ai-card.component.d.ts +17 -0
  176. package/src/lib/components/staff-org-ai-card.component.js +739 -0
  177. package/src/lib/components/staff-org-ai-card.component.js.map +1 -0
  178. package/src/lib/components/staff-org-usage-ai-columns.component.d.ts +41 -0
  179. package/src/lib/components/staff-org-usage-ai-columns.component.js +65 -0
  180. package/src/lib/components/staff-org-usage-ai-columns.component.js.map +1 -0
  181. package/src/lib/components/staff-orgs-ai-spend-column.component.d.ts +28 -0
  182. package/src/lib/components/staff-orgs-ai-spend-column.component.js +89 -0
  183. package/src/lib/components/staff-orgs-ai-spend-column.component.js.map +1 -0
  184. package/src/lib/components/staff-user-ai-usage-card.component.d.ts +27 -0
  185. package/src/lib/components/staff-user-ai-usage-card.component.js +183 -0
  186. package/src/lib/components/staff-user-ai-usage-card.component.js.map +1 -0
  187. package/src/lib/components/use-ai-allotments.d.ts +49 -0
  188. package/src/lib/components/use-ai-allotments.js +171 -0
  189. package/src/lib/components/use-ai-allotments.js.map +1 -0
  190. package/src/lib/components/use-ai-crm-answer.d.ts +50 -0
  191. package/src/lib/components/use-ai-crm-answer.js +220 -0
  192. package/src/lib/components/use-ai-crm-answer.js.map +1 -0
  193. package/src/lib/components/use-ai-job-run.d.ts +51 -0
  194. package/src/lib/components/use-ai-job-run.js +176 -0
  195. package/src/lib/components/use-ai-job-run.js.map +1 -0
  196. package/src/lib/components/use-ai-model-choice.d.ts +47 -0
  197. package/src/lib/components/use-ai-model-choice.js +150 -0
  198. package/src/lib/components/use-ai-model-choice.js.map +1 -0
  199. package/src/lib/components/use-ai-products-jobs.d.ts +36 -0
  200. package/src/lib/components/use-ai-products-jobs.js +190 -0
  201. package/src/lib/components/use-ai-products-jobs.js.map +1 -0
  202. package/src/lib/components/use-ai-usage-meter.d.ts +11 -0
  203. package/src/lib/components/use-ai-usage-meter.js +96 -0
  204. package/src/lib/components/use-ai-usage-meter.js.map +1 -0
  205. package/src/lib/components/use-org-ai-usage.d.ts +42 -0
  206. package/src/lib/components/use-org-ai-usage.js +181 -0
  207. package/src/lib/components/use-org-ai-usage.js.map +1 -0
  208. package/src/lib/components/use-staff-orgs-ai-spend.d.ts +18 -0
  209. package/src/lib/components/use-staff-orgs-ai-spend.js +127 -0
  210. package/src/lib/components/use-staff-orgs-ai-spend.js.map +1 -0
  211. package/src/lib/constants.d.ts +24 -0
  212. package/src/lib/constants.js +23 -0
  213. package/src/lib/constants.js.map +1 -0
  214. package/src/lib/declarations.d.ts +48 -0
  215. package/src/lib/declarations.js +129 -0
  216. package/src/lib/declarations.js.map +1 -0
  217. package/src/lib/declarations.server.d.ts +35 -0
  218. package/src/lib/declarations.server.js +138 -0
  219. package/src/lib/declarations.server.js.map +1 -0
  220. package/src/lib/insights/ai-figure-readers.d.ts +90 -0
  221. package/src/lib/insights/ai-figure-readers.js +863 -0
  222. package/src/lib/insights/ai-figure-readers.js.map +1 -0
  223. package/src/lib/insights/ai-insight-digest.d.ts +165 -0
  224. package/src/lib/insights/ai-insight-digest.js +363 -0
  225. package/src/lib/insights/ai-insight-digest.js.map +1 -0
  226. package/src/lib/insights/ai-insight-readers.d.ts +71 -0
  227. package/src/lib/insights/ai-insight-readers.js +141 -0
  228. package/src/lib/insights/ai-insight-readers.js.map +1 -0
  229. package/src/lib/jobs/ai-crm-access.d.ts +61 -0
  230. package/src/lib/jobs/ai-crm-access.js +94 -0
  231. package/src/lib/jobs/ai-crm-access.js.map +1 -0
  232. package/src/lib/jobs/ai-email-bindings.d.ts +97 -0
  233. package/src/lib/jobs/ai-email-bindings.js +147 -0
  234. package/src/lib/jobs/ai-email-bindings.js.map +1 -0
  235. package/src/lib/jobs/ai-job-admission.d.ts +82 -0
  236. package/src/lib/jobs/ai-job-admission.js +45 -0
  237. package/src/lib/jobs/ai-job-admission.js.map +1 -0
  238. package/src/lib/jobs/ai-job-budget.d.ts +167 -0
  239. package/src/lib/jobs/ai-job-budget.js +161 -0
  240. package/src/lib/jobs/ai-job-budget.js.map +1 -0
  241. package/src/lib/jobs/ai-job-campaign-step.d.ts +108 -0
  242. package/src/lib/jobs/ai-job-campaign-step.js +340 -0
  243. package/src/lib/jobs/ai-job-campaign-step.js.map +1 -0
  244. package/src/lib/jobs/ai-job-component-checks.d.ts +74 -0
  245. package/src/lib/jobs/ai-job-component-checks.js +442 -0
  246. package/src/lib/jobs/ai-job-component-checks.js.map +1 -0
  247. package/src/lib/jobs/ai-job-component-step.d.ts +75 -0
  248. package/src/lib/jobs/ai-job-component-step.js +262 -0
  249. package/src/lib/jobs/ai-job-component-step.js.map +1 -0
  250. package/src/lib/jobs/ai-job-crm-step.d.ts +192 -0
  251. package/src/lib/jobs/ai-job-crm-step.js +734 -0
  252. package/src/lib/jobs/ai-job-crm-step.js.map +1 -0
  253. package/src/lib/jobs/ai-job-draft-ids.d.ts +62 -0
  254. package/src/lib/jobs/ai-job-draft-ids.js +132 -0
  255. package/src/lib/jobs/ai-job-draft-ids.js.map +1 -0
  256. package/src/lib/jobs/ai-job-drafts.d.ts +304 -0
  257. package/src/lib/jobs/ai-job-drafts.js +557 -0
  258. package/src/lib/jobs/ai-job-drafts.js.map +1 -0
  259. package/src/lib/jobs/ai-job-email-step.d.ts +195 -0
  260. package/src/lib/jobs/ai-job-email-step.js +547 -0
  261. package/src/lib/jobs/ai-job-email-step.js.map +1 -0
  262. package/src/lib/jobs/ai-job-experiment-step.d.ts +105 -0
  263. package/src/lib/jobs/ai-job-experiment-step.js +445 -0
  264. package/src/lib/jobs/ai-job-experiment-step.js.map +1 -0
  265. package/src/lib/jobs/ai-job-form-step.d.ts +250 -0
  266. package/src/lib/jobs/ai-job-form-step.js +634 -0
  267. package/src/lib/jobs/ai-job-form-step.js.map +1 -0
  268. package/src/lib/jobs/ai-job-generation.d.ts +114 -0
  269. package/src/lib/jobs/ai-job-generation.js +384 -0
  270. package/src/lib/jobs/ai-job-generation.js.map +1 -0
  271. package/src/lib/jobs/ai-job-insight-budget.d.ts +41 -0
  272. package/src/lib/jobs/ai-job-insight-budget.js +46 -0
  273. package/src/lib/jobs/ai-job-insight-budget.js.map +1 -0
  274. package/src/lib/jobs/ai-job-insight-step.d.ts +58 -0
  275. package/src/lib/jobs/ai-job-insight-step.js +350 -0
  276. package/src/lib/jobs/ai-job-insight-step.js.map +1 -0
  277. package/src/lib/jobs/ai-job-layout-step.d.ts +103 -0
  278. package/src/lib/jobs/ai-job-layout-step.js +340 -0
  279. package/src/lib/jobs/ai-job-layout-step.js.map +1 -0
  280. package/src/lib/jobs/ai-job-page-budget.d.ts +57 -0
  281. package/src/lib/jobs/ai-job-page-budget.js +60 -0
  282. package/src/lib/jobs/ai-job-page-budget.js.map +1 -0
  283. package/src/lib/jobs/ai-job-page-sections.d.ts +150 -0
  284. package/src/lib/jobs/ai-job-page-sections.js +450 -0
  285. package/src/lib/jobs/ai-job-page-sections.js.map +1 -0
  286. package/src/lib/jobs/ai-job-page-step.d.ts +198 -0
  287. package/src/lib/jobs/ai-job-page-step.js +667 -0
  288. package/src/lib/jobs/ai-job-page-step.js.map +1 -0
  289. package/src/lib/jobs/ai-job-plan-conformance.d.ts +107 -0
  290. package/src/lib/jobs/ai-job-plan-conformance.js +164 -0
  291. package/src/lib/jobs/ai-job-plan-conformance.js.map +1 -0
  292. package/src/lib/jobs/ai-job-plan-step.d.ts +196 -0
  293. package/src/lib/jobs/ai-job-plan-step.js +458 -0
  294. package/src/lib/jobs/ai-job-plan-step.js.map +1 -0
  295. package/src/lib/jobs/ai-job-plugin-drafts.d.ts +76 -0
  296. package/src/lib/jobs/ai-job-plugin-drafts.js +91 -0
  297. package/src/lib/jobs/ai-job-plugin-drafts.js.map +1 -0
  298. package/src/lib/jobs/ai-job-products-step.d.ts +106 -0
  299. package/src/lib/jobs/ai-job-products-step.js +436 -0
  300. package/src/lib/jobs/ai-job-products-step.js.map +1 -0
  301. package/src/lib/jobs/ai-job-seo-budget.d.ts +52 -0
  302. package/src/lib/jobs/ai-job-seo-budget.js +63 -0
  303. package/src/lib/jobs/ai-job-seo-budget.js.map +1 -0
  304. package/src/lib/jobs/ai-job-seo-step.d.ts +145 -0
  305. package/src/lib/jobs/ai-job-seo-step.js +809 -0
  306. package/src/lib/jobs/ai-job-seo-step.js.map +1 -0
  307. package/src/lib/jobs/ai-job-site-step.d.ts +252 -0
  308. package/src/lib/jobs/ai-job-site-step.js +538 -0
  309. package/src/lib/jobs/ai-job-site-step.js.map +1 -0
  310. package/src/lib/jobs/ai-job-template-step.d.ts +105 -0
  311. package/src/lib/jobs/ai-job-template-step.js +391 -0
  312. package/src/lib/jobs/ai-job-template-step.js.map +1 -0
  313. package/src/lib/jobs/ai-job-text-step.d.ts +125 -0
  314. package/src/lib/jobs/ai-job-text-step.js +128 -0
  315. package/src/lib/jobs/ai-job-text-step.js.map +1 -0
  316. package/src/lib/jobs/ai-job-theme-budget.d.ts +38 -0
  317. package/src/lib/jobs/ai-job-theme-budget.js +43 -0
  318. package/src/lib/jobs/ai-job-theme-budget.js.map +1 -0
  319. package/src/lib/jobs/ai-job-theme-step.d.ts +115 -0
  320. package/src/lib/jobs/ai-job-theme-step.js +337 -0
  321. package/src/lib/jobs/ai-job-theme-step.js.map +1 -0
  322. package/src/lib/jobs/ai-job-workflow-step.d.ts +139 -0
  323. package/src/lib/jobs/ai-job-workflow-step.js +530 -0
  324. package/src/lib/jobs/ai-job-workflow-step.js.map +1 -0
  325. package/src/lib/jobs/ai-jobs-beat.d.ts +78 -0
  326. package/src/lib/jobs/ai-jobs-beat.js +93 -0
  327. package/src/lib/jobs/ai-jobs-beat.js.map +1 -0
  328. package/src/lib/jobs/ai-jobs-pause.d.ts +38 -0
  329. package/src/lib/jobs/ai-jobs-pause.js +45 -0
  330. package/src/lib/jobs/ai-jobs-pause.js.map +1 -0
  331. package/src/lib/jobs/ai-jobs.d.ts +558 -0
  332. package/src/lib/jobs/ai-jobs.js +1410 -0
  333. package/src/lib/jobs/ai-jobs.js.map +1 -0
  334. package/src/lib/jobs/ai-media-asset-server.d.ts +34 -0
  335. package/src/lib/jobs/ai-media-asset-server.js +34 -0
  336. package/src/lib/jobs/ai-media-asset-server.js.map +1 -0
  337. package/src/lib/jobs/ai-media-asset.d.ts +59 -0
  338. package/src/lib/jobs/ai-media-asset.js +86 -0
  339. package/src/lib/jobs/ai-media-asset.js.map +1 -0
  340. package/src/lib/jobs/ai-product-image.d.ts +78 -0
  341. package/src/lib/jobs/ai-product-image.js +113 -0
  342. package/src/lib/jobs/ai-product-image.js.map +1 -0
  343. package/src/lib/jobs/ai-theme-brand-inputs.d.ts +125 -0
  344. package/src/lib/jobs/ai-theme-brand-inputs.js +378 -0
  345. package/src/lib/jobs/ai-theme-brand-inputs.js.map +1 -0
  346. package/src/lib/jobs/ai-theme-brand-server.d.ts +33 -0
  347. package/src/lib/jobs/ai-theme-brand-server.js +33 -0
  348. package/src/lib/jobs/ai-theme-brand-server.js.map +1 -0
  349. package/src/lib/jobs/ai-workflow-records.d.ts +84 -0
  350. package/src/lib/jobs/ai-workflow-records.js +158 -0
  351. package/src/lib/jobs/ai-workflow-records.js.map +1 -0
  352. package/src/lib/jobs/fixtures/ai-free-page-built-recording.d.ts +31 -0
  353. package/src/lib/jobs/fixtures/ai-free-page-built-recording.js +367 -0
  354. package/src/lib/jobs/fixtures/ai-free-page-built-recording.js.map +1 -0
  355. package/src/lib/jobs/fixtures/ai-free-page-recording.d.ts +69 -0
  356. package/src/lib/jobs/fixtures/ai-free-page-recording.js +442 -0
  357. package/src/lib/jobs/fixtures/ai-free-page-recording.js.map +1 -0
  358. package/src/lib/jobs/fixtures/ai-page-briefs.d.ts +146 -0
  359. package/src/lib/jobs/fixtures/ai-page-briefs.js +1850 -0
  360. package/src/lib/jobs/fixtures/ai-page-briefs.js.map +1 -0
  361. package/src/lib/model/ai-allotments.d.ts +208 -0
  362. package/src/lib/model/ai-allotments.js +269 -0
  363. package/src/lib/model/ai-allotments.js.map +1 -0
  364. package/src/lib/model/ai-automation-draft.d.ts +74 -0
  365. package/src/lib/model/ai-automation-draft.js +310 -0
  366. package/src/lib/model/ai-automation-draft.js.map +1 -0
  367. package/src/lib/model/ai-automation-outline.d.ts +50 -0
  368. package/src/lib/model/ai-automation-outline.js +262 -0
  369. package/src/lib/model/ai-automation-outline.js.map +1 -0
  370. package/src/lib/model/ai-build-plan.d.ts +197 -0
  371. package/src/lib/model/ai-build-plan.js +438 -0
  372. package/src/lib/model/ai-build-plan.js.map +1 -0
  373. package/src/lib/model/ai-crm.d.ts +237 -0
  374. package/src/lib/model/ai-crm.js +225 -0
  375. package/src/lib/model/ai-crm.js.map +1 -0
  376. package/src/lib/model/ai-experiment-proposal.d.ts +68 -0
  377. package/src/lib/model/ai-experiment-proposal.js +146 -0
  378. package/src/lib/model/ai-experiment-proposal.js.map +1 -0
  379. package/src/lib/model/ai-experiment.d.ts +309 -0
  380. package/src/lib/model/ai-experiment.js +395 -0
  381. package/src/lib/model/ai-experiment.js.map +1 -0
  382. package/src/lib/model/ai-insight.d.ts +178 -0
  383. package/src/lib/model/ai-insight.js +201 -0
  384. package/src/lib/model/ai-insight.js.map +1 -0
  385. package/src/lib/model/ai-jobs.types.d.ts +412 -0
  386. package/src/lib/model/ai-jobs.types.js +42 -0
  387. package/src/lib/model/ai-jobs.types.js.map +1 -0
  388. package/src/lib/model/ai-page-job.d.ts +92 -0
  389. package/src/lib/model/ai-page-job.js +159 -0
  390. package/src/lib/model/ai-page-job.js.map +1 -0
  391. package/src/lib/model/ai-permissions.d.ts +49 -0
  392. package/src/lib/model/ai-permissions.js +97 -0
  393. package/src/lib/model/ai-permissions.js.map +1 -0
  394. package/src/lib/model/ai-plan-capabilities.d.ts +139 -0
  395. package/src/lib/model/ai-plan-capabilities.js +149 -0
  396. package/src/lib/model/ai-plan-capabilities.js.map +1 -0
  397. package/src/lib/model/ai-products.d.ts +251 -0
  398. package/src/lib/model/ai-products.js +253 -0
  399. package/src/lib/model/ai-products.js.map +1 -0
  400. package/src/lib/model/ai-seo.d.ts +208 -0
  401. package/src/lib/model/ai-seo.js +150 -0
  402. package/src/lib/model/ai-seo.js.map +1 -0
  403. package/src/lib/model/ai-site-inventory.d.ts +164 -0
  404. package/src/lib/model/ai-site-inventory.js +145 -0
  405. package/src/lib/model/ai-site-inventory.js.map +1 -0
  406. package/src/lib/model/ai-site-job.d.ts +247 -0
  407. package/src/lib/model/ai-site-job.js +314 -0
  408. package/src/lib/model/ai-site-job.js.map +1 -0
  409. package/src/lib/model/ai-site-start-seo.d.ts +103 -0
  410. package/src/lib/model/ai-site-start-seo.js +154 -0
  411. package/src/lib/model/ai-site-start-seo.js.map +1 -0
  412. package/src/lib/model/ai-site-start.d.ts +122 -0
  413. package/src/lib/model/ai-site-start.js +159 -0
  414. package/src/lib/model/ai-site-start.js.map +1 -0
  415. package/src/lib/model/ai-site-switch.d.ts +56 -0
  416. package/src/lib/model/ai-site-switch.js +73 -0
  417. package/src/lib/model/ai-site-switch.js.map +1 -0
  418. package/src/lib/model/ai-storefront-claims.d.ts +70 -0
  419. package/src/lib/model/ai-storefront-claims.js +130 -0
  420. package/src/lib/model/ai-storefront-claims.js.map +1 -0
  421. package/src/lib/model/ai-template-subjects.d.ts +82 -0
  422. package/src/lib/model/ai-template-subjects.js +136 -0
  423. package/src/lib/model/ai-template-subjects.js.map +1 -0
  424. package/src/lib/model/ai-theme-proposal.d.ts +210 -0
  425. package/src/lib/model/ai-theme-proposal.js +506 -0
  426. package/src/lib/model/ai-theme-proposal.js.map +1 -0
  427. package/src/lib/model/ai-tokens.d.ts +96 -0
  428. package/src/lib/model/ai-tokens.js +117 -0
  429. package/src/lib/model/ai-tokens.js.map +1 -0
  430. package/src/lib/model/ai-usage-by-user.d.ts +120 -0
  431. package/src/lib/model/ai-usage-by-user.js +139 -0
  432. package/src/lib/model/ai-usage-by-user.js.map +1 -0
  433. package/src/lib/model/ai-workflow-job.d.ts +111 -0
  434. package/src/lib/model/ai-workflow-job.js +183 -0
  435. package/src/lib/model/ai-workflow-job.js.map +1 -0
  436. package/src/lib/model/assist-edit.d.ts +261 -0
  437. package/src/lib/model/assist-edit.js +175 -0
  438. package/src/lib/model/assist-edit.js.map +1 -0
  439. package/src/lib/plugin-config.d.ts +33 -0
  440. package/src/lib/plugin-config.js +118 -0
  441. package/src/lib/plugin-config.js.map +1 -0
  442. package/src/lib/plugin.d.ts +30 -0
  443. package/src/lib/plugin.js +525 -0
  444. package/src/lib/plugin.js.map +1 -0
  445. package/src/lib/providers/anthropic.d.ts +84 -0
  446. package/src/lib/providers/anthropic.js +432 -0
  447. package/src/lib/providers/anthropic.js.map +1 -0
  448. package/src/lib/providers/catalog.d.ts +197 -0
  449. package/src/lib/providers/catalog.js +312 -0
  450. package/src/lib/providers/catalog.js.map +1 -0
  451. package/src/lib/providers/contract.d.ts +464 -0
  452. package/src/lib/providers/contract.js +274 -0
  453. package/src/lib/providers/contract.js.map +1 -0
  454. package/src/lib/providers/model-choice.d.ts +119 -0
  455. package/src/lib/providers/model-choice.js +416 -0
  456. package/src/lib/providers/model-choice.js.map +1 -0
  457. package/src/lib/providers/openai-compatible.d.ts +58 -0
  458. package/src/lib/providers/openai-compatible.js +361 -0
  459. package/src/lib/providers/openai-compatible.js.map +1 -0
  460. package/src/lib/providers/registry.d.ts +49 -0
  461. package/src/lib/providers/registry.js +71 -0
  462. package/src/lib/providers/registry.js.map +1 -0
  463. package/src/lib/providers/routing.d.ts +98 -0
  464. package/src/lib/providers/routing.js +450 -0
  465. package/src/lib/providers/routing.js.map +1 -0
  466. package/src/lib/runtime/ai-abuse-guards.d.ts +113 -0
  467. package/src/lib/runtime/ai-abuse-guards.js +148 -0
  468. package/src/lib/runtime/ai-abuse-guards.js.map +1 -0
  469. package/src/lib/runtime/ai-component-bindings.d.ts +67 -0
  470. package/src/lib/runtime/ai-component-bindings.js +106 -0
  471. package/src/lib/runtime/ai-component-bindings.js.map +1 -0
  472. package/src/lib/runtime/ai-device-audit.d.ts +109 -0
  473. package/src/lib/runtime/ai-device-audit.js +97 -0
  474. package/src/lib/runtime/ai-device-audit.js.map +1 -0
  475. package/src/lib/runtime/ai-doctrine-validators.d.ts +720 -0
  476. package/src/lib/runtime/ai-doctrine-validators.js +3133 -0
  477. package/src/lib/runtime/ai-doctrine-validators.js.map +1 -0
  478. package/src/lib/runtime/ai-doctrine.d.ts +372 -0
  479. package/src/lib/runtime/ai-doctrine.js +944 -0
  480. package/src/lib/runtime/ai-doctrine.js.map +1 -0
  481. package/src/lib/runtime/ai-eval-live.d.ts +321 -0
  482. package/src/lib/runtime/ai-eval-live.js +1257 -0
  483. package/src/lib/runtime/ai-eval-live.js.map +1 -0
  484. package/src/lib/runtime/ai-eval-memory-firestore.d.ts +51 -0
  485. package/src/lib/runtime/ai-eval-memory-firestore.js +183 -0
  486. package/src/lib/runtime/ai-eval-memory-firestore.js.map +1 -0
  487. package/src/lib/runtime/ai-eval.d.ts +441 -0
  488. package/src/lib/runtime/ai-eval.js +1151 -0
  489. package/src/lib/runtime/ai-eval.js.map +1 -0
  490. package/src/lib/runtime/ai-gate.d.ts +130 -0
  491. package/src/lib/runtime/ai-gate.js +272 -0
  492. package/src/lib/runtime/ai-gate.js.map +1 -0
  493. package/src/lib/runtime/ai-generation-bounds.d.ts +24 -0
  494. package/src/lib/runtime/ai-generation-bounds.js +23 -0
  495. package/src/lib/runtime/ai-generation-bounds.js.map +1 -0
  496. package/src/lib/runtime/ai-insight-check.d.ts +76 -0
  497. package/src/lib/runtime/ai-insight-check.js +281 -0
  498. package/src/lib/runtime/ai-insight-check.js.map +1 -0
  499. package/src/lib/runtime/ai-node-tree.d.ts +181 -0
  500. package/src/lib/runtime/ai-node-tree.js +931 -0
  501. package/src/lib/runtime/ai-node-tree.js.map +1 -0
  502. package/src/lib/runtime/ai-page-links.d.ts +79 -0
  503. package/src/lib/runtime/ai-page-links.js +135 -0
  504. package/src/lib/runtime/ai-page-links.js.map +1 -0
  505. package/src/lib/runtime/ai-palette.d.ts +252 -0
  506. package/src/lib/runtime/ai-palette.generated.d.ts +34 -0
  507. package/src/lib/runtime/ai-palette.generated.js +5263 -0
  508. package/src/lib/runtime/ai-palette.generated.js.map +1 -0
  509. package/src/lib/runtime/ai-palette.js +187 -0
  510. package/src/lib/runtime/ai-palette.js.map +1 -0
  511. package/src/lib/runtime/ai-products-generation.d.ts +107 -0
  512. package/src/lib/runtime/ai-products-generation.js +250 -0
  513. package/src/lib/runtime/ai-products-generation.js.map +1 -0
  514. package/src/lib/runtime/ai-repeated-items.d.ts +95 -0
  515. package/src/lib/runtime/ai-repeated-items.js +397 -0
  516. package/src/lib/runtime/ai-repeated-items.js.map +1 -0
  517. package/src/lib/runtime/ai-runtime.d.ts +148 -0
  518. package/src/lib/runtime/ai-runtime.js +237 -0
  519. package/src/lib/runtime/ai-runtime.js.map +1 -0
  520. package/src/lib/runtime/ai-template-examples.d.ts +71 -0
  521. package/src/lib/runtime/ai-template-examples.js +135 -0
  522. package/src/lib/runtime/ai-template-examples.js.map +1 -0
  523. package/src/lib/runtime/assist-answer-cache.d.ts +80 -0
  524. package/src/lib/runtime/assist-answer-cache.js +184 -0
  525. package/src/lib/runtime/assist-answer-cache.js.map +1 -0
  526. package/src/lib/runtime/seo-audit.d.ts +93 -0
  527. package/src/lib/runtime/seo-audit.js +260 -0
  528. package/src/lib/runtime/seo-audit.js.map +1 -0
  529. package/src/lib/runtime/seo-content-fixes.d.ts +41 -0
  530. package/src/lib/runtime/seo-content-fixes.js +168 -0
  531. package/src/lib/runtime/seo-content-fixes.js.map +1 -0
  532. package/src/lib/runtime/seo-fields.d.ts +152 -0
  533. package/src/lib/runtime/seo-fields.js +215 -0
  534. package/src/lib/runtime/seo-fields.js.map +1 -0
  535. package/src/lib/runtime/seo-page-facts.d.ts +61 -0
  536. package/src/lib/runtime/seo-page-facts.js +150 -0
  537. package/src/lib/runtime/seo-page-facts.js.map +1 -0
  538. package/src/lib/runtime/site-inventory.d.ts +63 -0
  539. package/src/lib/runtime/site-inventory.js +230 -0
  540. package/src/lib/runtime/site-inventory.js.map +1 -0
  541. package/src/lib/server/ai-admin-org.d.ts +33 -0
  542. package/src/lib/server/ai-admin-org.js +381 -0
  543. package/src/lib/server/ai-admin-org.js.map +1 -0
  544. package/src/lib/server/ai-admin-orgs-spend.d.ts +40 -0
  545. package/src/lib/server/ai-admin-orgs-spend.js +129 -0
  546. package/src/lib/server/ai-admin-orgs-spend.js.map +1 -0
  547. package/src/lib/server/ai-admin-overage.d.ts +19 -0
  548. package/src/lib/server/ai-admin-overage.js +246 -0
  549. package/src/lib/server/ai-admin-overage.js.map +1 -0
  550. package/src/lib/server/ai-admin-signals.d.ts +34 -0
  551. package/src/lib/server/ai-admin-signals.js +330 -0
  552. package/src/lib/server/ai-admin-signals.js.map +1 -0
  553. package/src/lib/server/ai-admin-user.d.ts +27 -0
  554. package/src/lib/server/ai-admin-user.js +128 -0
  555. package/src/lib/server/ai-admin-user.js.map +1 -0
  556. package/src/lib/server/ai-allotments.d.ts +27 -0
  557. package/src/lib/server/ai-allotments.js +544 -0
  558. package/src/lib/server/ai-allotments.js.map +1 -0
  559. package/src/lib/server/ai-assist-prompts.d.ts +102 -0
  560. package/src/lib/server/ai-assist-prompts.js +207 -0
  561. package/src/lib/server/ai-assist-prompts.js.map +1 -0
  562. package/src/lib/server/ai-assist.d.ts +119 -0
  563. package/src/lib/server/ai-assist.js +517 -0
  564. package/src/lib/server/ai-assist.js.map +1 -0
  565. package/src/lib/server/ai-crm-answer.d.ts +30 -0
  566. package/src/lib/server/ai-crm-answer.js +98 -0
  567. package/src/lib/server/ai-crm-answer.js.map +1 -0
  568. package/src/lib/server/ai-generate-component.d.ts +111 -0
  569. package/src/lib/server/ai-generate-component.js +643 -0
  570. package/src/lib/server/ai-generate-component.js.map +1 -0
  571. package/src/lib/server/ai-host-permissions.d.ts +46 -0
  572. package/src/lib/server/ai-host-permissions.js +204 -0
  573. package/src/lib/server/ai-host-permissions.js.map +1 -0
  574. package/src/lib/server/ai-insight-answer.d.ts +30 -0
  575. package/src/lib/server/ai-insight-answer.js +83 -0
  576. package/src/lib/server/ai-insight-answer.js.map +1 -0
  577. package/src/lib/server/ai-insight-digest-route.d.ts +30 -0
  578. package/src/lib/server/ai-insight-digest-route.js +156 -0
  579. package/src/lib/server/ai-insight-digest-route.js.map +1 -0
  580. package/src/lib/server/ai-jobs-batch.d.ts +48 -0
  581. package/src/lib/server/ai-jobs-batch.js +306 -0
  582. package/src/lib/server/ai-jobs-batch.js.map +1 -0
  583. package/src/lib/server/ai-jobs-beat-route.d.ts +36 -0
  584. package/src/lib/server/ai-jobs-beat-route.js +86 -0
  585. package/src/lib/server/ai-jobs-beat-route.js.map +1 -0
  586. package/src/lib/server/ai-jobs-cancel.d.ts +30 -0
  587. package/src/lib/server/ai-jobs-cancel.js +74 -0
  588. package/src/lib/server/ai-jobs-cancel.js.map +1 -0
  589. package/src/lib/server/ai-jobs-events-route.d.ts +31 -0
  590. package/src/lib/server/ai-jobs-events-route.js +51 -0
  591. package/src/lib/server/ai-jobs-events-route.js.map +1 -0
  592. package/src/lib/server/ai-jobs-events.d.ts +55 -0
  593. package/src/lib/server/ai-jobs-events.js +144 -0
  594. package/src/lib/server/ai-jobs-events.js.map +1 -0
  595. package/src/lib/server/ai-jobs-gate.d.ts +47 -0
  596. package/src/lib/server/ai-jobs-gate.js +106 -0
  597. package/src/lib/server/ai-jobs-gate.js.map +1 -0
  598. package/src/lib/server/ai-jobs-resume.d.ts +23 -0
  599. package/src/lib/server/ai-jobs-resume.js +209 -0
  600. package/src/lib/server/ai-jobs-resume.js.map +1 -0
  601. package/src/lib/server/ai-jobs-route.d.ts +32 -0
  602. package/src/lib/server/ai-jobs-route.js +307 -0
  603. package/src/lib/server/ai-jobs-route.js.map +1 -0
  604. package/src/lib/server/ai-models.d.ts +18 -0
  605. package/src/lib/server/ai-models.js +134 -0
  606. package/src/lib/server/ai-models.js.map +1 -0
  607. package/src/lib/server/ai-seo-apply.d.ts +53 -0
  608. package/src/lib/server/ai-seo-apply.js +294 -0
  609. package/src/lib/server/ai-seo-apply.js.map +1 -0
  610. package/src/lib/server/ai-usage.d.ts +18 -0
  611. package/src/lib/server/ai-usage.js +220 -0
  612. package/src/lib/server/ai-usage.js.map +1 -0
  613. package/src/lib/server/assist-chat.d.ts +234 -0
  614. package/src/lib/server/assist-chat.js +1446 -0
  615. package/src/lib/server/assist-chat.js.map +1 -0
  616. package/src/lib/server/assist-edit-applied.d.ts +22 -0
  617. package/src/lib/server/assist-edit-applied.js +239 -0
  618. package/src/lib/server/assist-edit-applied.js.map +1 -0
  619. package/src/lib/server/assist-edit.d.ts +124 -0
  620. package/src/lib/server/assist-edit.js +1000 -0
  621. package/src/lib/server/assist-edit.js.map +1 -0
  622. package/src/lib/server/assist-feedback.d.ts +31 -0
  623. package/src/lib/server/assist-feedback.js +115 -0
  624. package/src/lib/server/assist-feedback.js.map +1 -0
  625. package/src/lib/server/assist-view-context.d.ts +343 -0
  626. package/src/lib/server/assist-view-context.js +690 -0
  627. package/src/lib/server/assist-view-context.js.map +1 -0
  628. package/src/lib/server/billing-credits.d.ts +59 -0
  629. package/src/lib/server/billing-credits.js +146 -0
  630. package/src/lib/server/billing-credits.js.map +1 -0
  631. package/src/lib/server/billing-overage.d.ts +19 -0
  632. package/src/lib/server/billing-overage.js +337 -0
  633. package/src/lib/server/billing-overage.js.map +1 -0
  634. package/src/lib/server.d.ts +32 -0
  635. package/src/lib/server.js +265 -0
  636. package/src/lib/server.js.map +1 -0
  637. package/src/lib/subprocessors.d.ts +18 -0
  638. package/src/lib/subprocessors.js +52 -0
  639. package/src/lib/subprocessors.js.map +1 -0
  640. package/src/lib/tools/ai-component-tool.d.ts +99 -0
  641. package/src/lib/tools/ai-component-tool.js +369 -0
  642. package/src/lib/tools/ai-component-tool.js.map +1 -0
  643. package/src/lib/tools/ai-crm-tool.d.ts +106 -0
  644. package/src/lib/tools/ai-crm-tool.js +488 -0
  645. package/src/lib/tools/ai-crm-tool.js.map +1 -0
  646. package/src/lib/tools/ai-duplicate-resource-tool.d.ts +71 -0
  647. package/src/lib/tools/ai-duplicate-resource-tool.js +164 -0
  648. package/src/lib/tools/ai-duplicate-resource-tool.js.map +1 -0
  649. package/src/lib/tools/ai-experiment-tool.d.ts +40 -0
  650. package/src/lib/tools/ai-experiment-tool.js +155 -0
  651. package/src/lib/tools/ai-experiment-tool.js.map +1 -0
  652. package/src/lib/tools/ai-insight-tool.d.ts +46 -0
  653. package/src/lib/tools/ai-insight-tool.js +200 -0
  654. package/src/lib/tools/ai-insight-tool.js.map +1 -0
  655. package/src/lib/tools/ai-inventory-lookup-tool.d.ts +86 -0
  656. package/src/lib/tools/ai-inventory-lookup-tool.js +164 -0
  657. package/src/lib/tools/ai-inventory-lookup-tool.js.map +1 -0
  658. package/src/lib/tools/ai-products-tool.d.ts +65 -0
  659. package/src/lib/tools/ai-products-tool.js +644 -0
  660. package/src/lib/tools/ai-products-tool.js.map +1 -0
  661. package/src/lib/tools/ai-seo-tool.d.ts +162 -0
  662. package/src/lib/tools/ai-seo-tool.js +546 -0
  663. package/src/lib/tools/ai-seo-tool.js.map +1 -0
  664. package/src/lib/tools/ai-theme-tool.d.ts +101 -0
  665. package/src/lib/tools/ai-theme-tool.js +562 -0
  666. package/src/lib/tools/ai-theme-tool.js.map +1 -0
  667. package/src/lib/tools/ai-workflow-tool.d.ts +166 -0
  668. package/src/lib/tools/ai-workflow-tool.js +860 -0
  669. package/src/lib/tools/ai-workflow-tool.js.map +1 -0
  670. package/src/lib/usage/ai-allotment-alerts.d.ts +72 -0
  671. package/src/lib/usage/ai-allotment-alerts.js +157 -0
  672. package/src/lib/usage/ai-allotment-alerts.js.map +1 -0
  673. package/src/lib/usage/ai-allotments.d.ts +125 -0
  674. package/src/lib/usage/ai-allotments.js +239 -0
  675. package/src/lib/usage/ai-allotments.js.map +1 -0
  676. package/src/lib/usage/ai-model-sample.d.ts +36 -0
  677. package/src/lib/usage/ai-model-sample.js +68 -0
  678. package/src/lib/usage/ai-model-sample.js.map +1 -0
  679. package/src/lib/usage/ai-usage-alerts.d.ts +55 -0
  680. package/src/lib/usage/ai-usage-alerts.js +114 -0
  681. package/src/lib/usage/ai-usage-alerts.js.map +1 -0
  682. package/src/lib/usage/ai-usage-by-user.d.ts +161 -0
  683. package/src/lib/usage/ai-usage-by-user.js +211 -0
  684. package/src/lib/usage/ai-usage-by-user.js.map +1 -0
  685. package/src/lib/usage/ai-usage-eraser.d.ts +29 -0
  686. package/src/lib/usage/ai-usage-eraser.js +40 -0
  687. package/src/lib/usage/ai-usage-eraser.js.map +1 -0
  688. package/src/lib/usage/ai-usage-meter.d.ts +39 -0
  689. package/src/lib/usage/ai-usage-meter.js +85 -0
  690. package/src/lib/usage/ai-usage-meter.js.map +1 -0
  691. package/src/lib/usage/ai-usage-wire.d.ts +184 -0
  692. package/src/lib/usage/ai-usage-wire.js +98 -0
  693. package/src/lib/usage/ai-usage-wire.js.map +1 -0
  694. package/src/lib/usage/assist-ceiling.d.ts +87 -0
  695. package/src/lib/usage/assist-ceiling.js +110 -0
  696. package/src/lib/usage/assist-ceiling.js.map +1 -0
  697. package/src/lib/usage/assist-free-taste.d.ts +225 -0
  698. package/src/lib/usage/assist-free-taste.js +308 -0
  699. package/src/lib/usage/assist-free-taste.js.map +1 -0
  700. package/src/lib/usage/assist-refusals.d.ts +69 -0
  701. package/src/lib/usage/assist-refusals.js +79 -0
  702. package/src/lib/usage/assist-refusals.js.map +1 -0
  703. package/src/lib/usage/assist-signal-mining.d.ts +375 -0
  704. package/src/lib/usage/assist-signal-mining.js +344 -0
  705. package/src/lib/usage/assist-signal-mining.js.map +1 -0
  706. package/src/lib/usage/assist-usage.d.ts +571 -0
  707. package/src/lib/usage/assist-usage.js +978 -0
  708. package/src/lib/usage/assist-usage.js.map +1 -0
  709. package/src/lib/usage/staff-org-ai.d.ts +242 -0
  710. package/src/lib/usage/staff-org-ai.js +173 -0
  711. package/src/lib/usage/staff-org-ai.js.map +1 -0
  712. package/src/lib/usage/staff-org-usage-ai.d.ts +83 -0
  713. package/src/lib/usage/staff-org-usage-ai.js +59 -0
  714. package/src/lib/usage/staff-org-usage-ai.js.map +1 -0
  715. package/src/lib/usage/staff-orgs-ai-spend.d.ts +83 -0
  716. package/src/lib/usage/staff-orgs-ai-spend.js +114 -0
  717. package/src/lib/usage/staff-orgs-ai-spend.js.map +1 -0
@@ -0,0 +1,152 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2026 Aglyn LLC
4
+ *
5
+ * Licensed under the Apache License, Version 2.0 (the "License");
6
+ * you may not use this file except in compliance with the License.
7
+ * You may obtain a copy of the License at
8
+ *
9
+ * http://www.apache.org/licenses/LICENSE-2.0
10
+ *
11
+ * Unless required by applicable law or agreed to in writing, software
12
+ * distributed under the License is distributed on an "AS IS" BASIS,
13
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ * See the License for the specific language governing permissions and
15
+ * limitations under the License.
16
+ */
17
+ import type { SeoListingFieldKey } from '@aglyn/aglyn/app-utils/seo-listing-fields';
18
+ import type { AiSeoFieldValues } from '../model/ai-seo';
19
+ import type { AiStepKind } from '../providers/catalog';
20
+ import type { AiProvider } from '../providers/contract';
21
+ import { type AiPluginSettings } from '../providers/routing';
22
+ import { type AiValidatedGeneration } from './ai-doctrine';
23
+ import type { AiSystemBlock } from './ai-runtime';
24
+ /**
25
+ * SEO fields by AI (AGL-2910): a search listing — title, description,
26
+ * breadcrumb label, image description — written from what a page or a
27
+ * product actually says, and held to the lengths its editor enforces.
28
+ *
29
+ * `generateSeoFields` is the one entry point. The "Write SEO" card on a
30
+ * page's SEO panel and on a product's listing calls it through an `seo` job,
31
+ * and a page generator calls it for the title and description of the page it
32
+ * builds. It proposes; it never writes a listing anywhere.
33
+ *
34
+ * The tool the model answers through, and the check that holds the answer to
35
+ * the editor, are `tools/ai-seo-tool.ts`: the tool is built from the editor's
36
+ * own field list, so a field and its length are said once.
37
+ *
38
+ * ## The request
39
+ *
40
+ * The fast tier through the routing table (`job.seo`), never a model
41
+ * literal, and the building doctrine's generation call
42
+ * (`runValidatedGeneration`, AGL-3009): the doctrine's cached block, which
43
+ * carries the acceptable-use rules, then these rules, cached after it. The
44
+ * page's text, its current listing, the site's name and the target keywords
45
+ * ride in the user turn, so no byte of a site sits inside the cached prefix,
46
+ * and no site inventory is sent: a listing is written from its page.
47
+ */
48
+ /**
49
+ * The output budget, from the routing table. The largest answer the tool
50
+ * accepts — every field at its limit — is under 300 tokens of JSON
51
+ * (`ai-job-seo-step.spec.ts` measures it); the rest is headroom, and the fast
52
+ * tier thinks in none of it.
53
+ */
54
+ export declare const AI_SEO_FIELDS_MAX_TOKENS: number;
55
+ /** What a listing request carries, and therefore which rules it is sent. */
56
+ export interface AiSeoFieldsInstructionShape {
57
+ fields: readonly SeoListingFieldKey[];
58
+ keywords: boolean;
59
+ otherTitles: boolean;
60
+ }
61
+ /**
62
+ * The rules for one listing request.
63
+ *
64
+ * Byte-identical for every request of the same SHAPE, and identical across
65
+ * workspaces at every shape: no site's name, text or listing is in here, so
66
+ * two tenants writing the same kind of listing send the same rules. That is
67
+ * the invariant `runtime/ai-prompt-cache.spec.ts` holds, and it is weaker
68
+ * than "one block for everything" on purpose — a rule about target keywords
69
+ * is worth nothing to a request that carries none, and `job.seo` runs on a
70
+ * model that caches no prompt this short, so an unread rule is simply paid
71
+ * for at full input rate on every attempt and every re-ask.
72
+ */
73
+ export declare function aiSeoFieldsInstructions(shape: AiSeoFieldsInstructionShape): AiSystemBlock[];
74
+ /** The rules for a listing of the default shape, for a door that names no other. */
75
+ export declare const AI_SEO_FIELDS_INSTRUCTIONS: AiSystemBlock[];
76
+ /**
77
+ * What the site itself is, in the words of whoever set it up (AGL-2918).
78
+ *
79
+ * A page's own text says what the page is; it does not say who the page is
80
+ * written for. On a site whose pages have just been generated that gap is at
81
+ * its widest — every page reads like the same competent stranger wrote it —
82
+ * so the words the owner used are carried into the listing rather than
83
+ * inferred back out of the copy they produced.
84
+ *
85
+ * It rides in the user turn and nowhere else: it is one site's own words, so
86
+ * putting it in a rules block would key the platform's cache entry on a
87
+ * tenant's sentence, and the rules already say to write from what is given.
88
+ */
89
+ export interface AiSeoSiteWords {
90
+ /** What kind of site it is: "a neighborhood dog groomer". */
91
+ about?: string | null;
92
+ /** Who it is for: "local dog owners who want a regular groom booked online". */
93
+ audience?: string | null;
94
+ }
95
+ export interface AiSeoFieldsPromptInput {
96
+ subject: {
97
+ kind: 'screen' | 'product';
98
+ name: string;
99
+ path?: string | null;
100
+ };
101
+ /** The site's name, as its visitors see it. */
102
+ brand: string;
103
+ /** What the site is and who it is for, where the caller knows (AGL-2918). */
104
+ site?: AiSeoSiteWords | null;
105
+ /** What the page or the product says: a page's Markdown, a product's description. */
106
+ text: string;
107
+ fields: readonly SeoListingFieldKey[];
108
+ current?: AiSeoFieldValues;
109
+ /**
110
+ * What is known about the share image, when the listing has one: the
111
+ * description it carries, and the page text around the same picture where
112
+ * the page shows it.
113
+ */
114
+ image?: {
115
+ alt?: string | null;
116
+ context?: string | null;
117
+ } | null;
118
+ keywords?: readonly string[];
119
+ otherTitles?: readonly string[];
120
+ }
121
+ /** The user turn: the subject, what it says now, and the page's own text. */
122
+ export declare function aiSeoFieldsPrompt(input: AiSeoFieldsPromptInput): string;
123
+ export interface GenerateSeoFieldsInput extends Omit<AiSeoFieldsPromptInput, 'fields'> {
124
+ /** The fields to write; the title, description and breadcrumb label when omitted. */
125
+ fields?: readonly SeoListingFieldKey[];
126
+ /** The step kind the call is routed as; `job.seo` when omitted. */
127
+ step?: AiStepKind;
128
+ settings?: AiPluginSettings;
129
+ model?: string;
130
+ /**
131
+ * The answer's ceiling: `AI_SEO_FIELDS_MAX_TOKENS` when omitted. A job step
132
+ * passes the most its registered time allows on the model it runs
133
+ * (AGL-3035).
134
+ */
135
+ maxTokens?: number;
136
+ signal?: AbortSignal;
137
+ provider?: AiProvider;
138
+ }
139
+ /** What a listing is written with when the caller names no fields. */
140
+ export declare const AI_SEO_DEFAULT_FIELDS: readonly SeoListingFieldKey[];
141
+ /**
142
+ * Propose a search listing for a page or a product.
143
+ *
144
+ * STABLE: a page generator calls this for the title and description of a
145
+ * page it builds (`fields: ['title', 'description']`), and the `seo` job
146
+ * calls it for a page's or a product's whole listing. It asks the routing
147
+ * table's `job.seo` model through the doctrine's generation call and resolves
148
+ * to its result — `ok` with the values, `needs_input` when the answer could
149
+ * not be held to the editor after one re-ask, `refused` when the model
150
+ * declined. It writes nothing.
151
+ */
152
+ export declare function generateSeoFields(input: GenerateSeoFieldsInput): Promise<AiValidatedGeneration<AiSeoFieldValues>>;
@@ -0,0 +1,215 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2026 Aglyn LLC
4
+ *
5
+ * Licensed under the Apache License, Version 2.0 (the "License");
6
+ * you may not use this file except in compliance with the License.
7
+ * You may obtain a copy of the License at
8
+ *
9
+ * http://www.apache.org/licenses/LICENSE-2.0
10
+ *
11
+ * Unless required by applicable law or agreed to in writing, software
12
+ * distributed under the License is distributed on an "AS IS" BASIS,
13
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ * See the License for the specific language governing permissions and
15
+ * limitations under the License.
16
+ */ import { _ as _extends } from "@swc/helpers/_/_extends";
17
+ import { AI_ROUTING_TABLE } from "../providers/routing.js";
18
+ import { AI_SEO_FIELDS_TOOL_NAME, aiSeoFieldsTool, checkAiSeoFields, orderedSeoListingFields } from "../tools/ai-seo-tool.js";
19
+ import { runValidatedGeneration } from "./ai-doctrine.js";
20
+ /**
21
+ * SEO fields by AI (AGL-2910): a search listing — title, description,
22
+ * breadcrumb label, image description — written from what a page or a
23
+ * product actually says, and held to the lengths its editor enforces.
24
+ *
25
+ * `generateSeoFields` is the one entry point. The "Write SEO" card on a
26
+ * page's SEO panel and on a product's listing calls it through an `seo` job,
27
+ * and a page generator calls it for the title and description of the page it
28
+ * builds. It proposes; it never writes a listing anywhere.
29
+ *
30
+ * The tool the model answers through, and the check that holds the answer to
31
+ * the editor, are `tools/ai-seo-tool.ts`: the tool is built from the editor's
32
+ * own field list, so a field and its length are said once.
33
+ *
34
+ * ## The request
35
+ *
36
+ * The fast tier through the routing table (`job.seo`), never a model
37
+ * literal, and the building doctrine's generation call
38
+ * (`runValidatedGeneration`, AGL-3009): the doctrine's cached block, which
39
+ * carries the acceptable-use rules, then these rules, cached after it. The
40
+ * page's text, its current listing, the site's name and the target keywords
41
+ * ride in the user turn, so no byte of a site sits inside the cached prefix,
42
+ * and no site inventory is sent: a listing is written from its page.
43
+ */ /* ------------------------------------------------------------------------ *
44
+ * The request
45
+ * ------------------------------------------------------------------------ */ /**
46
+ * The output budget, from the routing table. The largest answer the tool
47
+ * accepts — every field at its limit — is under 300 tokens of JSON
48
+ * (`ai-job-seo-step.spec.ts` measures it); the rest is headroom, and the fast
49
+ * tier thinks in none of it.
50
+ */ export const AI_SEO_FIELDS_MAX_TOKENS = AI_ROUTING_TABLE['job.seo'].maxTokens;
51
+ /** How many other pages' titles a prompt lists for the model to avoid. */ const OTHER_TITLES_LISTED = 40;
52
+ /**
53
+ * What one listing field's rule ADDS to the tool's own description of that
54
+ * field (AGL-2937), stated only when the field is asked for.
55
+ *
56
+ * The schema the answer arrives through is built from the editor's field
57
+ * catalog, and it already names each field, says what the value is for and
58
+ * states its length. It rides in the same request, ahead of these blocks, so
59
+ * a rule that restated it would be the same sentence billed twice on a door
60
+ * whose prompt no model will cache. Each rule here is therefore only what
61
+ * the schema does not say: how to write the field rather than what it is.
62
+ * The image description has no rule at all, because its description already
63
+ * carries both halves of one — what it describes, and when to answer null.
64
+ *
65
+ * `runtime/ai-prompt-cache.spec.ts` holds the pair together: whatever
66
+ * `checkAiSeoFields` can refuse an answer for, the request has to state
67
+ * somewhere, in a block or in the schema.
68
+ */ const AI_SEO_FIELD_RULES = {
69
+ title: 'The title says what the page is, specifically and in plain words; add the site name only where it helps.',
70
+ description: 'The description is one or two sentences: no quotation marks, no emoji, no capitals for emphasis.',
71
+ breadcrumb: 'The breadcrumb label is one to three words.'
72
+ };
73
+ /**
74
+ * The rules for one listing request.
75
+ *
76
+ * Byte-identical for every request of the same SHAPE, and identical across
77
+ * workspaces at every shape: no site's name, text or listing is in here, so
78
+ * two tenants writing the same kind of listing send the same rules. That is
79
+ * the invariant `runtime/ai-prompt-cache.spec.ts` holds, and it is weaker
80
+ * than "one block for everything" on purpose — a rule about target keywords
81
+ * is worth nothing to a request that carries none, and `job.seo` runs on a
82
+ * model that caches no prompt this short, so an unread rule is simply paid
83
+ * for at full input rate on every attempt and every re-ask.
84
+ */ export function aiSeoFieldsInstructions(shape) {
85
+ const fields = orderedSeoListingFields(shape.fields);
86
+ const rules = [
87
+ 'Write only from the text you are given. Never invent a fact, a price, a name, a place, an offer or a claim the text does not state.',
88
+ ...fields.map((key)=>AI_SEO_FIELD_RULES[key]).filter((rule)=>Boolean(rule)),
89
+ // Every field a person reads is held to this, keywords or none, so it is
90
+ // stated on every shape rather than inside the keyword rule it used to
91
+ // ride in: `checkAiSeoFields` refuses a repeat in a listing that named
92
+ // no keywords too.
93
+ 'Never repeat the same word three times in one field.',
94
+ ...shape.keywords ? [
95
+ 'A target keyword goes in only where the page is about it and it reads naturally: at most once in the title and once in the description. Never list keywords, and leave out a keyword the page is not about.'
96
+ ] : [],
97
+ ...shape.otherTitles ? [
98
+ 'Do not reuse a title another page of the site already uses.'
99
+ ] : [],
100
+ 'Write in the language of the page text.'
101
+ ];
102
+ return [
103
+ {
104
+ text: 'You write the search listing for one page or one product of a website: what a search result shows.\n\n' + `Answer by calling ${AI_SEO_FIELDS_TOOL_NAME} exactly once. A reply in prose cannot be used.\n\n` + `Rules:\n${rules.map((rule)=>`- ${rule}`).join('\n')}`,
105
+ cacheBreakpoint: true
106
+ }
107
+ ];
108
+ }
109
+ /** The rules for a listing of the default shape, for a door that names no other. */ export const AI_SEO_FIELDS_INSTRUCTIONS = aiSeoFieldsInstructions({
110
+ fields: [
111
+ 'title',
112
+ 'description',
113
+ 'breadcrumb'
114
+ ],
115
+ keywords: false,
116
+ otherTitles: false
117
+ });
118
+ /** The longest a site's own words run in a prompt; they are a phrase, not copy. */ const SITE_WORDS_MAX_CHARS = 160;
119
+ /** One of the site's own words as its line reads, or nothing when it says nothing. */ function siteWordsLine(label, value) {
120
+ const text = (value != null ? value : '').replace(/\s+/g, ' ').trim().slice(0, SITE_WORDS_MAX_CHARS).trim();
121
+ return text ? `${label}: ${text}` : '';
122
+ }
123
+ /** The user turn: the subject, what it says now, and the page's own text. */ export function aiSeoFieldsPrompt(input) {
124
+ var _input_site, _input_site1, _input_keywords, _input_otherTitles;
125
+ const fields = orderedSeoListingFields(input.fields);
126
+ const lines = [
127
+ `Site: ${input.brand || 'untitled site'}`,
128
+ siteWordsLine('What the site is', (_input_site = input.site) == null ? void 0 : _input_site.about),
129
+ siteWordsLine('Who the site is for', (_input_site1 = input.site) == null ? void 0 : _input_site1.audience),
130
+ input.subject.kind === 'product' ? `Product: ${input.subject.name || 'untitled product'}` : `Page: ${input.subject.name || 'untitled page'}${input.subject.path ? ` (${input.subject.path})` : ''}`,
131
+ `Fields to write: ${fields.join(', ')}`
132
+ ].filter(Boolean);
133
+ const current = fields.map((key)=>{
134
+ var _input_current_key, _input_current;
135
+ return [
136
+ key,
137
+ (_input_current = input.current) == null ? void 0 : (_input_current_key = _input_current[key]) == null ? void 0 : _input_current_key.trim()
138
+ ];
139
+ }).filter(([, value])=>Boolean(value));
140
+ if (current.length) {
141
+ lines.push('Current listing:', ...current.map(([key, value])=>`- ${key}: ${value}`));
142
+ }
143
+ if (input.image) {
144
+ const known = [
145
+ input.image.alt && `its current description: ${input.image.alt}`,
146
+ input.image.context && `the page text beside it: ${input.image.context}`
147
+ ].filter(Boolean).join('; ');
148
+ lines.push(`Share image: ${known || 'set, and nothing is known about what it shows'}`);
149
+ }
150
+ if ((_input_keywords = input.keywords) == null ? void 0 : _input_keywords.length) lines.push(`Target keywords: ${input.keywords.join(', ')}`);
151
+ if ((_input_otherTitles = input.otherTitles) == null ? void 0 : _input_otherTitles.length) {
152
+ lines.push('Titles other pages already use:', ...input.otherTitles.slice(0, OTHER_TITLES_LISTED).map((title)=>`- ${title}`));
153
+ }
154
+ lines.push('', input.subject.kind === 'product' ? 'Product description:' : 'Page text:', input.text.trim() || '(no text)');
155
+ return lines.join('\n');
156
+ }
157
+ /** What a listing is written with when the caller names no fields. */ export const AI_SEO_DEFAULT_FIELDS = [
158
+ 'title',
159
+ 'description',
160
+ 'breadcrumb'
161
+ ];
162
+ /**
163
+ * Propose a search listing for a page or a product.
164
+ *
165
+ * STABLE: a page generator calls this for the title and description of a
166
+ * page it builds (`fields: ['title', 'description']`), and the `seo` job
167
+ * calls it for a page's or a product's whole listing. It asks the routing
168
+ * table's `job.seo` model through the doctrine's generation call and resolves
169
+ * to its result — `ok` with the values, `needs_input` when the answer could
170
+ * not be held to the editor after one re-ask, `refused` when the model
171
+ * declined. It writes nothing.
172
+ */ export async function generateSeoFields(input) {
173
+ var _input_fields, _input_keywords, _input_step, _input_maxTokens;
174
+ var _input_otherTitles;
175
+ const hasImage = Boolean(input.image);
176
+ const fields = orderedSeoListingFields((_input_fields = input.fields) != null ? _input_fields : AI_SEO_DEFAULT_FIELDS).filter((key)=>key !== 'imageAlt' || hasImage);
177
+ const keywords = (_input_keywords = input.keywords) != null ? _input_keywords : [];
178
+ return runValidatedGeneration('seo-fields', _extends({
179
+ step: (_input_step = input.step) != null ? _input_step : 'job.seo'
180
+ }, input.settings ? {
181
+ settings: input.settings
182
+ } : {}, input.model ? {
183
+ model: input.model
184
+ } : {}, {
185
+ instructions: aiSeoFieldsInstructions({
186
+ fields,
187
+ keywords: keywords.length > 0,
188
+ otherTitles: Boolean((_input_otherTitles = input.otherTitles) == null ? void 0 : _input_otherTitles.length)
189
+ }),
190
+ messages: [
191
+ {
192
+ role: 'user',
193
+ content: aiSeoFieldsPrompt(_extends({}, input, {
194
+ fields,
195
+ keywords
196
+ }))
197
+ }
198
+ ],
199
+ tool: aiSeoFieldsTool(fields),
200
+ maxTokens: (_input_maxTokens = input.maxTokens) != null ? _input_maxTokens : AI_SEO_FIELDS_MAX_TOKENS
201
+ }, input.signal ? {
202
+ signal: input.signal
203
+ } : {}, input.provider ? {
204
+ provider: input.provider
205
+ } : {}, {
206
+ check: (answer)=>checkAiSeoFields(answer, {
207
+ fields,
208
+ hasImage,
209
+ keywords,
210
+ otherTitles: input.otherTitles
211
+ })
212
+ }));
213
+ }
214
+
215
+ //# sourceMappingURL=seo-fields.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../../../../libs/plugins/ai/src/lib/runtime/seo-fields.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 type { SeoListingFieldKey } from '@aglyn/aglyn/app-utils/seo-listing-fields'\nimport type { AiSeoFieldValues } from '../model/ai-seo'\nimport type { AiStepKind } from '../providers/catalog'\nimport type { AiProvider } from '../providers/contract'\nimport { AI_ROUTING_TABLE, type AiPluginSettings } from '../providers/routing'\nimport {\n AI_SEO_FIELDS_TOOL_NAME,\n aiSeoFieldsTool,\n checkAiSeoFields,\n orderedSeoListingFields,\n} from '../tools/ai-seo-tool'\nimport { runValidatedGeneration, type AiValidatedGeneration } from './ai-doctrine'\nimport type { AiSystemBlock } from './ai-runtime'\n\n/**\n * SEO fields by AI (AGL-2910): a search listing — title, description,\n * breadcrumb label, image description — written from what a page or a\n * product actually says, and held to the lengths its editor enforces.\n *\n * `generateSeoFields` is the one entry point. The \"Write SEO\" card on a\n * page's SEO panel and on a product's listing calls it through an `seo` job,\n * and a page generator calls it for the title and description of the page it\n * builds. It proposes; it never writes a listing anywhere.\n *\n * The tool the model answers through, and the check that holds the answer to\n * the editor, are `tools/ai-seo-tool.ts`: the tool is built from the editor's\n * own field list, so a field and its length are said once.\n *\n * ## The request\n *\n * The fast tier through the routing table (`job.seo`), never a model\n * literal, and the building doctrine's generation call\n * (`runValidatedGeneration`, AGL-3009): the doctrine's cached block, which\n * carries the acceptable-use rules, then these rules, cached after it. The\n * page's text, its current listing, the site's name and the target keywords\n * ride in the user turn, so no byte of a site sits inside the cached prefix,\n * and no site inventory is sent: a listing is written from its page.\n */\n\n/* ------------------------------------------------------------------------ *\n * The request\n * ------------------------------------------------------------------------ */\n\n/**\n * The output budget, from the routing table. The largest answer the tool\n * accepts — every field at its limit — is under 300 tokens of JSON\n * (`ai-job-seo-step.spec.ts` measures it); the rest is headroom, and the fast\n * tier thinks in none of it.\n */\nexport const AI_SEO_FIELDS_MAX_TOKENS = AI_ROUTING_TABLE['job.seo'].maxTokens\n\n/** How many other pages' titles a prompt lists for the model to avoid. */\nconst OTHER_TITLES_LISTED = 40\n\n/**\n * What one listing field's rule ADDS to the tool's own description of that\n * field (AGL-2937), stated only when the field is asked for.\n *\n * The schema the answer arrives through is built from the editor's field\n * catalog, and it already names each field, says what the value is for and\n * states its length. It rides in the same request, ahead of these blocks, so\n * a rule that restated it would be the same sentence billed twice on a door\n * whose prompt no model will cache. Each rule here is therefore only what\n * the schema does not say: how to write the field rather than what it is.\n * The image description has no rule at all, because its description already\n * carries both halves of one — what it describes, and when to answer null.\n *\n * `runtime/ai-prompt-cache.spec.ts` holds the pair together: whatever\n * `checkAiSeoFields` can refuse an answer for, the request has to state\n * somewhere, in a block or in the schema.\n */\nconst AI_SEO_FIELD_RULES: Readonly<Partial<Record<SeoListingFieldKey, string>>> = {\n title:\n 'The title says what the page is, specifically and in plain words; add the site name only where it helps.',\n description:\n 'The description is one or two sentences: no quotation marks, no emoji, no capitals for emphasis.',\n breadcrumb: 'The breadcrumb label is one to three words.',\n}\n\n/** What a listing request carries, and therefore which rules it is sent. */\nexport interface AiSeoFieldsInstructionShape {\n fields: readonly SeoListingFieldKey[]\n keywords: boolean\n otherTitles: boolean\n}\n\n/**\n * The rules for one listing request.\n *\n * Byte-identical for every request of the same SHAPE, and identical across\n * workspaces at every shape: no site's name, text or listing is in here, so\n * two tenants writing the same kind of listing send the same rules. That is\n * the invariant `runtime/ai-prompt-cache.spec.ts` holds, and it is weaker\n * than \"one block for everything\" on purpose — a rule about target keywords\n * is worth nothing to a request that carries none, and `job.seo` runs on a\n * model that caches no prompt this short, so an unread rule is simply paid\n * for at full input rate on every attempt and every re-ask.\n */\nexport function aiSeoFieldsInstructions(\n shape: AiSeoFieldsInstructionShape,\n): AiSystemBlock[] {\n const fields = orderedSeoListingFields(shape.fields)\n const rules = [\n 'Write only from the text you are given. Never invent a fact, a price, a name, a place, an offer or a claim the text does not state.',\n ...fields.map((key) => AI_SEO_FIELD_RULES[key]).filter((rule): rule is string => Boolean(rule)),\n // Every field a person reads is held to this, keywords or none, so it is\n // stated on every shape rather than inside the keyword rule it used to\n // ride in: `checkAiSeoFields` refuses a repeat in a listing that named\n // no keywords too.\n 'Never repeat the same word three times in one field.',\n ...(shape.keywords\n ? [\n 'A target keyword goes in only where the page is about it and it reads naturally: at most once in the title and once in the description. Never list keywords, and leave out a keyword the page is not about.',\n ]\n : []),\n ...(shape.otherTitles\n ? ['Do not reuse a title another page of the site already uses.']\n : []),\n 'Write in the language of the page text.',\n ]\n return [\n {\n text:\n 'You write the search listing for one page or one product of a website: what a search result shows.\\n\\n' +\n `Answer by calling ${AI_SEO_FIELDS_TOOL_NAME} exactly once. A reply in prose cannot be used.\\n\\n` +\n `Rules:\\n${rules.map((rule) => `- ${rule}`).join('\\n')}`,\n cacheBreakpoint: true,\n },\n ]\n}\n\n/** The rules for a listing of the default shape, for a door that names no other. */\nexport const AI_SEO_FIELDS_INSTRUCTIONS: AiSystemBlock[] = aiSeoFieldsInstructions({\n fields: ['title', 'description', 'breadcrumb'],\n keywords: false,\n otherTitles: false,\n})\n\n/**\n * What the site itself is, in the words of whoever set it up (AGL-2918).\n *\n * A page's own text says what the page is; it does not say who the page is\n * written for. On a site whose pages have just been generated that gap is at\n * its widest — every page reads like the same competent stranger wrote it —\n * so the words the owner used are carried into the listing rather than\n * inferred back out of the copy they produced.\n *\n * It rides in the user turn and nowhere else: it is one site's own words, so\n * putting it in a rules block would key the platform's cache entry on a\n * tenant's sentence, and the rules already say to write from what is given.\n */\nexport interface AiSeoSiteWords {\n /** What kind of site it is: \"a neighborhood dog groomer\". */\n about?: string | null\n /** Who it is for: \"local dog owners who want a regular groom booked online\". */\n audience?: string | null\n}\n\nexport interface AiSeoFieldsPromptInput {\n subject: { kind: 'screen' | 'product'; name: string; path?: string | null }\n /** The site's name, as its visitors see it. */\n brand: string\n /** What the site is and who it is for, where the caller knows (AGL-2918). */\n site?: AiSeoSiteWords | null\n /** What the page or the product says: a page's Markdown, a product's description. */\n text: string\n fields: readonly SeoListingFieldKey[]\n current?: AiSeoFieldValues\n /**\n * What is known about the share image, when the listing has one: the\n * description it carries, and the page text around the same picture where\n * the page shows it.\n */\n image?: { alt?: string | null; context?: string | null } | null\n keywords?: readonly string[]\n otherTitles?: readonly string[]\n}\n\n/** The longest a site's own words run in a prompt; they are a phrase, not copy. */\nconst SITE_WORDS_MAX_CHARS = 160\n\n/** One of the site's own words as its line reads, or nothing when it says nothing. */\nfunction siteWordsLine(label: string, value: string | null | undefined): string {\n const text = (value ?? '').replace(/\\s+/g, ' ').trim().slice(0, SITE_WORDS_MAX_CHARS).trim()\n return text ? `${label}: ${text}` : ''\n}\n\n/** The user turn: the subject, what it says now, and the page's own text. */\nexport function aiSeoFieldsPrompt(input: AiSeoFieldsPromptInput): string {\n const fields = orderedSeoListingFields(input.fields)\n const lines = [\n `Site: ${input.brand || 'untitled site'}`,\n siteWordsLine('What the site is', input.site?.about),\n siteWordsLine('Who the site is for', input.site?.audience),\n input.subject.kind === 'product'\n ? `Product: ${input.subject.name || 'untitled product'}`\n : `Page: ${input.subject.name || 'untitled page'}${input.subject.path ? ` (${input.subject.path})` : ''}`,\n `Fields to write: ${fields.join(', ')}`,\n // Only the two site lines can be empty here, and an empty one is a\n // question nobody answered rather than a blank line to send.\n ].filter(Boolean)\n const current = fields\n .map((key) => [key, input.current?.[key]?.trim()] as const)\n .filter(([, value]) => Boolean(value))\n if (current.length) {\n lines.push('Current listing:', ...current.map(([key, value]) => `- ${key}: ${value}`))\n }\n if (input.image) {\n const known = [\n input.image.alt && `its current description: ${input.image.alt}`,\n input.image.context && `the page text beside it: ${input.image.context}`,\n ]\n .filter(Boolean)\n .join('; ')\n lines.push(`Share image: ${known || 'set, and nothing is known about what it shows'}`)\n }\n if (input.keywords?.length) lines.push(`Target keywords: ${input.keywords.join(', ')}`)\n if (input.otherTitles?.length) {\n lines.push(\n 'Titles other pages already use:',\n ...input.otherTitles.slice(0, OTHER_TITLES_LISTED).map((title) => `- ${title}`),\n )\n }\n lines.push(\n '',\n input.subject.kind === 'product' ? 'Product description:' : 'Page text:',\n input.text.trim() || '(no text)',\n )\n return lines.join('\\n')\n}\n\nexport interface GenerateSeoFieldsInput extends Omit<AiSeoFieldsPromptInput, 'fields'> {\n /** The fields to write; the title, description and breadcrumb label when omitted. */\n fields?: readonly SeoListingFieldKey[]\n /** The step kind the call is routed as; `job.seo` when omitted. */\n step?: AiStepKind\n settings?: AiPluginSettings\n model?: string\n /**\n * The answer's ceiling: `AI_SEO_FIELDS_MAX_TOKENS` when omitted. A job step\n * passes the most its registered time allows on the model it runs\n * (AGL-3035).\n */\n maxTokens?: number\n signal?: AbortSignal\n provider?: AiProvider\n}\n\n/** What a listing is written with when the caller names no fields. */\nexport const AI_SEO_DEFAULT_FIELDS: readonly SeoListingFieldKey[] = ['title', 'description', 'breadcrumb']\n\n/**\n * Propose a search listing for a page or a product.\n *\n * STABLE: a page generator calls this for the title and description of a\n * page it builds (`fields: ['title', 'description']`), and the `seo` job\n * calls it for a page's or a product's whole listing. It asks the routing\n * table's `job.seo` model through the doctrine's generation call and resolves\n * to its result — `ok` with the values, `needs_input` when the answer could\n * not be held to the editor after one re-ask, `refused` when the model\n * declined. It writes nothing.\n */\nexport async function generateSeoFields(\n input: GenerateSeoFieldsInput,\n): Promise<AiValidatedGeneration<AiSeoFieldValues>> {\n const hasImage = Boolean(input.image)\n const fields = orderedSeoListingFields(input.fields ?? AI_SEO_DEFAULT_FIELDS).filter(\n (key) => key !== 'imageAlt' || hasImage,\n )\n const keywords = input.keywords ?? []\n return runValidatedGeneration('seo-fields', {\n step: input.step ?? 'job.seo',\n ...(input.settings ? { settings: input.settings } : {}),\n ...(input.model ? { model: input.model } : {}),\n instructions: aiSeoFieldsInstructions({\n fields,\n keywords: keywords.length > 0,\n otherTitles: Boolean(input.otherTitles?.length),\n }),\n messages: [{ role: 'user', content: aiSeoFieldsPrompt({ ...input, fields, keywords }) }],\n tool: aiSeoFieldsTool(fields),\n maxTokens: input.maxTokens ?? AI_SEO_FIELDS_MAX_TOKENS,\n ...(input.signal ? { signal: input.signal } : {}),\n ...(input.provider ? { provider: input.provider } : {}),\n check: (answer) =>\n checkAiSeoFields(answer, {\n fields,\n hasImage,\n keywords,\n otherTitles: input.otherTitles,\n }),\n })\n}\n"],"names":["AI_ROUTING_TABLE","AI_SEO_FIELDS_TOOL_NAME","aiSeoFieldsTool","checkAiSeoFields","orderedSeoListingFields","runValidatedGeneration","AI_SEO_FIELDS_MAX_TOKENS","maxTokens","OTHER_TITLES_LISTED","AI_SEO_FIELD_RULES","title","description","breadcrumb","aiSeoFieldsInstructions","shape","fields","rules","map","key","filter","rule","Boolean","keywords","otherTitles","text","join","cacheBreakpoint","AI_SEO_FIELDS_INSTRUCTIONS","SITE_WORDS_MAX_CHARS","siteWordsLine","label","value","replace","trim","slice","aiSeoFieldsPrompt","input","lines","brand","site","about","audience","subject","kind","name","path","current","length","push","image","known","alt","context","AI_SEO_DEFAULT_FIELDS","generateSeoFields","hasImage","step","settings","model","instructions","messages","role","content","tool","signal","provider","check","answer"],"mappings":"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"}
@@ -0,0 +1,61 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2026 Aglyn LLC
4
+ *
5
+ * Licensed under the Apache License, Version 2.0 (the "License");
6
+ * you may not use this file except in compliance with the License.
7
+ * You may obtain a copy of the License at
8
+ *
9
+ * http://www.apache.org/licenses/LICENSE-2.0
10
+ *
11
+ * Unless required by applicable law or agreed to in writing, software
12
+ * distributed under the License is distributed on an "AS IS" BASIS,
13
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ * See the License for the specific language governing permissions and
15
+ * limitations under the License.
16
+ */
17
+ import { type PageMarkdownNodes } from '@aglyn/aglyn/app-utils/page-markdown';
18
+ /**
19
+ * What a page SAYS, read off its node tree (AGL-2910): the text a search
20
+ * listing is written from, the headings, and the images — each heading and
21
+ * image by node id, because a content fix addresses the element it changes.
22
+ *
23
+ * The text is the page's Markdown representation, the one an agent is
24
+ * served, so what the listing summarizes is what a reader of the page gets.
25
+ * The walk starts where that serializer starts — the content region — and
26
+ * skips what it skips, through the same chrome predicate: a heading in the
27
+ * site's navigation is not the page's heading.
28
+ */
29
+ /** How much of a page's text a prompt carries. A listing summarizes; it does not need the page. */
30
+ export declare const AI_SEO_PAGE_TEXT_MAX_CHARS = 2000;
31
+ export interface AiSeoHeading {
32
+ /** The element, or `null` for a heading inside rich text a fix cannot address. */
33
+ nodeId: string | null;
34
+ level: number;
35
+ text: string;
36
+ /** Whether a content fix can change it: a text component with plain text. */
37
+ editable: boolean;
38
+ }
39
+ export interface AiSeoImage {
40
+ nodeId: string;
41
+ src: string;
42
+ alt: string;
43
+ /** The nearest heading or text before it, which is what the image illustrates. */
44
+ context: string;
45
+ }
46
+ export interface AiSeoPageFacts {
47
+ /** The page's Markdown body, capped. */
48
+ text: string;
49
+ wordCount: number;
50
+ headings: AiSeoHeading[];
51
+ h1s: AiSeoHeading[];
52
+ images: AiSeoImage[];
53
+ imagesMissingAlt: AiSeoImage[];
54
+ /** The node the content region starts at; a new heading goes first inside it. */
55
+ contentRootId: string | null;
56
+ }
57
+ /** Read the facts a listing and an audit need from one page's node map. */
58
+ export declare function aiSeoPageFacts(nodes: PageMarkdownNodes | null | undefined, options?: {
59
+ rootId?: string;
60
+ maxChars?: number;
61
+ }): AiSeoPageFacts;
@@ -0,0 +1,150 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2026 Aglyn LLC
4
+ *
5
+ * Licensed under the Apache License, Version 2.0 (the "License");
6
+ * you may not use this file except in compliance with the License.
7
+ * You may obtain a copy of the License at
8
+ *
9
+ * http://www.apache.org/licenses/LICENSE-2.0
10
+ *
11
+ * Unless required by applicable law or agreed to in writing, software
12
+ * distributed under the License is distributed on an "AS IS" BASIS,
13
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ * See the License for the specific language governing permissions and
15
+ * limitations under the License.
16
+ */ import { buildPageMarkdown, headingLevelOf, isPageChromeNode, pageContentRootId } from "@aglyn/aglyn/app-utils/page-markdown";
17
+ /**
18
+ * What a page SAYS, read off its node tree (AGL-2910): the text a search
19
+ * listing is written from, the headings, and the images — each heading and
20
+ * image by node id, because a content fix addresses the element it changes.
21
+ *
22
+ * The text is the page's Markdown representation, the one an agent is
23
+ * served, so what the listing summarizes is what a reader of the page gets.
24
+ * The walk starts where that serializer starts — the content region — and
25
+ * skips what it skips, through the same chrome predicate: a heading in the
26
+ * site's navigation is not the page's heading.
27
+ */ /** How much of a page's text a prompt carries. A listing summarizes; it does not need the page. */ export const AI_SEO_PAGE_TEXT_MAX_CHARS = 2000;
28
+ /** How much text around an image describes it. */ const IMAGE_CONTEXT_MAX_CHARS = 160;
29
+ /** The deepest a walk goes, and it stops at a cycle — a node map is data. */ const MAX_DEPTH = 64;
30
+ /** The text components whose heading level `headingLevelOf` reads. */ const TEXT_COMPONENTS = new Set([
31
+ 'muiTypography',
32
+ 'muiInlineText',
33
+ 'muiListItemText'
34
+ ]);
35
+ const collapse = (value)=>value.replace(/\s+/g, ' ').trim();
36
+ /** Author HTML to its text, for a heading stored as rich text. */ function htmlText(html) {
37
+ return collapse(html.replace(/<[^>]*>/g, ' ').replace(/&nbsp;/g, ' ').replace(/&amp;/g, '&'));
38
+ }
39
+ /** A text component's own text, and whether it is plain (a fix can rewrite it). */ function textOf(props) {
40
+ const html = props['html'];
41
+ if (typeof html === 'string' && html.trim()) return {
42
+ text: htmlText(html),
43
+ plain: false
44
+ };
45
+ const children = props['children'];
46
+ return typeof children === 'string' ? {
47
+ text: collapse(children),
48
+ plain: true
49
+ } : {
50
+ text: '',
51
+ plain: true
52
+ };
53
+ }
54
+ const childIdsOf = (node)=>Array.isArray(node == null ? void 0 : node.nodes) ? (node == null ? void 0 : node.nodes).filter((id)=>typeof id === 'string') : [];
55
+ /** Read the facts a listing and an audit need from one page's node map. */ export function aiSeoPageFacts(nodes, options = {}) {
56
+ var _options_maxChars;
57
+ const empty = {
58
+ text: '',
59
+ wordCount: 0,
60
+ headings: [],
61
+ h1s: [],
62
+ images: [],
63
+ imagesMissingAlt: [],
64
+ contentRootId: null
65
+ };
66
+ if (!nodes) return empty;
67
+ const contentRootId = pageContentRootId(nodes, options.rootId);
68
+ if (!contentRootId) return empty;
69
+ const markdown = buildPageMarkdown({
70
+ nodes,
71
+ rootId: options.rootId
72
+ });
73
+ const text = markdown.trim().slice(0, (_options_maxChars = options.maxChars) != null ? _options_maxChars : AI_SEO_PAGE_TEXT_MAX_CHARS);
74
+ const headings = [];
75
+ const images = [];
76
+ let lastText = '';
77
+ const seen = new Set();
78
+ const visit = (id, depth)=>{
79
+ var _node_props, _node_componentId, _props_html;
80
+ if (depth > MAX_DEPTH || seen.has(id)) return;
81
+ const node = nodes[id];
82
+ if (!node) return;
83
+ seen.add(id);
84
+ if (isPageChromeNode(node)) return;
85
+ const props = (_node_props = node.props) != null ? _node_props : {};
86
+ const componentId = String((_node_componentId = node.componentId) != null ? _node_componentId : '');
87
+ if (TEXT_COMPONENTS.has(componentId)) {
88
+ const { text: own, plain } = textOf(props);
89
+ const level = headingLevelOf(props);
90
+ if (own) {
91
+ if (level > 0) headings.push({
92
+ nodeId: id,
93
+ level,
94
+ text: own,
95
+ editable: plain
96
+ });
97
+ lastText = own;
98
+ }
99
+ } else if (componentId === 'markdown' && typeof props['content'] === 'string') {
100
+ for (const line of String(props['content']).split('\n')){
101
+ const match = /^(#{1,6})\s+(.+)$/.exec(line.trim());
102
+ if (match) {
103
+ headings.push({
104
+ nodeId: null,
105
+ level: match[1].length,
106
+ text: collapse(match[2]),
107
+ editable: false
108
+ });
109
+ }
110
+ }
111
+ lastText = collapse(String(props['content'])).slice(0, IMAGE_CONTEXT_MAX_CHARS);
112
+ } else if (componentId === 'custom-html' && typeof ((_props_html = props['html']) != null ? _props_html : props['children']) === 'string') {
113
+ var _props_html1;
114
+ const html = String((_props_html1 = props['html']) != null ? _props_html1 : props['children']);
115
+ for (const match of html.matchAll(/<h([1-6])[^>]*>([\s\S]*?)<\/h\1>/gi)){
116
+ headings.push({
117
+ nodeId: null,
118
+ level: Number(match[1]),
119
+ text: htmlText(match[2]),
120
+ editable: false
121
+ });
122
+ }
123
+ } else if (componentId === 'image') {
124
+ var _props_src;
125
+ const src = String((_props_src = props['src']) != null ? _props_src : '').trim();
126
+ if (src) {
127
+ var _props_alt;
128
+ images.push({
129
+ nodeId: id,
130
+ src,
131
+ alt: collapse(String((_props_alt = props['alt']) != null ? _props_alt : '')),
132
+ context: lastText.slice(0, IMAGE_CONTEXT_MAX_CHARS)
133
+ });
134
+ }
135
+ }
136
+ for (const childId of childIdsOf(node))visit(childId, depth + 1);
137
+ };
138
+ visit(contentRootId, 0);
139
+ return {
140
+ text,
141
+ wordCount: text ? text.split(/\s+/).filter(Boolean).length : 0,
142
+ headings,
143
+ h1s: headings.filter((heading)=>heading.level === 1),
144
+ images,
145
+ imagesMissingAlt: images.filter((image)=>!image.alt),
146
+ contentRootId
147
+ };
148
+ }
149
+
150
+ //# sourceMappingURL=seo-page-facts.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../../../../libs/plugins/ai/src/lib/runtime/seo-page-facts.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 buildPageMarkdown,\n headingLevelOf,\n isPageChromeNode,\n pageContentRootId,\n type PageMarkdownNode,\n type PageMarkdownNodes,\n} from '@aglyn/aglyn/app-utils/page-markdown'\n\n/**\n * What a page SAYS, read off its node tree (AGL-2910): the text a search\n * listing is written from, the headings, and the images — each heading and\n * image by node id, because a content fix addresses the element it changes.\n *\n * The text is the page's Markdown representation, the one an agent is\n * served, so what the listing summarizes is what a reader of the page gets.\n * The walk starts where that serializer starts — the content region — and\n * skips what it skips, through the same chrome predicate: a heading in the\n * site's navigation is not the page's heading.\n */\n\n/** How much of a page's text a prompt carries. A listing summarizes; it does not need the page. */\nexport const AI_SEO_PAGE_TEXT_MAX_CHARS = 2_000\n\n/** How much text around an image describes it. */\nconst IMAGE_CONTEXT_MAX_CHARS = 160\n\n/** The deepest a walk goes, and it stops at a cycle — a node map is data. */\nconst MAX_DEPTH = 64\n\n/** The text components whose heading level `headingLevelOf` reads. */\nconst TEXT_COMPONENTS: ReadonlySet<string> = new Set(['muiTypography', 'muiInlineText', 'muiListItemText'])\n\nexport interface AiSeoHeading {\n /** The element, or `null` for a heading inside rich text a fix cannot address. */\n nodeId: string | null\n level: number\n text: string\n /** Whether a content fix can change it: a text component with plain text. */\n editable: boolean\n}\n\nexport interface AiSeoImage {\n nodeId: string\n src: string\n alt: string\n /** The nearest heading or text before it, which is what the image illustrates. */\n context: string\n}\n\nexport interface AiSeoPageFacts {\n /** The page's Markdown body, capped. */\n text: string\n wordCount: number\n headings: AiSeoHeading[]\n h1s: AiSeoHeading[]\n images: AiSeoImage[]\n imagesMissingAlt: AiSeoImage[]\n /** The node the content region starts at; a new heading goes first inside it. */\n contentRootId: string | null\n}\n\nconst collapse = (value: string): string => value.replace(/\\s+/g, ' ').trim()\n\n/** Author HTML to its text, for a heading stored as rich text. */\nfunction htmlText(html: string): string {\n return collapse(html.replace(/<[^>]*>/g, ' ').replace(/&nbsp;/g, ' ').replace(/&amp;/g, '&'))\n}\n\n/** A text component's own text, and whether it is plain (a fix can rewrite it). */\nfunction textOf(props: Record<string, unknown>): { text: string; plain: boolean } {\n const html = props['html']\n if (typeof html === 'string' && html.trim()) return { text: htmlText(html), plain: false }\n const children = props['children']\n return typeof children === 'string' ? { text: collapse(children), plain: true } : { text: '', plain: true }\n}\n\nconst childIdsOf = (node: PageMarkdownNode | undefined): string[] =>\n Array.isArray(node?.nodes) ? (node?.nodes as unknown[]).filter((id): id is string => typeof id === 'string') : []\n\n/** Read the facts a listing and an audit need from one page's node map. */\nexport function aiSeoPageFacts(\n nodes: PageMarkdownNodes | null | undefined,\n options: { rootId?: string; maxChars?: number } = {},\n): AiSeoPageFacts {\n const empty: AiSeoPageFacts = {\n text: '',\n wordCount: 0,\n headings: [],\n h1s: [],\n images: [],\n imagesMissingAlt: [],\n contentRootId: null,\n }\n if (!nodes) return empty\n const contentRootId = pageContentRootId(nodes, options.rootId)\n if (!contentRootId) return empty\n\n const markdown = buildPageMarkdown({ nodes, rootId: options.rootId })\n const text = markdown.trim().slice(0, options.maxChars ?? AI_SEO_PAGE_TEXT_MAX_CHARS)\n const headings: AiSeoHeading[] = []\n const images: AiSeoImage[] = []\n let lastText = ''\n\n const seen = new Set<string>()\n const visit = (id: string, depth: number): void => {\n if (depth > MAX_DEPTH || seen.has(id)) return\n const node = nodes[id]\n if (!node) return\n seen.add(id)\n if (isPageChromeNode(node)) return\n const props = (node.props ?? {}) as Record<string, unknown>\n const componentId = String(node.componentId ?? '')\n if (TEXT_COMPONENTS.has(componentId)) {\n const { text: own, plain } = textOf(props)\n const level = headingLevelOf(props)\n if (own) {\n if (level > 0) headings.push({ nodeId: id, level, text: own, editable: plain })\n lastText = own\n }\n } else if (componentId === 'markdown' && typeof props['content'] === 'string') {\n for (const line of String(props['content']).split('\\n')) {\n const match = /^(#{1,6})\\s+(.+)$/.exec(line.trim())\n if (match) {\n headings.push({ nodeId: null, level: match[1].length, text: collapse(match[2]), editable: false })\n }\n }\n lastText = collapse(String(props['content'])).slice(0, IMAGE_CONTEXT_MAX_CHARS)\n } else if (componentId === 'custom-html' && typeof (props['html'] ?? props['children']) === 'string') {\n const html = String(props['html'] ?? props['children'])\n for (const match of html.matchAll(/<h([1-6])[^>]*>([\\s\\S]*?)<\\/h\\1>/gi)) {\n headings.push({ nodeId: null, level: Number(match[1]), text: htmlText(match[2]), editable: false })\n }\n } else if (componentId === 'image') {\n const src = String(props['src'] ?? '').trim()\n if (src) {\n images.push({\n nodeId: id,\n src,\n alt: collapse(String(props['alt'] ?? '')),\n context: lastText.slice(0, IMAGE_CONTEXT_MAX_CHARS),\n })\n }\n }\n for (const childId of childIdsOf(node)) visit(childId, depth + 1)\n }\n visit(contentRootId, 0)\n\n return {\n text,\n wordCount: text ? text.split(/\\s+/).filter(Boolean).length : 0,\n headings,\n h1s: headings.filter((heading) => heading.level === 1),\n images,\n imagesMissingAlt: images.filter((image) => !image.alt),\n contentRootId,\n }\n}\n"],"names":["buildPageMarkdown","headingLevelOf","isPageChromeNode","pageContentRootId","AI_SEO_PAGE_TEXT_MAX_CHARS","IMAGE_CONTEXT_MAX_CHARS","MAX_DEPTH","TEXT_COMPONENTS","Set","collapse","value","replace","trim","htmlText","html","textOf","props","text","plain","children","childIdsOf","node","Array","isArray","nodes","filter","id","aiSeoPageFacts","options","empty","wordCount","headings","h1s","images","imagesMissingAlt","contentRootId","rootId","markdown","slice","maxChars","lastText","seen","visit","depth","has","add","componentId","String","own","level","push","nodeId","editable","line","split","match","exec","length","matchAll","Number","src","alt","context","childId","Boolean","heading","image"],"mappings":"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"}