@aglyn/plugins-ai 1.0.0-beta.229 → 1.0.0-beta.231

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 (340) hide show
  1. package/README.md +3 -3
  2. package/package.json +17 -17
  3. package/src/lib/activity/ai-activity-actions.js +7 -1
  4. package/src/lib/activity/ai-activity-actions.js.map +1 -1
  5. package/src/lib/components/ai-assist-provider-on-host.component.d.ts +66 -0
  6. package/src/lib/components/ai-assist-provider-on-host.component.js +78 -0
  7. package/src/lib/components/ai-assist-provider-on-host.component.js.map +1 -0
  8. package/src/lib/components/ai-assist-provider.component.js +9 -10
  9. package/src/lib/components/ai-assist-provider.component.js.map +1 -1
  10. package/src/lib/components/ai-automation-zones.d.ts +38 -0
  11. package/src/lib/components/ai-automation-zones.js +5 -1
  12. package/src/lib/components/ai-automation-zones.js.map +1 -1
  13. package/src/lib/components/ai-brief-dialog.component.d.ts +20 -2
  14. package/src/lib/components/ai-brief-dialog.component.js +87 -8
  15. package/src/lib/components/ai-brief-dialog.component.js.map +1 -1
  16. package/src/lib/components/ai-campaign-create.component.d.ts +54 -0
  17. package/src/lib/components/ai-campaign-create.component.js +270 -0
  18. package/src/lib/components/ai-campaign-create.component.js.map +1 -0
  19. package/src/lib/components/ai-describe-automation.component.d.ts +8 -3
  20. package/src/lib/components/ai-describe-automation.component.js +15 -6
  21. package/src/lib/components/ai-describe-automation.component.js.map +1 -1
  22. package/src/lib/components/ai-describe-button.component.d.ts +20 -8
  23. package/src/lib/components/ai-describe-button.component.js +19 -36
  24. package/src/lib/components/ai-describe-button.component.js.map +1 -1
  25. package/src/lib/components/ai-describe-email.component.d.ts +31 -0
  26. package/src/lib/components/ai-describe-email.component.js +22 -0
  27. package/src/lib/components/ai-describe-email.component.js.map +1 -0
  28. package/src/lib/components/ai-describe-org-automation.component.d.ts +36 -0
  29. package/src/lib/components/ai-describe-org-automation.component.js +238 -0
  30. package/src/lib/components/ai-describe-org-automation.component.js.map +1 -0
  31. package/src/lib/components/ai-experiment-cards.component.d.ts +9 -1
  32. package/src/lib/components/ai-experiment-cards.component.js +104 -18
  33. package/src/lib/components/ai-experiment-cards.component.js.map +1 -1
  34. package/src/lib/components/ai-explain-automation.component.js +1 -5
  35. package/src/lib/components/ai-explain-automation.component.js.map +1 -1
  36. package/src/lib/components/ai-funnel-zones.component.d.ts +61 -0
  37. package/src/lib/components/ai-funnel-zones.component.js +178 -0
  38. package/src/lib/components/ai-funnel-zones.component.js.map +1 -0
  39. package/src/lib/components/ai-insight-card.component.d.ts +42 -0
  40. package/src/lib/components/ai-insight-card.component.js +137 -0
  41. package/src/lib/components/ai-insight-card.component.js.map +1 -0
  42. package/src/lib/components/ai-insight-dialog.component.d.ts +6 -0
  43. package/src/lib/components/ai-insight-dialog.component.js +9 -3
  44. package/src/lib/components/ai-insight-dialog.component.js.map +1 -1
  45. package/src/lib/components/ai-job-plan.component.d.ts +7 -2
  46. package/src/lib/components/ai-job-plan.component.js +38 -6
  47. package/src/lib/components/ai-job-plan.component.js.map +1 -1
  48. package/src/lib/components/ai-job-requests.d.ts +17 -1
  49. package/src/lib/components/ai-job-requests.js +39 -3
  50. package/src/lib/components/ai-job-requests.js.map +1 -1
  51. package/src/lib/components/ai-logic-zones.d.ts +64 -0
  52. package/src/lib/components/ai-logic-zones.js +18 -0
  53. package/src/lib/components/ai-logic-zones.js.map +1 -0
  54. package/src/lib/components/ai-logic.component.d.ts +77 -0
  55. package/src/lib/components/ai-logic.component.js +553 -0
  56. package/src/lib/components/ai-logic.component.js.map +1 -0
  57. package/src/lib/components/ai-marketing-insight.component.d.ts +30 -0
  58. package/src/lib/components/ai-marketing-insight.component.js +80 -0
  59. package/src/lib/components/ai-marketing-insight.component.js.map +1 -0
  60. package/src/lib/components/ai-media-create.component.d.ts +55 -0
  61. package/src/lib/components/ai-media-create.component.js +433 -0
  62. package/src/lib/components/ai-media-create.component.js.map +1 -0
  63. package/src/lib/components/ai-overlay-cards.component.d.ts +83 -0
  64. package/src/lib/components/ai-overlay-cards.component.js +505 -0
  65. package/src/lib/components/ai-overlay-cards.component.js.map +1 -0
  66. package/src/lib/components/ai-permissions-on-host.component.d.ts +3 -46
  67. package/src/lib/components/ai-permissions-on-host.component.js +5 -53
  68. package/src/lib/components/ai-permissions-on-host.component.js.map +1 -1
  69. package/src/lib/components/ai-product-zones.d.ts +5 -0
  70. package/src/lib/components/ai-product-zones.js +1 -1
  71. package/src/lib/components/ai-product-zones.js.map +1 -1
  72. package/src/lib/components/ai-products-create-button.component.d.ts +42 -0
  73. package/src/lib/components/ai-products-create-button.component.js +67 -0
  74. package/src/lib/components/ai-products-create-button.component.js.map +1 -0
  75. package/src/lib/components/ai-products-hub-card.component.js +100 -81
  76. package/src/lib/components/ai-products-hub-card.component.js.map +1 -1
  77. package/src/lib/components/ai-revise-automation.component.d.ts +16 -0
  78. package/src/lib/components/ai-revise-automation.component.js +207 -0
  79. package/src/lib/components/ai-revise-automation.component.js.map +1 -0
  80. package/src/lib/components/ai-site-build-page.component.js +160 -24
  81. package/src/lib/components/ai-site-build-page.component.js.map +1 -1
  82. package/src/lib/components/ai-upsell-dialog.component.d.ts +53 -0
  83. package/src/lib/components/ai-upsell-dialog.component.js +177 -0
  84. package/src/lib/components/ai-upsell-dialog.component.js.map +1 -0
  85. package/src/lib/components/assist-build-card.component.d.ts +42 -0
  86. package/src/lib/components/assist-build-card.component.js +183 -0
  87. package/src/lib/components/assist-build-card.component.js.map +1 -0
  88. package/src/lib/components/assist-edit-canvas.d.ts +2 -0
  89. package/src/lib/components/assist-edit-canvas.js +56 -1
  90. package/src/lib/components/assist-edit-canvas.js.map +1 -1
  91. package/src/lib/components/assist-jobs-drawer.component.js +48 -3
  92. package/src/lib/components/assist-jobs-drawer.component.js.map +1 -1
  93. package/src/lib/components/assist-panel.component.js +51 -2
  94. package/src/lib/components/assist-panel.component.js.map +1 -1
  95. package/src/lib/components/use-ai-job-run.d.ts +3 -14
  96. package/src/lib/components/use-ai-job-run.js +0 -50
  97. package/src/lib/components/use-ai-job-run.js.map +1 -1
  98. package/src/lib/jobs/ai-build-capabilities.d.ts +58 -0
  99. package/src/lib/jobs/ai-build-capabilities.js +256 -0
  100. package/src/lib/jobs/ai-build-capabilities.js.map +1 -0
  101. package/src/lib/jobs/ai-build-unit-outcome.d.ts +52 -0
  102. package/src/lib/jobs/ai-build-unit-outcome.js +140 -0
  103. package/src/lib/jobs/ai-build-unit-outcome.js.map +1 -0
  104. package/src/lib/jobs/ai-job-auto-confirm.d.ts +8 -0
  105. package/src/lib/jobs/ai-job-auto-confirm.js +30 -6
  106. package/src/lib/jobs/ai-job-auto-confirm.js.map +1 -1
  107. package/src/lib/jobs/ai-job-build-step.d.ts +144 -0
  108. package/src/lib/jobs/ai-job-build-step.js +668 -0
  109. package/src/lib/jobs/ai-job-build-step.js.map +1 -0
  110. package/src/lib/jobs/ai-job-draft-ids.js +9 -1
  111. package/src/lib/jobs/ai-job-draft-ids.js.map +1 -1
  112. package/src/lib/jobs/ai-job-drafts.d.ts +14 -4
  113. package/src/lib/jobs/ai-job-drafts.js +25 -4
  114. package/src/lib/jobs/ai-job-drafts.js.map +1 -1
  115. package/src/lib/jobs/ai-job-generation.d.ts +8 -0
  116. package/src/lib/jobs/ai-job-generation.js +13 -2
  117. package/src/lib/jobs/ai-job-generation.js.map +1 -1
  118. package/src/lib/jobs/ai-job-insight-step.js +8 -1
  119. package/src/lib/jobs/ai-job-insight-step.js.map +1 -1
  120. package/src/lib/jobs/ai-job-layout-language.d.ts +73 -0
  121. package/src/lib/jobs/ai-job-layout-language.js +194 -0
  122. package/src/lib/jobs/ai-job-layout-language.js.map +1 -0
  123. package/src/lib/jobs/ai-job-layout-site-pages.d.ts +13 -2
  124. package/src/lib/jobs/ai-job-layout-site-pages.js +18 -2
  125. package/src/lib/jobs/ai-job-layout-site-pages.js.map +1 -1
  126. package/src/lib/jobs/ai-job-layout-step.d.ts +5 -0
  127. package/src/lib/jobs/ai-job-layout-step.js +105 -5
  128. package/src/lib/jobs/ai-job-layout-step.js.map +1 -1
  129. package/src/lib/jobs/ai-job-logic-step.d.ts +107 -0
  130. package/src/lib/jobs/ai-job-logic-step.js +395 -0
  131. package/src/lib/jobs/ai-job-logic-step.js.map +1 -0
  132. package/src/lib/jobs/ai-job-overlay-copy.d.ts +70 -0
  133. package/src/lib/jobs/ai-job-overlay-copy.js +178 -0
  134. package/src/lib/jobs/ai-job-overlay-copy.js.map +1 -0
  135. package/src/lib/jobs/ai-job-page-language.d.ts +149 -0
  136. package/src/lib/jobs/ai-job-page-language.js +355 -0
  137. package/src/lib/jobs/ai-job-page-language.js.map +1 -0
  138. package/src/lib/jobs/ai-job-page-sections.d.ts +37 -1
  139. package/src/lib/jobs/ai-job-page-sections.js +93 -11
  140. package/src/lib/jobs/ai-job-page-sections.js.map +1 -1
  141. package/src/lib/jobs/ai-job-page-step.d.ts +4 -4
  142. package/src/lib/jobs/ai-job-page-step.js +111 -20
  143. package/src/lib/jobs/ai-job-page-step.js.map +1 -1
  144. package/src/lib/jobs/ai-job-plan-step.d.ts +27 -2
  145. package/src/lib/jobs/ai-job-plan-step.js +87 -13
  146. package/src/lib/jobs/ai-job-plan-step.js.map +1 -1
  147. package/src/lib/jobs/ai-job-site-step.d.ts +19 -1
  148. package/src/lib/jobs/ai-job-site-step.js +220 -61
  149. package/src/lib/jobs/ai-job-site-step.js.map +1 -1
  150. package/src/lib/jobs/ai-job-text-step.d.ts +22 -1
  151. package/src/lib/jobs/ai-job-text-step.js +12 -0
  152. package/src/lib/jobs/ai-job-text-step.js.map +1 -1
  153. package/src/lib/jobs/ai-job-workflow-step.d.ts +54 -4
  154. package/src/lib/jobs/ai-job-workflow-step.js +320 -15
  155. package/src/lib/jobs/ai-job-workflow-step.js.map +1 -1
  156. package/src/lib/jobs/ai-jobs.d.ts +80 -2
  157. package/src/lib/jobs/ai-jobs.js +391 -18
  158. package/src/lib/jobs/ai-jobs.js.map +1 -1
  159. package/src/lib/jobs/ai-layout-full-height.d.ts +40 -0
  160. package/src/lib/jobs/ai-layout-full-height.js +82 -0
  161. package/src/lib/jobs/ai-layout-full-height.js.map +1 -0
  162. package/src/lib/jobs/ai-layout-site-facts.d.ts +54 -0
  163. package/src/lib/jobs/ai-layout-site-facts.js +153 -0
  164. package/src/lib/jobs/ai-layout-site-facts.js.map +1 -0
  165. package/src/lib/jobs/ai-logic-records.d.ts +40 -0
  166. package/src/lib/jobs/ai-logic-records.js +55 -0
  167. package/src/lib/jobs/ai-logic-records.js.map +1 -0
  168. package/src/lib/jobs/ai-site-publish.d.ts +7 -0
  169. package/src/lib/jobs/ai-site-publish.js +9 -0
  170. package/src/lib/jobs/ai-site-publish.js.map +1 -1
  171. package/src/lib/jobs/ai-workflow-records.d.ts +4 -0
  172. package/src/lib/jobs/ai-workflow-records.js +40 -1
  173. package/src/lib/jobs/ai-workflow-records.js.map +1 -1
  174. package/src/lib/layout-language/ai-layout-compiler.d.ts +145 -0
  175. package/src/lib/layout-language/ai-layout-compiler.js +1148 -0
  176. package/src/lib/layout-language/ai-layout-compiler.js.map +1 -0
  177. package/src/lib/layout-language/ai-layout-copy.d.ts +73 -0
  178. package/src/lib/layout-language/ai-layout-copy.js +137 -0
  179. package/src/lib/layout-language/ai-layout-copy.js.map +1 -0
  180. package/src/lib/layout-language/ai-layout-frame.d.ts +52 -0
  181. package/src/lib/layout-language/ai-layout-frame.js +457 -0
  182. package/src/lib/layout-language/ai-layout-frame.js.map +1 -0
  183. package/src/lib/layout-language/ai-layout-gaps.d.ts +63 -0
  184. package/src/lib/layout-language/ai-layout-gaps.js +345 -0
  185. package/src/lib/layout-language/ai-layout-gaps.js.map +1 -0
  186. package/src/lib/layout-language/ai-layout-language.d.ts +161 -0
  187. package/src/lib/layout-language/ai-layout-language.js +446 -0
  188. package/src/lib/layout-language/ai-layout-language.js.map +1 -0
  189. package/src/lib/layout-language/ai-layout-links.d.ts +80 -0
  190. package/src/lib/layout-language/ai-layout-links.js +109 -0
  191. package/src/lib/layout-language/ai-layout-links.js.map +1 -0
  192. package/src/lib/layout-language/ai-layout-store.d.ts +39 -0
  193. package/src/lib/layout-language/ai-layout-store.js +69 -0
  194. package/src/lib/layout-language/ai-layout-store.js.map +1 -0
  195. package/src/lib/layout-language/ai-layout-tree.d.ts +59 -0
  196. package/src/lib/layout-language/ai-layout-tree.js +84 -0
  197. package/src/lib/layout-language/ai-layout-tree.js.map +1 -0
  198. package/src/lib/lazy-widget.d.ts +45 -0
  199. package/src/lib/lazy-widget.js +53 -0
  200. package/src/lib/lazy-widget.js.map +1 -0
  201. package/src/lib/model/ai-automation-draft.d.ts +18 -0
  202. package/src/lib/model/ai-automation-draft.js +86 -0
  203. package/src/lib/model/ai-automation-draft.js.map +1 -1
  204. package/src/lib/model/ai-build-job.d.ts +201 -0
  205. package/src/lib/model/ai-build-job.js +472 -0
  206. package/src/lib/model/ai-build-job.js.map +1 -0
  207. package/src/lib/model/ai-build-plan.d.ts +61 -0
  208. package/src/lib/model/ai-build-plan.js +154 -9
  209. package/src/lib/model/ai-build-plan.js.map +1 -1
  210. package/src/lib/model/ai-build-progress.d.ts +73 -0
  211. package/src/lib/model/ai-build-progress.js +170 -0
  212. package/src/lib/model/ai-build-progress.js.map +1 -0
  213. package/src/lib/model/ai-host-publish-context.d.ts +51 -0
  214. package/src/lib/model/ai-host-publish-context.js +104 -0
  215. package/src/lib/model/ai-host-publish-context.js.map +1 -0
  216. package/src/lib/model/ai-insight.d.ts +20 -10
  217. package/src/lib/model/ai-insight.js +72 -9
  218. package/src/lib/model/ai-insight.js.map +1 -1
  219. package/src/lib/model/ai-job-activity.d.ts +22 -0
  220. package/src/lib/model/ai-job-activity.js +25 -2
  221. package/src/lib/model/ai-job-activity.js.map +1 -1
  222. package/src/lib/model/ai-job-failure-copy.d.ts +38 -1
  223. package/src/lib/model/ai-job-failure-copy.js +56 -1
  224. package/src/lib/model/ai-job-failure-copy.js.map +1 -1
  225. package/src/lib/model/ai-job-notice.d.ts +3 -1
  226. package/src/lib/model/ai-job-notice.js +31 -9
  227. package/src/lib/model/ai-job-notice.js.map +1 -1
  228. package/src/lib/model/ai-jobs.types.d.ts +99 -2
  229. package/src/lib/model/ai-jobs.types.js +3 -1
  230. package/src/lib/model/ai-jobs.types.js.map +1 -1
  231. package/src/lib/model/ai-logic-job.d.ts +108 -0
  232. package/src/lib/model/ai-logic-job.js +327 -0
  233. package/src/lib/model/ai-logic-job.js.map +1 -0
  234. package/src/lib/model/ai-media-credits.d.ts +52 -0
  235. package/src/lib/model/ai-media-credits.js +61 -0
  236. package/src/lib/model/ai-media-credits.js.map +1 -0
  237. package/src/lib/model/ai-overlay-copy.d.ts +114 -0
  238. package/src/lib/model/ai-overlay-copy.js +175 -0
  239. package/src/lib/model/ai-overlay-copy.js.map +1 -0
  240. package/src/lib/model/ai-site-build-progress.d.ts +25 -4
  241. package/src/lib/model/ai-site-build-progress.js +194 -11
  242. package/src/lib/model/ai-site-build-progress.js.map +1 -1
  243. package/src/lib/model/ai-site-job.d.ts +8 -0
  244. package/src/lib/model/ai-site-job.js +9 -0
  245. package/src/lib/model/ai-site-job.js.map +1 -1
  246. package/src/lib/model/ai-site-start-seo.d.ts +1 -1
  247. package/src/lib/model/ai-site-start.d.ts +5 -2
  248. package/src/lib/model/ai-site-start.js +5 -2
  249. package/src/lib/model/ai-site-start.js.map +1 -1
  250. package/src/lib/model/ai-svg.d.ts +69 -0
  251. package/src/lib/model/ai-svg.js +265 -0
  252. package/src/lib/model/ai-svg.js.map +1 -0
  253. package/src/lib/model/ai-usage-by-user.d.ts +3 -2
  254. package/src/lib/model/ai-usage-by-user.js.map +1 -1
  255. package/src/lib/model/ai-workflow-job.d.ts +92 -4
  256. package/src/lib/model/ai-workflow-job.js +124 -7
  257. package/src/lib/model/ai-workflow-job.js.map +1 -1
  258. package/src/lib/model/assist-build.d.ts +58 -0
  259. package/src/lib/model/assist-build.js +52 -0
  260. package/src/lib/model/assist-build.js.map +1 -0
  261. package/src/lib/model/assist-edit.d.ts +48 -3
  262. package/src/lib/model/assist-edit.js +48 -4
  263. package/src/lib/model/assist-edit.js.map +1 -1
  264. package/src/lib/plugin-config.js +2 -0
  265. package/src/lib/plugin-config.js.map +1 -1
  266. package/src/lib/plugin.js +308 -47
  267. package/src/lib/plugin.js.map +1 -1
  268. package/src/lib/providers/catalog.d.ts +82 -5
  269. package/src/lib/providers/catalog.js +83 -12
  270. package/src/lib/providers/catalog.js.map +1 -1
  271. package/src/lib/providers/image-contract.d.ts +116 -0
  272. package/src/lib/providers/image-contract.js +74 -0
  273. package/src/lib/providers/image-contract.js.map +1 -0
  274. package/src/lib/providers/model-choice.js +11 -0
  275. package/src/lib/providers/model-choice.js.map +1 -1
  276. package/src/lib/providers/routing.js +18 -0
  277. package/src/lib/providers/routing.js.map +1 -1
  278. package/src/lib/providers/vertex-image.d.ts +121 -0
  279. package/src/lib/providers/vertex-image.js +312 -0
  280. package/src/lib/providers/vertex-image.js.map +1 -0
  281. package/src/lib/runtime/ai-doctrine-validators.d.ts +101 -0
  282. package/src/lib/runtime/ai-doctrine-validators.js +525 -4
  283. package/src/lib/runtime/ai-doctrine-validators.js.map +1 -1
  284. package/src/lib/runtime/ai-doctrine.js +21 -6
  285. package/src/lib/runtime/ai-doctrine.js.map +1 -1
  286. package/src/lib/runtime/ai-eval-live.js +4 -0
  287. package/src/lib/runtime/ai-eval-live.js.map +1 -1
  288. package/src/lib/runtime/ai-eval.d.ts +15 -1
  289. package/src/lib/runtime/ai-eval.js +52 -1
  290. package/src/lib/runtime/ai-eval.js.map +1 -1
  291. package/src/lib/runtime/ai-icon-library.d.ts +257 -0
  292. package/src/lib/runtime/ai-icon-library.js +254 -0
  293. package/src/lib/runtime/ai-icon-library.js.map +1 -0
  294. package/src/lib/runtime/ai-node-tree.d.ts +9 -0
  295. package/src/lib/runtime/ai-node-tree.js +30 -4
  296. package/src/lib/runtime/ai-node-tree.js.map +1 -1
  297. package/src/lib/runtime/ai-palette.d.ts +6 -0
  298. package/src/lib/runtime/ai-palette.generated.js +70 -0
  299. package/src/lib/runtime/ai-palette.generated.js.map +1 -1
  300. package/src/lib/runtime/ai-palette.js.map +1 -1
  301. package/src/lib/runtime/experiment-variant-copy.d.ts +34 -0
  302. package/src/lib/runtime/experiment-variant-copy.js +102 -0
  303. package/src/lib/runtime/experiment-variant-copy.js.map +1 -0
  304. package/src/lib/server/ai-experiment-versions.d.ts +51 -0
  305. package/src/lib/server/ai-experiment-versions.js +270 -0
  306. package/src/lib/server/ai-experiment-versions.js.map +1 -0
  307. package/src/lib/server/ai-jobs-resume.js +74 -4
  308. package/src/lib/server/ai-jobs-resume.js.map +1 -1
  309. package/src/lib/server/ai-media-image.d.ts +66 -0
  310. package/src/lib/server/ai-media-image.js +521 -0
  311. package/src/lib/server/ai-media-image.js.map +1 -0
  312. package/src/lib/server/ai-media-svg.d.ts +91 -0
  313. package/src/lib/server/ai-media-svg.js +186 -0
  314. package/src/lib/server/ai-media-svg.js.map +1 -0
  315. package/src/lib/server/assist-build.d.ts +54 -0
  316. package/src/lib/server/assist-build.js +121 -0
  317. package/src/lib/server/assist-build.js.map +1 -0
  318. package/src/lib/server/assist-chat.js +108 -12
  319. package/src/lib/server/assist-chat.js.map +1 -1
  320. package/src/lib/server/assist-edit.js +213 -3
  321. package/src/lib/server/assist-edit.js.map +1 -1
  322. package/src/lib/server/assist-view-context.js +242 -4
  323. package/src/lib/server/assist-view-context.js.map +1 -1
  324. package/src/lib/server.js +26 -0
  325. package/src/lib/server.js.map +1 -1
  326. package/src/lib/tools/ai-logic-tool.d.ts +27 -0
  327. package/src/lib/tools/ai-logic-tool.js +207 -0
  328. package/src/lib/tools/ai-logic-tool.js.map +1 -0
  329. package/src/lib/tools/ai-overlay-tool.d.ts +35 -0
  330. package/src/lib/tools/ai-overlay-tool.js +107 -0
  331. package/src/lib/tools/ai-overlay-tool.js.map +1 -0
  332. package/src/lib/tools/ai-workflow-tool.d.ts +17 -2
  333. package/src/lib/tools/ai-workflow-tool.js +47 -14
  334. package/src/lib/tools/ai-workflow-tool.js.map +1 -1
  335. package/src/lib/usage/assist-job-refund.d.ts +28 -1
  336. package/src/lib/usage/assist-job-refund.js +44 -9
  337. package/src/lib/usage/assist-job-refund.js.map +1 -1
  338. package/src/lib/usage/assist-usage.d.ts +5 -0
  339. package/src/lib/usage/assist-usage.js +2 -0
  340. package/src/lib/usage/assist-usage.js.map +1 -1
@@ -0,0 +1,40 @@
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
+ /**
18
+ * A layout at least as tall as the window (AGL-3596).
19
+ *
20
+ * A layout is header, page, footer, top to bottom, and on a page shorter than
21
+ * the window the footer used to end wherever the page did — on beta.230 a
22
+ * contact page left its footer floating halfway up the screen with blank page
23
+ * under it. So every layout the AI builds is written as one column at least
24
+ * the window's height, and the part of it that holds the Layout Slot takes
25
+ * the room left over: the footer sits at the bottom of a short page and
26
+ * follows the content of a long one.
27
+ *
28
+ * Written by the platform after the model answers and before the doctrine
29
+ * checks the tree, so the doctrine holds the column like anything else: it is
30
+ * a Stack with a style of its own, which no rule calls an empty wrapper.
31
+ */
32
+ /** The id of the column the platform adds, when no node of the tree has it. */
33
+ export declare const AI_LAYOUT_FRAME_ID = "aiLayoutFrame";
34
+ /**
35
+ * The layout with its root's children in a column at least the window's
36
+ * height, and the child that holds the Layout Slot growing into the room
37
+ * left. A tree whose top already sets a minimum height is left as it came,
38
+ * and so is anything that is not a node map or holds no Layout Slot.
39
+ */
40
+ export declare function aiLayoutWithFullHeight(tree: unknown): unknown;
@@ -0,0 +1,82 @@
1
+ import { _ as _extends } from "@swc/helpers/_/_extends";
2
+ /**
3
+ * @license
4
+ * Copyright 2026 Aglyn LLC
5
+ *
6
+ * Licensed under the Apache License, Version 2.0 (the "License");
7
+ * you may not use this file except in compliance with the License.
8
+ * You may obtain a copy of the License at
9
+ *
10
+ * http://www.apache.org/licenses/LICENSE-2.0
11
+ *
12
+ * Unless required by applicable law or agreed to in writing, software
13
+ * distributed under the License is distributed on an "AS IS" BASIS,
14
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ * See the License for the specific language governing permissions and
16
+ * limitations under the License.
17
+ */ /**
18
+ * A layout at least as tall as the window (AGL-3596).
19
+ *
20
+ * A layout is header, page, footer, top to bottom, and on a page shorter than
21
+ * the window the footer used to end wherever the page did — on beta.230 a
22
+ * contact page left its footer floating halfway up the screen with blank page
23
+ * under it. So every layout the AI builds is written as one column at least
24
+ * the window's height, and the part of it that holds the Layout Slot takes
25
+ * the room left over: the footer sits at the bottom of a short page and
26
+ * follows the content of a long one.
27
+ *
28
+ * Written by the platform after the model answers and before the doctrine
29
+ * checks the tree, so the doctrine holds the column like anything else: it is
30
+ * a Stack with a style of its own, which no rule calls an empty wrapper.
31
+ */ /** The id of the column the platform adds, when no node of the tree has it. */ export const AI_LAYOUT_FRAME_ID = 'aiLayoutFrame';
32
+ const isRecord = (value)=>Boolean(value) && typeof value === 'object' && !Array.isArray(value);
33
+ const childrenOf = (node)=>Array.isArray(node == null ? void 0 : node.nodes) ? node.nodes.filter((id)=>typeof id === 'string') : [];
34
+ /**
35
+ * The layout with its root's children in a column at least the window's
36
+ * height, and the child that holds the Layout Slot growing into the room
37
+ * left. A tree whose top already sets a minimum height is left as it came,
38
+ * and so is anything that is not a node map or holds no Layout Slot.
39
+ */ export function aiLayoutWithFullHeight(tree) {
40
+ var _source_grower_sx;
41
+ var _source_top__sx;
42
+ if (!isRecord(tree) || !isRecord(tree['nodes'])) return tree;
43
+ const source = tree['nodes'];
44
+ const rootId = typeof tree['rootId'] === 'string' ? tree['rootId'] : null;
45
+ if (!rootId || !isRecord(source[rootId])) return tree;
46
+ const top = childrenOf(source[rootId]).filter((id)=>isRecord(source[id]));
47
+ if (!top.length) return tree;
48
+ if (top.length === 1 && ((_source_top__sx = source[top[0]].sx) == null ? void 0 : _source_top__sx['minHeight']) !== undefined) return tree;
49
+ const holdsSlot = (id, seen = new Set())=>{
50
+ if (seen.has(id) || !isRecord(source[id])) return false;
51
+ seen.add(id);
52
+ return source[id].componentId === 'layoutSlot' || childrenOf(source[id]).some((child)=>holdsSlot(child, seen));
53
+ };
54
+ const grower = top.find((id)=>holdsSlot(id));
55
+ if (!grower) return tree;
56
+ let frameId = AI_LAYOUT_FRAME_ID;
57
+ for(let n = 2; frameId in source; n += 1)frameId = `${AI_LAYOUT_FRAME_ID}${n}`;
58
+ const nodes = _extends({}, source, {
59
+ [rootId]: _extends({}, source[rootId], {
60
+ nodes: [
61
+ frameId
62
+ ]
63
+ }),
64
+ [frameId]: {
65
+ componentId: 'muiStack',
66
+ sx: {
67
+ minHeight: '100vh'
68
+ },
69
+ nodes: top
70
+ },
71
+ [grower]: _extends({}, source[grower], {
72
+ sx: _extends({}, (_source_grower_sx = source[grower].sx) != null ? _source_grower_sx : {}, {
73
+ flexGrow: 1
74
+ })
75
+ })
76
+ });
77
+ return _extends({}, tree, {
78
+ nodes
79
+ });
80
+ }
81
+
82
+ //# sourceMappingURL=ai-layout-full-height.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../../../../libs/plugins/ai/src/lib/jobs/ai-layout-full-height.ts"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * A layout at least as tall as the window (AGL-3596).\n *\n * A layout is header, page, footer, top to bottom, and on a page shorter than\n * the window the footer used to end wherever the page did — on beta.230 a\n * contact page left its footer floating halfway up the screen with blank page\n * under it. So every layout the AI builds is written as one column at least\n * the window's height, and the part of it that holds the Layout Slot takes\n * the room left over: the footer sits at the bottom of a short page and\n * follows the content of a long one.\n *\n * Written by the platform after the model answers and before the doctrine\n * checks the tree, so the doctrine holds the column like anything else: it is\n * a Stack with a style of its own, which no rule calls an empty wrapper.\n */\n\n/** The id of the column the platform adds, when no node of the tree has it. */\nexport const AI_LAYOUT_FRAME_ID = 'aiLayoutFrame'\n\ntype RawNode = { componentId?: unknown; props?: Record<string, unknown>; sx?: Record<string, unknown>; nodes?: unknown }\n\nconst isRecord = (value: unknown): value is Record<string, unknown> =>\n Boolean(value) && typeof value === 'object' && !Array.isArray(value)\n\nconst childrenOf = (node: RawNode | undefined): string[] =>\n Array.isArray(node?.nodes) ? (node.nodes as unknown[]).filter((id): id is string => typeof id === 'string') : []\n\n/**\n * The layout with its root's children in a column at least the window's\n * height, and the child that holds the Layout Slot growing into the room\n * left. A tree whose top already sets a minimum height is left as it came,\n * and so is anything that is not a node map or holds no Layout Slot.\n */\nexport function aiLayoutWithFullHeight(tree: unknown): unknown {\n if (!isRecord(tree) || !isRecord(tree['nodes'])) return tree\n const source = tree['nodes'] as Record<string, RawNode>\n const rootId = typeof tree['rootId'] === 'string' ? tree['rootId'] : null\n if (!rootId || !isRecord(source[rootId])) return tree\n const top = childrenOf(source[rootId]).filter((id) => isRecord(source[id]))\n if (!top.length) return tree\n if (top.length === 1 && source[top[0]].sx?.['minHeight'] !== undefined) return tree\n\n const holdsSlot = (id: string, seen = new Set<string>()): boolean => {\n if (seen.has(id) || !isRecord(source[id])) return false\n seen.add(id)\n return source[id].componentId === 'layoutSlot' || childrenOf(source[id]).some((child) => holdsSlot(child, seen))\n }\n const grower = top.find((id) => holdsSlot(id))\n if (!grower) return tree\n\n let frameId = AI_LAYOUT_FRAME_ID\n for (let n = 2; frameId in source; n += 1) frameId = `${AI_LAYOUT_FRAME_ID}${n}`\n const nodes: Record<string, RawNode> = {\n ...source,\n [rootId]: { ...source[rootId], nodes: [frameId] },\n [frameId]: { componentId: 'muiStack', sx: { minHeight: '100vh' }, nodes: top },\n [grower]: { ...source[grower], sx: { ...(source[grower].sx ?? {}), flexGrow: 1 } },\n }\n return { ...tree, nodes }\n}\n"],"names":["AI_LAYOUT_FRAME_ID","isRecord","value","Boolean","Array","isArray","childrenOf","node","nodes","filter","id","aiLayoutWithFullHeight","tree","source","rootId","top","length","sx","undefined","holdsSlot","seen","Set","has","add","componentId","some","child","grower","find","frameId","n","minHeight","flexGrow"],"mappings":";AAAA;;;;;;;;;;;;;;;CAeC,GAED;;;;;;;;;;;;;;CAcC,GAED,6EAA6E,GAC7E,OAAO,MAAMA,qBAAqB,gBAAe;AAIjD,MAAMC,WAAW,CAACC,QAChBC,QAAQD,UAAU,OAAOA,UAAU,YAAY,CAACE,MAAMC,OAAO,CAACH;AAEhE,MAAMI,aAAa,CAACC,OAClBH,MAAMC,OAAO,CAACE,wBAAAA,KAAMC,KAAK,IAAI,AAACD,KAAKC,KAAK,CAAeC,MAAM,CAAC,CAACC,KAAqB,OAAOA,OAAO,YAAY,EAAE;AAElH;;;;;CAKC,GACD,OAAO,SAASC,uBAAuBC,IAAa;QAuBPC;QAhBnBA;IANxB,IAAI,CAACZ,SAASW,SAAS,CAACX,SAASW,IAAI,CAAC,QAAQ,GAAG,OAAOA;IACxD,MAAMC,SAASD,IAAI,CAAC,QAAQ;IAC5B,MAAME,SAAS,OAAOF,IAAI,CAAC,SAAS,KAAK,WAAWA,IAAI,CAAC,SAAS,GAAG;IACrE,IAAI,CAACE,UAAU,CAACb,SAASY,MAAM,CAACC,OAAO,GAAG,OAAOF;IACjD,MAAMG,MAAMT,WAAWO,MAAM,CAACC,OAAO,EAAEL,MAAM,CAAC,CAACC,KAAOT,SAASY,MAAM,CAACH,GAAG;IACzE,IAAI,CAACK,IAAIC,MAAM,EAAE,OAAOJ;IACxB,IAAIG,IAAIC,MAAM,KAAK,KAAKH,EAAAA,kBAAAA,MAAM,CAACE,GAAG,CAAC,EAAE,CAAC,CAACE,EAAE,qBAAjBJ,eAAmB,CAAC,YAAY,MAAKK,WAAW,OAAON;IAE/E,MAAMO,YAAY,CAACT,IAAYU,OAAO,IAAIC,KAAa;QACrD,IAAID,KAAKE,GAAG,CAACZ,OAAO,CAACT,SAASY,MAAM,CAACH,GAAG,GAAG,OAAO;QAClDU,KAAKG,GAAG,CAACb;QACT,OAAOG,MAAM,CAACH,GAAG,CAACc,WAAW,KAAK,gBAAgBlB,WAAWO,MAAM,CAACH,GAAG,EAAEe,IAAI,CAAC,CAACC,QAAUP,UAAUO,OAAON;IAC5G;IACA,MAAMO,SAASZ,IAAIa,IAAI,CAAC,CAAClB,KAAOS,UAAUT;IAC1C,IAAI,CAACiB,QAAQ,OAAOf;IAEpB,IAAIiB,UAAU7B;IACd,IAAK,IAAI8B,IAAI,GAAGD,WAAWhB,QAAQiB,KAAK,EAAGD,UAAU,GAAG7B,qBAAqB8B,GAAG;IAChF,MAAMtB,QAAiC,aAClCK;QACH,CAACC,OAAO,EAAE,aAAKD,MAAM,CAACC,OAAO;YAAEN,OAAO;gBAACqB;aAAQ;;QAC/C,CAACA,QAAQ,EAAE;YAAEL,aAAa;YAAYP,IAAI;gBAAEc,WAAW;YAAQ;YAAGvB,OAAOO;QAAI;QAC7E,CAACY,OAAO,EAAE,aAAKd,MAAM,CAACc,OAAO;YAAEV,IAAI,cAAMJ,oBAAAA,MAAM,CAACc,OAAO,CAACV,EAAE,YAAjBJ,oBAAqB,CAAC;gBAAImB,UAAU;;;;IAE/E,OAAO,aAAKpB;QAAMJ;;AACpB"}
@@ -0,0 +1,54 @@
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 { AiDoctrineTree, AiDoctrineViolation } from '../runtime/ai-doctrine-validators';
18
+ /**
19
+ * What a layout may say about the business it frames (AGL-3596).
20
+ *
21
+ * A layout's header and footer are on every page, so a fact in them is
22
+ * published everywhere at once. Two went wrong on beta.230: the model coined
23
+ * a name for the business ("Austin Paws Grooming" for a site called Hillside
24
+ * Dog Grooming), and a footer is exactly where a model reaches for a phone
25
+ * number, an email or opening hours the brief never gave.
26
+ *
27
+ * - The site's name is the brand, and it is written as the host token that
28
+ * reads it (`{{host.businessName}}`), so a rename in Setup follows on every
29
+ * page rather than leaving the name it was built under
30
+ * (`aiLayoutWithSiteName`).
31
+ * - A contact detail the brief does not give is refused by the layout's own
32
+ * check (`aiLayoutInventedContactViolations`), so the model is asked again
33
+ * to leave it out: an email, a phone number, a street address or opening
34
+ * hours appear in the layout only when the brief has them.
35
+ */
36
+ /** The host token that reads a site's own name at render. */
37
+ export declare const AI_SITE_NAME_TOKEN = "{{host.businessName}}";
38
+ /**
39
+ * The tree with every written occurrence of the site's name — the brand, the
40
+ * copyright line — replaced by the host token that reads it. Matched whole,
41
+ * ignoring case and runs of spaces. Anything that is not a node map, and a
42
+ * name too short to match safely, leaves the tree as it came.
43
+ */
44
+ export declare function aiLayoutWithSiteName(tree: unknown, siteName: string | null | undefined): unknown;
45
+ /**
46
+ * Rule 14 for a layout: every email address, phone number, street address
47
+ * and opening time its words carry is one the brief gives. A number is read
48
+ * by its digits, so a brief's "512.555.0142" admits "(512) 555-0142"; a year
49
+ * or a price is not a phone number, so only a run of seven digits or more is
50
+ * read as one. An address is matched by its house number and first street
51
+ * word; hours are admitted when the brief gives any, since a brief that names
52
+ * its hours is spelled a dozen ways a footer may fairly reword.
53
+ */
54
+ export declare function aiLayoutInventedContactViolations(tree: AiDoctrineTree, brief: string): AiDoctrineViolation[];
@@ -0,0 +1,153 @@
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 { walkTree } from "../runtime/ai-doctrine-validators.js";
18
+ /**
19
+ * What a layout may say about the business it frames (AGL-3596).
20
+ *
21
+ * A layout's header and footer are on every page, so a fact in them is
22
+ * published everywhere at once. Two went wrong on beta.230: the model coined
23
+ * a name for the business ("Austin Paws Grooming" for a site called Hillside
24
+ * Dog Grooming), and a footer is exactly where a model reaches for a phone
25
+ * number, an email or opening hours the brief never gave.
26
+ *
27
+ * - The site's name is the brand, and it is written as the host token that
28
+ * reads it (`{{host.businessName}}`), so a rename in Setup follows on every
29
+ * page rather than leaving the name it was built under
30
+ * (`aiLayoutWithSiteName`).
31
+ * - A contact detail the brief does not give is refused by the layout's own
32
+ * check (`aiLayoutInventedContactViolations`), so the model is asked again
33
+ * to leave it out: an email, a phone number, a street address or opening
34
+ * hours appear in the layout only when the brief has them.
35
+ */ /** The host token that reads a site's own name at render. */ export const AI_SITE_NAME_TOKEN = '{{host.businessName}}';
36
+ const isRecord = (value)=>Boolean(value) && typeof value === 'object' && !Array.isArray(value);
37
+ const escapeRegExp = (value)=>value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
38
+ /**
39
+ * The tree with every written occurrence of the site's name — the brand, the
40
+ * copyright line — replaced by the host token that reads it. Matched whole,
41
+ * ignoring case and runs of spaces. Anything that is not a node map, and a
42
+ * name too short to match safely, leaves the tree as it came.
43
+ */ export function aiLayoutWithSiteName(tree, siteName) {
44
+ const name = (siteName != null ? siteName : '').replace(/\s+/g, ' ').trim();
45
+ if (name.length < 3 || !isRecord(tree) || !isRecord(tree['nodes'])) return tree;
46
+ const pattern = new RegExp(`(?<![\\p{L}\\p{N}])${escapeRegExp(name).replace(/ /g, '\\s+')}(?![\\p{L}\\p{N}])`, 'giu');
47
+ let changed = false;
48
+ const nodes = {};
49
+ for (const [id, node] of Object.entries(tree['nodes'])){
50
+ if (!isRecord(node) || !isRecord(node['props'])) {
51
+ nodes[id] = node;
52
+ continue;
53
+ }
54
+ const props = {};
55
+ let touched = false;
56
+ for (const [key, value] of Object.entries(node['props'])){
57
+ const next = typeof value === 'string' ? value.replace(pattern, AI_SITE_NAME_TOKEN) : value;
58
+ if (next !== value) touched = true;
59
+ props[key] = next;
60
+ }
61
+ nodes[id] = touched ? _extends({}, node, {
62
+ props
63
+ }) : node;
64
+ changed || (changed = touched);
65
+ }
66
+ return changed ? _extends({}, tree, {
67
+ nodes
68
+ }) : tree;
69
+ }
70
+ const EMAIL = /[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}/g;
71
+ /** A phone number as people write one: seven or more digits, with the usual separators between them. */ const PHONE = /(?:\+?\(?\d[\d\s().-]{5,}\d)/g;
72
+ const digitsOf = (value)=>value.replace(/\D/g, '');
73
+ const STREET_SUFFIX = 'Street|St|Avenue|Ave|Road|Rd|Boulevard|Blvd|Lane|Ln|Drive|Dr|Way|Court|Ct|Place|Pl|Parkway|Pkwy|Highway|Hwy|Trail|Trl|Circle|Cir|Square|Sq';
74
+ /** A street address as a footer writes one: a house number, one to four words, and a street suffix. */ const ADDRESS = new RegExp(`\\b\\d{1,6}\\s+(?:[A-Z0-9][\\w'.-]*\\s+){1,4}(?:${STREET_SUFFIX})\\b\\.?`, 'g');
75
+ const DAY = '(?:Mon(?:day)?|Tue(?:s|sday)?|Wed(?:nesday)?|Thu(?:r|rs|rsday)?|Fri(?:day)?|Sat(?:urday)?|Sun(?:day)?)';
76
+ /**
77
+ * Opening hours: a time of day ("9am", "8:30 PM") or a range of days
78
+ * ("Mon–Fri", "Monday through Saturday"). A bare "9–5" is left alone, since
79
+ * "2–3 weeks" is written the same way.
80
+ */ const HOURS = new RegExp([
81
+ '\\b\\d{1,2}(?::\\d{2})?\\s?(?:[ap]\\.?m\\.?)(?![a-z])',
82
+ `\\b${DAY}\\s?(?:[–—-]|to|through|thru)\\s?${DAY}\\b`
83
+ ].join('|'), 'gi');
84
+ /** SVG path data: a move command, then only commands and numbers. */ const SVG_PATH_DATA = /^\s*[Mm][\s\d.,eE+-]*[\d.][\s\d.,eE+\-MmLlHhVvCcSsQqTtAaZz]*$/;
85
+ /** The words of an address, as a brief and a layout can both spell them. */ const addressKey = (value)=>{
86
+ var _value_toLowerCase_match;
87
+ const [number, word] = (_value_toLowerCase_match = value.toLowerCase().match(/[a-z0-9]+/g)) != null ? _value_toLowerCase_match : [];
88
+ return `${number != null ? number : ''} ${word != null ? word : ''}`;
89
+ };
90
+ /**
91
+ * The contact details a brief gives: its email addresses, the digits of its
92
+ * phone numbers, the house number and first word of its street addresses,
93
+ * and whether it gives opening hours at all.
94
+ */ function briefFacts(brief) {
95
+ var _brief_match, _brief_match1;
96
+ return {
97
+ emails: new Set(((_brief_match = brief.match(EMAIL)) != null ? _brief_match : []).map((email)=>email.toLowerCase())),
98
+ digits: digitsOf(brief),
99
+ addresses: new Set(((_brief_match1 = brief.match(ADDRESS)) != null ? _brief_match1 : []).map(addressKey)),
100
+ hours: new RegExp(HOURS.source, 'i').test(brief)
101
+ };
102
+ }
103
+ /**
104
+ * Rule 14 for a layout: every email address, phone number, street address
105
+ * and opening time its words carry is one the brief gives. A number is read
106
+ * by its digits, so a brief's "512.555.0142" admits "(512) 555-0142"; a year
107
+ * or a price is not a phone number, so only a run of seven digits or more is
108
+ * read as one. An address is matched by its house number and first street
109
+ * word; hours are admitted when the brief gives any, since a brief that names
110
+ * its hours is spelled a dozen ways a footer may fairly reword.
111
+ */ export function aiLayoutInventedContactViolations(tree, brief) {
112
+ const given = briefFacts(brief);
113
+ const invented = [];
114
+ const nodeIds = [];
115
+ for (const { id, node } of walkTree(tree)){
116
+ var _node_props;
117
+ for (const value of Object.values((_node_props = node.props) != null ? _node_props : {})){
118
+ // An icon's drawing (`iconPath`) is SVG path data, whose coordinates read as phone numbers.
119
+ if (typeof value !== 'string' || SVG_PATH_DATA.test(value)) continue;
120
+ const matches = (pattern)=>{
121
+ var _value_match;
122
+ return [
123
+ ...(_value_match = value.match(pattern)) != null ? _value_match : []
124
+ ];
125
+ };
126
+ const found = [
127
+ ...matches(EMAIL).filter((email)=>!given.emails.has(email.toLowerCase())),
128
+ ...matches(PHONE).filter((phone)=>{
129
+ const digits = digitsOf(phone);
130
+ return digits.length >= 7 && !given.digits.includes(digits);
131
+ }),
132
+ ...matches(ADDRESS).filter((address)=>!given.addresses.has(addressKey(address))),
133
+ ...given.hours ? [] : matches(HOURS)
134
+ ];
135
+ if (!found.length) continue;
136
+ invented.push(...found.map((fact)=>fact.trim()));
137
+ if (!nodeIds.includes(id)) nodeIds.push(id);
138
+ }
139
+ }
140
+ if (!invented.length) return [];
141
+ return [
142
+ {
143
+ rule: 14,
144
+ code: 'contact-not-in-brief',
145
+ message: `${[
146
+ ...new Set(invented)
147
+ ].map((fact)=>`"${fact}"`).join(', ')} is not in the brief. A layout shows only the contact details the brief gives: leave this out, and never invent one.`,
148
+ nodeIds
149
+ }
150
+ ];
151
+ }
152
+
153
+ //# sourceMappingURL=ai-layout-site-facts.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../../../../libs/plugins/ai/src/lib/jobs/ai-layout-site-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 type { AiDoctrineNode, AiDoctrineTree, AiDoctrineViolation } from '../runtime/ai-doctrine-validators'\nimport { walkTree } from '../runtime/ai-doctrine-validators'\n\n/**\n * What a layout may say about the business it frames (AGL-3596).\n *\n * A layout's header and footer are on every page, so a fact in them is\n * published everywhere at once. Two went wrong on beta.230: the model coined\n * a name for the business (\"Austin Paws Grooming\" for a site called Hillside\n * Dog Grooming), and a footer is exactly where a model reaches for a phone\n * number, an email or opening hours the brief never gave.\n *\n * - The site's name is the brand, and it is written as the host token that\n * reads it (`{{host.businessName}}`), so a rename in Setup follows on every\n * page rather than leaving the name it was built under\n * (`aiLayoutWithSiteName`).\n * - A contact detail the brief does not give is refused by the layout's own\n * check (`aiLayoutInventedContactViolations`), so the model is asked again\n * to leave it out: an email, a phone number, a street address or opening\n * hours appear in the layout only when the brief has them.\n */\n\n/** The host token that reads a site's own name at render. */\nexport const AI_SITE_NAME_TOKEN = '{{host.businessName}}'\n\nconst isRecord = (value: unknown): value is Record<string, unknown> =>\n Boolean(value) && typeof value === 'object' && !Array.isArray(value)\n\nconst escapeRegExp = (value: string) => value.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&')\n\n/**\n * The tree with every written occurrence of the site's name — the brand, the\n * copyright line — replaced by the host token that reads it. Matched whole,\n * ignoring case and runs of spaces. Anything that is not a node map, and a\n * name too short to match safely, leaves the tree as it came.\n */\nexport function aiLayoutWithSiteName(tree: unknown, siteName: string | null | undefined): unknown {\n const name = (siteName ?? '').replace(/\\s+/g, ' ').trim()\n if (name.length < 3 || !isRecord(tree) || !isRecord(tree['nodes'])) return tree\n const pattern = new RegExp(`(?<![\\\\p{L}\\\\p{N}])${escapeRegExp(name).replace(/ /g, '\\\\s+')}(?![\\\\p{L}\\\\p{N}])`, 'giu')\n let changed = false\n const nodes: Record<string, unknown> = {}\n for (const [id, node] of Object.entries(tree['nodes'])) {\n if (!isRecord(node) || !isRecord(node['props'])) {\n nodes[id] = node\n continue\n }\n const props: Record<string, unknown> = {}\n let touched = false\n for (const [key, value] of Object.entries(node['props'])) {\n const next = typeof value === 'string' ? value.replace(pattern, AI_SITE_NAME_TOKEN) : value\n if (next !== value) touched = true\n props[key] = next\n }\n nodes[id] = touched ? { ...node, props } : node\n changed ||= touched\n }\n return changed ? { ...tree, nodes } : tree\n}\n\nconst EMAIL = /[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,}/g\n/** A phone number as people write one: seven or more digits, with the usual separators between them. */\nconst PHONE = /(?:\\+?\\(?\\d[\\d\\s().-]{5,}\\d)/g\n\nconst digitsOf = (value: string) => value.replace(/\\D/g, '')\n\nconst STREET_SUFFIX =\n 'Street|St|Avenue|Ave|Road|Rd|Boulevard|Blvd|Lane|Ln|Drive|Dr|Way|Court|Ct|Place|Pl|Parkway|Pkwy|Highway|Hwy|Trail|Trl|Circle|Cir|Square|Sq'\n/** A street address as a footer writes one: a house number, one to four words, and a street suffix. */\nconst ADDRESS = new RegExp(`\\\\b\\\\d{1,6}\\\\s+(?:[A-Z0-9][\\\\w'.-]*\\\\s+){1,4}(?:${STREET_SUFFIX})\\\\b\\\\.?`, 'g')\nconst DAY = '(?:Mon(?:day)?|Tue(?:s|sday)?|Wed(?:nesday)?|Thu(?:r|rs|rsday)?|Fri(?:day)?|Sat(?:urday)?|Sun(?:day)?)'\n/**\n * Opening hours: a time of day (\"9am\", \"8:30 PM\") or a range of days\n * (\"Mon–Fri\", \"Monday through Saturday\"). A bare \"9–5\" is left alone, since\n * \"2–3 weeks\" is written the same way.\n */\nconst HOURS = new RegExp(\n [\n '\\\\b\\\\d{1,2}(?::\\\\d{2})?\\\\s?(?:[ap]\\\\.?m\\\\.?)(?![a-z])',\n `\\\\b${DAY}\\\\s?(?:[–—-]|to|through|thru)\\\\s?${DAY}\\\\b`,\n ].join('|'),\n 'gi',\n)\n\n/** SVG path data: a move command, then only commands and numbers. */\nconst SVG_PATH_DATA = /^\\s*[Mm][\\s\\d.,eE+-]*[\\d.][\\s\\d.,eE+\\-MmLlHhVvCcSsQqTtAaZz]*$/\n\n/** The words of an address, as a brief and a layout can both spell them. */\nconst addressKey = (value: string) => {\n const [number, word] = value.toLowerCase().match(/[a-z0-9]+/g) ?? []\n return `${number ?? ''} ${word ?? ''}`\n}\n\n/**\n * The contact details a brief gives: its email addresses, the digits of its\n * phone numbers, the house number and first word of its street addresses,\n * and whether it gives opening hours at all.\n */\nfunction briefFacts(brief: string): { emails: Set<string>; digits: string; addresses: Set<string>; hours: boolean } {\n return {\n emails: new Set((brief.match(EMAIL) ?? []).map((email) => email.toLowerCase())),\n digits: digitsOf(brief),\n addresses: new Set((brief.match(ADDRESS) ?? []).map(addressKey)),\n hours: new RegExp(HOURS.source, 'i').test(brief),\n }\n}\n\n/**\n * Rule 14 for a layout: every email address, phone number, street address\n * and opening time its words carry is one the brief gives. A number is read\n * by its digits, so a brief's \"512.555.0142\" admits \"(512) 555-0142\"; a year\n * or a price is not a phone number, so only a run of seven digits or more is\n * read as one. An address is matched by its house number and first street\n * word; hours are admitted when the brief gives any, since a brief that names\n * its hours is spelled a dozen ways a footer may fairly reword.\n */\nexport function aiLayoutInventedContactViolations(tree: AiDoctrineTree, brief: string): AiDoctrineViolation[] {\n const given = briefFacts(brief)\n const invented: string[] = []\n const nodeIds: string[] = []\n for (const { id, node } of walkTree(tree)) {\n for (const value of Object.values((node as AiDoctrineNode).props ?? {})) {\n // An icon's drawing (`iconPath`) is SVG path data, whose coordinates read as phone numbers.\n if (typeof value !== 'string' || SVG_PATH_DATA.test(value)) continue\n const matches = (pattern: RegExp): string[] => [...(value.match(pattern) ?? [])]\n const found: string[] = [\n ...matches(EMAIL).filter((email) => !given.emails.has(email.toLowerCase())),\n ...matches(PHONE).filter((phone) => {\n const digits = digitsOf(phone)\n return digits.length >= 7 && !given.digits.includes(digits)\n }),\n ...matches(ADDRESS).filter((address) => !given.addresses.has(addressKey(address))),\n ...(given.hours ? [] : matches(HOURS)),\n ]\n if (!found.length) continue\n invented.push(...found.map((fact) => fact.trim()))\n if (!nodeIds.includes(id)) nodeIds.push(id)\n }\n }\n if (!invented.length) return []\n return [\n {\n rule: 14,\n code: 'contact-not-in-brief',\n message: `${[...new Set(invented)].map((fact) => `\"${fact}\"`).join(', ')} is not in the brief. A layout shows only the contact details the brief gives: leave this out, and never invent one.`,\n nodeIds,\n },\n ]\n}\n"],"names":["walkTree","AI_SITE_NAME_TOKEN","isRecord","value","Boolean","Array","isArray","escapeRegExp","replace","aiLayoutWithSiteName","tree","siteName","name","trim","length","pattern","RegExp","changed","nodes","id","node","Object","entries","props","touched","key","next","EMAIL","PHONE","digitsOf","STREET_SUFFIX","ADDRESS","DAY","HOURS","join","SVG_PATH_DATA","addressKey","number","word","toLowerCase","match","briefFacts","brief","emails","Set","map","email","digits","addresses","hours","source","test","aiLayoutInventedContactViolations","given","invented","nodeIds","values","matches","found","filter","has","phone","includes","address","push","fact","rule","code","message"],"mappings":"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"}
@@ -0,0 +1,40 @@
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 { HostFunction } from '@aglyn/aglyn/app-utils/functions';
18
+ import type { AiLogicSiteVariable } from '../model/ai-logic-job';
19
+ /**
20
+ * What a `logic` job reads (AGL-3603): the site's variables and function
21
+ * names, in the window the Functions & Variables page itself reads, and one
22
+ * saved function by id. Functions and variables are core documents
23
+ * (`hosts/{hostId}/functions`, `hosts/{hostId}/variables`), read through the
24
+ * Admin SDK as projections of the fields named here.
25
+ */
26
+ type Firestore = FirebaseFirestore.Firestore;
27
+ /** Records of one kind a job reads: the logic page's own ceiling. */
28
+ export declare const AI_LOGIC_RECORDS_WINDOW = 100;
29
+ export interface AiLogicRecords {
30
+ variables: AiLogicSiteVariable[];
31
+ functions: string[];
32
+ }
33
+ /** The site's live variables (name, type, value) and function names. */
34
+ export declare function readAiLogicRecords(firestore: Firestore, hostId: string): Promise<AiLogicRecords>;
35
+ /** One saved function of the site, or `null` for one that does not exist or was deleted. */
36
+ export declare function readAiLogicFunction(firestore: Firestore, input: {
37
+ hostId: string;
38
+ id: string;
39
+ }): Promise<HostFunction | null>;
40
+ export {};
@@ -0,0 +1,55 @@
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
+ /** Records of one kind a job reads: the logic page's own ceiling. */ export const AI_LOGIC_RECORDS_WINDOW = 100;
18
+ const live = (data)=>data['deletedAt'] == null;
19
+ /** The site's live variables (name, type, value) and function names. */ export async function readAiLogicRecords(firestore, hostId) {
20
+ const host = firestore.collection('hosts').doc(hostId);
21
+ const [variables, functions] = await Promise.all([
22
+ host.collection('variables').select('name', 'type', 'value', 'deletedAt').limit(AI_LOGIC_RECORDS_WINDOW).get(),
23
+ host.collection('functions').select('name', 'deletedAt').limit(AI_LOGIC_RECORDS_WINDOW).get()
24
+ ]);
25
+ return {
26
+ variables: variables.docs.map((doc)=>{
27
+ var _doc_data;
28
+ return (_doc_data = doc.data()) != null ? _doc_data : {};
29
+ }).filter(live).filter((data)=>typeof data['name'] === 'string' && data['name']).map((data)=>({
30
+ name: String(data['name']),
31
+ type: typeof data['type'] === 'string' ? data['type'] : 'text',
32
+ value: typeof data['value'] === 'string' ? data['value'] : ''
33
+ })),
34
+ functions: functions.docs.map((doc)=>{
35
+ var _doc_data;
36
+ return (_doc_data = doc.data()) != null ? _doc_data : {};
37
+ }).filter(live).map((data)=>typeof data['name'] === 'string' ? data['name'].trim() : '').filter(Boolean)
38
+ };
39
+ }
40
+ /** One saved function of the site, or `null` for one that does not exist or was deleted. */ export async function readAiLogicFunction(firestore, input) {
41
+ var _snapshot_data;
42
+ const snapshot = await firestore.collection('hosts').doc(input.hostId).collection('functions').doc(input.id).get();
43
+ const data = snapshot.exists ? (_snapshot_data = snapshot.data()) != null ? _snapshot_data : {} : null;
44
+ if (!data || !live(data) || typeof data['name'] !== 'string') return null;
45
+ return _extends({
46
+ name: data['name'],
47
+ parameters: Array.isArray(data['parameters']) ? data['parameters'] : [],
48
+ variables: Array.isArray(data['variables']) ? data['variables'] : [],
49
+ operations: Array.isArray(data['operations']) ? data['operations'] : []
50
+ }, typeof data['returnValue'] === 'string' ? {
51
+ returnValue: data['returnValue']
52
+ } : {});
53
+ }
54
+
55
+ //# sourceMappingURL=ai-logic-records.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../../../../libs/plugins/ai/src/lib/jobs/ai-logic-records.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 { HostFunction } from '@aglyn/aglyn/app-utils/functions'\nimport type { AiLogicSiteVariable } from '../model/ai-logic-job'\n\n/**\n * What a `logic` job reads (AGL-3603): the site's variables and function\n * names, in the window the Functions & Variables page itself reads, and one\n * saved function by id. Functions and variables are core documents\n * (`hosts/{hostId}/functions`, `hosts/{hostId}/variables`), read through the\n * Admin SDK as projections of the fields named here.\n */\n\ntype Firestore = FirebaseFirestore.Firestore\ntype Data = Record<string, unknown>\n\n/** Records of one kind a job reads: the logic page's own ceiling. */\nexport const AI_LOGIC_RECORDS_WINDOW = 100\n\nconst live = (data: Data) => data['deletedAt'] == null\n\nexport interface AiLogicRecords {\n variables: AiLogicSiteVariable[]\n functions: string[]\n}\n\n/** The site's live variables (name, type, value) and function names. */\nexport async function readAiLogicRecords(firestore: Firestore, hostId: string): Promise<AiLogicRecords> {\n const host = firestore.collection('hosts').doc(hostId)\n const [variables, functions] = await Promise.all([\n host.collection('variables').select('name', 'type', 'value', 'deletedAt').limit(AI_LOGIC_RECORDS_WINDOW).get(),\n host.collection('functions').select('name', 'deletedAt').limit(AI_LOGIC_RECORDS_WINDOW).get(),\n ])\n return {\n variables: variables.docs\n .map((doc) => (doc.data() ?? {}) as Data)\n .filter(live)\n .filter((data) => typeof data['name'] === 'string' && data['name'])\n .map((data) => ({\n name: String(data['name']),\n type: (typeof data['type'] === 'string' ? data['type'] : 'text') as AiLogicSiteVariable['type'],\n value: typeof data['value'] === 'string' ? data['value'] : '',\n })),\n functions: functions.docs\n .map((doc) => (doc.data() ?? {}) as Data)\n .filter(live)\n .map((data) => (typeof data['name'] === 'string' ? data['name'].trim() : ''))\n .filter(Boolean),\n }\n}\n\n/** One saved function of the site, or `null` for one that does not exist or was deleted. */\nexport async function readAiLogicFunction(\n firestore: Firestore,\n input: { hostId: string; id: string },\n): Promise<HostFunction | null> {\n const snapshot = await firestore.collection('hosts').doc(input.hostId).collection('functions').doc(input.id).get()\n const data = snapshot.exists ? ((snapshot.data() ?? {}) as Data) : null\n if (!data || !live(data) || typeof data['name'] !== 'string') return null\n return {\n name: data['name'],\n parameters: Array.isArray(data['parameters']) ? (data['parameters'] as HostFunction['parameters']) : [],\n variables: Array.isArray(data['variables']) ? (data['variables'] as HostFunction['variables']) : [],\n operations: Array.isArray(data['operations']) ? (data['operations'] as HostFunction['operations']) : [],\n ...(typeof data['returnValue'] === 'string' ? { returnValue: data['returnValue'] } : {}),\n }\n}\n"],"names":["AI_LOGIC_RECORDS_WINDOW","live","data","readAiLogicRecords","firestore","hostId","host","collection","doc","variables","functions","Promise","all","select","limit","get","docs","map","filter","name","String","type","value","trim","Boolean","readAiLogicFunction","input","snapshot","id","exists","parameters","Array","isArray","operations","returnValue"],"mappings":"AAAA;;;;;;;;;;;;;;;CAeC;AAgBD,mEAAmE,GACnE,OAAO,MAAMA,0BAA0B,IAAG;AAE1C,MAAMC,OAAO,CAACC,OAAeA,IAAI,CAAC,YAAY,IAAI;AAOlD,sEAAsE,GACtE,OAAO,eAAeC,mBAAmBC,SAAoB,EAAEC,MAAc;IAC3E,MAAMC,OAAOF,UAAUG,UAAU,CAAC,SAASC,GAAG,CAACH;IAC/C,MAAM,CAACI,WAAWC,UAAU,GAAG,MAAMC,QAAQC,GAAG,CAAC;QAC/CN,KAAKC,UAAU,CAAC,aAAaM,MAAM,CAAC,QAAQ,QAAQ,SAAS,aAAaC,KAAK,CAACd,yBAAyBe,GAAG;QAC5GT,KAAKC,UAAU,CAAC,aAAaM,MAAM,CAAC,QAAQ,aAAaC,KAAK,CAACd,yBAAyBe,GAAG;KAC5F;IACD,OAAO;QACLN,WAAWA,UAAUO,IAAI,CACtBC,GAAG,CAAC,CAACT;gBAASA;oBAAAA,YAAAA,IAAIN,IAAI,cAARM,YAAc,CAAC;WAC7BU,MAAM,CAACjB,MACPiB,MAAM,CAAC,CAAChB,OAAS,OAAOA,IAAI,CAAC,OAAO,KAAK,YAAYA,IAAI,CAAC,OAAO,EACjEe,GAAG,CAAC,CAACf,OAAU,CAAA;gBACdiB,MAAMC,OAAOlB,IAAI,CAAC,OAAO;gBACzBmB,MAAO,OAAOnB,IAAI,CAAC,OAAO,KAAK,WAAWA,IAAI,CAAC,OAAO,GAAG;gBACzDoB,OAAO,OAAOpB,IAAI,CAAC,QAAQ,KAAK,WAAWA,IAAI,CAAC,QAAQ,GAAG;YAC7D,CAAA;QACFQ,WAAWA,UAAUM,IAAI,CACtBC,GAAG,CAAC,CAACT;gBAASA;oBAAAA,YAAAA,IAAIN,IAAI,cAARM,YAAc,CAAC;WAC7BU,MAAM,CAACjB,MACPgB,GAAG,CAAC,CAACf,OAAU,OAAOA,IAAI,CAAC,OAAO,KAAK,WAAWA,IAAI,CAAC,OAAO,CAACqB,IAAI,KAAK,IACxEL,MAAM,CAACM;IACZ;AACF;AAEA,0FAA0F,GAC1F,OAAO,eAAeC,oBACpBrB,SAAoB,EACpBsB,KAAqC;QAGJC;IADjC,MAAMA,WAAW,MAAMvB,UAAUG,UAAU,CAAC,SAASC,GAAG,CAACkB,MAAMrB,MAAM,EAAEE,UAAU,CAAC,aAAaC,GAAG,CAACkB,MAAME,EAAE,EAAEb,GAAG;IAChH,MAAMb,OAAOyB,SAASE,MAAM,IAAKF,iBAAAA,SAASzB,IAAI,cAAbyB,iBAAmB,CAAC,IAAc;IACnE,IAAI,CAACzB,QAAQ,CAACD,KAAKC,SAAS,OAAOA,IAAI,CAAC,OAAO,KAAK,UAAU,OAAO;IACrE,OAAO;QACLiB,MAAMjB,IAAI,CAAC,OAAO;QAClB4B,YAAYC,MAAMC,OAAO,CAAC9B,IAAI,CAAC,aAAa,IAAKA,IAAI,CAAC,aAAa,GAAkC,EAAE;QACvGO,WAAWsB,MAAMC,OAAO,CAAC9B,IAAI,CAAC,YAAY,IAAKA,IAAI,CAAC,YAAY,GAAiC,EAAE;QACnG+B,YAAYF,MAAMC,OAAO,CAAC9B,IAAI,CAAC,aAAa,IAAKA,IAAI,CAAC,aAAa,GAAkC,EAAE;OACnG,OAAOA,IAAI,CAAC,cAAc,KAAK,WAAW;QAAEgC,aAAahC,IAAI,CAAC,cAAc;IAAC,IAAI,CAAC;AAE1F"}
@@ -52,6 +52,13 @@ export interface AiSitePublishDeps {
52
52
  sendSitePublished?: typeof sendGa4SitePublished;
53
53
  dropCache?: typeof dropPluginSiteCache;
54
54
  }
55
+ /**
56
+ * Whether a build puts its pages live (AGL-3616): only where its request
57
+ * asked to (`publish`, set by Assist's proposal) AND the member ticked the
58
+ * plan card's box when confirming (`publishConfirmed`, set by the resume
59
+ * door). Every other build leaves drafts.
60
+ */
61
+ export declare function aiJobPublishesBuild(job: Pick<AiJob, 'kind' | 'inputs'>): boolean;
55
62
  /** Whether a finished job of this shape publishes what it built. */
56
63
  export declare function aiJobPublishesSite(job: Pick<AiJob, 'kind' | 'inputs'>): boolean;
57
64
  /**
@@ -22,6 +22,15 @@ import { decodeStoredNodes, encodeStoredNodes } from "@aglyn/aglyn/app-utils/sto
22
22
  import { dropPluginSiteCache } from "@aglyn/aglyn/plugin-manager/plugin-site-cache";
23
23
  import { sendGa4SitePublished } from "@aglyn/tenant-data-admin/server/ga4-measurement-protocol";
24
24
  import { FieldValue } from "firebase-admin/firestore";
25
+ /**
26
+ * Whether a build puts its pages live (AGL-3616): only where its request
27
+ * asked to (`publish`, set by Assist's proposal) AND the member ticked the
28
+ * plan card's box when confirming (`publishConfirmed`, set by the resume
29
+ * door). Every other build leaves drafts.
30
+ */ export function aiJobPublishesBuild(job) {
31
+ var _job_inputs, _job_inputs1;
32
+ return job.kind === 'build' && ((_job_inputs = job.inputs) == null ? void 0 : _job_inputs['publish']) === true && ((_job_inputs1 = job.inputs) == null ? void 0 : _job_inputs1['publishConfirmed']) === true;
33
+ }
25
34
  /** Whether a finished job of this shape publishes what it built. */ export function aiJobPublishesSite(job) {
26
35
  var _job_inputs;
27
36
  return job.kind === 'site' && ((_job_inputs = job.inputs) == null ? void 0 : _job_inputs['autoConfirm']) === true;