@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,270 @@
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
+ */ 'use client';
17
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
18
+ import { lockdownRefusalText, parseLockdownRefusal } from "@aglyn/aglyn";
19
+ import { pluginDocsHelp } from "@aglyn/aglyn/app-utils/docs-help";
20
+ import { checkQuota } from "@aglyn/aglyn/app-utils/plan-entitlements";
21
+ import { mdiCreation } from "@aglyn/shared-data-mdi";
22
+ import { MdiIcon } from "@aglyn/shared-ui-jsx";
23
+ import { authorizedFetch } from "@aglyn/shared-util-http/authorized-token";
24
+ import { useHostOrgId, useOrgPlan, useUser } from "@aglyn/tenant-feature-instance";
25
+ import { Alert, Button, Dialog, DialogActions, DialogContent, DialogTitle, Link, MenuItem, Stack, TextField, Typography } from "@mui/material";
26
+ import { useCallback, useEffect, useRef, useState } from "react";
27
+ import { AiJobFollow } from "./ai-job-follow.component.js";
28
+ import { publishAiJob } from "./ai-jobs-store.js";
29
+ import { AiUpsellButton } from "./ai-upsell-dialog.component.js";
30
+ /** The longest brief a job admits. */ const BRIEF_MAX_CHARS = 4000;
31
+ /** The longest name a campaign job reads. */ const NAME_MAX_CHARS = 120;
32
+ const FAILED_COPY = 'The campaign could not be started. Try again.';
33
+ /**
34
+ * The campaign door's refusal for a plan that sends no campaign email, as the
35
+ * campaign step words it, so a plan that changed after the dialog opened is
36
+ * recognized and answered with the design-only path.
37
+ */ const PLAN_REFUSAL_PREFIX = 'Campaign email is not included';
38
+ /** What the dialog says for each of the two jobs it can start. */ export const AI_CAMPAIGN_CREATE_COPY = {
39
+ campaign: {
40
+ title: 'Create a campaign with AI',
41
+ next: 'It writes an email design with three subject lines and three preheaders, and a draft ' + 'campaign that would send it. Nothing is sent or scheduled, and the campaign is aimed at ' + 'nobody until you pick its lists.',
42
+ submit: 'Write the campaign',
43
+ started: 'The campaign is being written. When it is done, open the draft campaign to pick who ' + 'receives it, check the email and schedule it.'
44
+ },
45
+ email: {
46
+ title: 'Write a campaign email with AI',
47
+ next: 'This workspace’s plan does not send campaign email, so this writes the email design on ' + 'its own, with three subject lines and three preheaders. Upgrade in Billing to draft a ' + 'campaign around it.',
48
+ submit: 'Plan the email',
49
+ started: 'The email is being planned. Review the plan here or in AI jobs, and confirm it to build. ' + 'The design is built as a draft and sent to nobody.'
50
+ }
51
+ };
52
+ /** Which job a workspace's plan allows: a campaign where it sends campaign email, else the design alone. */ export function aiCampaignJobKind(org) {
53
+ return checkQuota(org, 'emailSendsPerMonth', 0).allowed ? 'campaign' : 'email';
54
+ }
55
+ /** The job's inputs: the name the member gave it, when they gave one. */ export function aiCampaignJobInputs(name) {
56
+ const trimmed = name.replace(/\s+/g, ' ').trim().slice(0, NAME_MAX_CHARS);
57
+ return trimmed ? {
58
+ name: trimmed
59
+ } : {};
60
+ }
61
+ export function AiCreateCampaignButton(props) {
62
+ var _ref, _useHostOrgId, _props_orgId;
63
+ var _sites_;
64
+ const { hostId, sites } = props;
65
+ const { data: user } = useUser();
66
+ const userRef = useRef(user);
67
+ userRef.current = user;
68
+ const [open, setOpen] = useState(false);
69
+ const [siteId, setSiteId] = useState((_ref = hostId != null ? hostId : (_sites_ = sites[0]) == null ? void 0 : _sites_.id) != null ? _ref : '');
70
+ const site = hostId != null ? hostId : siteId;
71
+ const siteOrgId = (_useHostOrgId = useHostOrgId(site || undefined)) != null ? _useHostOrgId : undefined;
72
+ const orgId = (_props_orgId = props.orgId) != null ? _props_orgId : siteOrgId;
73
+ const { org, ready } = useOrgPlan(site || undefined);
74
+ const [refusedPlan, setRefusedPlan] = useState(false);
75
+ const kind = refusedPlan ? 'email' : aiCampaignJobKind(org);
76
+ const copy = AI_CAMPAIGN_CREATE_COPY[kind];
77
+ const [name, setName] = useState('');
78
+ const [brief, setBrief] = useState('');
79
+ const [busy, setBusy] = useState(false);
80
+ const [notice, setNotice] = useState(null);
81
+ const [started, setStarted] = useState(null);
82
+ // The org hub's sites settle after the widget mounts; take the first once they do.
83
+ useEffect(()=>{
84
+ if (!hostId && !siteId && sites[0]) setSiteId(sites[0].id);
85
+ }, [
86
+ hostId,
87
+ siteId,
88
+ sites
89
+ ]);
90
+ useEffect(()=>{
91
+ if (!open) return;
92
+ setNotice(null);
93
+ setStarted(null);
94
+ setRefusedPlan(false);
95
+ }, [
96
+ open
97
+ ]);
98
+ const start = useCallback(async ()=>{
99
+ if (!orgId || !site || !brief.trim()) return;
100
+ setBusy(true);
101
+ setNotice(null);
102
+ try {
103
+ var _ref;
104
+ const response = await authorizedFetch(userRef.current, '/api/ai/jobs', {
105
+ method: 'POST',
106
+ headers: {
107
+ 'Content-Type': 'application/json'
108
+ },
109
+ body: JSON.stringify({
110
+ orgId,
111
+ hostId: site,
112
+ kind,
113
+ brief: brief.trim(),
114
+ inputs: aiCampaignJobInputs(name)
115
+ })
116
+ });
117
+ const payload = await response.json().catch(()=>null);
118
+ if (!response.ok) {
119
+ var _ref1;
120
+ const locked = parseLockdownRefusal(response.status, payload);
121
+ const error = String((_ref1 = payload == null ? void 0 : payload.error) != null ? _ref1 : FAILED_COPY);
122
+ if (kind === 'campaign' && response.status === 403 && error.startsWith(PLAN_REFUSAL_PREFIX)) {
123
+ setRefusedPlan(true);
124
+ }
125
+ setNotice(locked ? lockdownRefusalText(locked) : error);
126
+ return;
127
+ }
128
+ const job = (_ref = payload == null ? void 0 : payload.job) != null ? _ref : null;
129
+ if (!job) {
130
+ setNotice(FAILED_COPY);
131
+ return;
132
+ }
133
+ publishAiJob(job);
134
+ setStarted(job);
135
+ setBrief('');
136
+ setName('');
137
+ } catch (unused) {
138
+ setNotice(FAILED_COPY);
139
+ } finally{
140
+ setBusy(false);
141
+ }
142
+ }, [
143
+ orgId,
144
+ site,
145
+ kind,
146
+ brief,
147
+ name
148
+ ]);
149
+ if (!hostId && !sites.length) return null;
150
+ // Drawn from the shell's gates alone (AGL-3601): nothing asks a server until
151
+ // it is used, and a plan without the add-on gets the add-on's dialog.
152
+ if (props.entitled === false) {
153
+ return props.upgrade ? /*#__PURE__*/ _jsx(AiUpsellButton, {
154
+ kind: "campaign",
155
+ upgrade: props.upgrade
156
+ }) : null;
157
+ }
158
+ const help = pluginDocsHelp('aiMarketing', {
159
+ anchor: '#create-a-campaign',
160
+ excerpt: 'Writes an email design and a draft campaign that would send it, from a brief. Nothing is sent or scheduled, and the campaign is aimed at nobody until you pick its lists.'
161
+ });
162
+ return /*#__PURE__*/ _jsxs(_Fragment, {
163
+ children: [
164
+ /*#__PURE__*/ _jsx(Button, {
165
+ size: "small",
166
+ variant: "outlined",
167
+ startIcon: /*#__PURE__*/ _jsx(MdiIcon, {
168
+ path: mdiCreation.path
169
+ }),
170
+ onClick: ()=>setOpen(true),
171
+ children: 'Create with AI'
172
+ }),
173
+ /*#__PURE__*/ _jsxs(Dialog, {
174
+ open: open,
175
+ onClose: busy ? undefined : ()=>setOpen(false),
176
+ fullWidth: true,
177
+ maxWidth: "sm",
178
+ children: [
179
+ /*#__PURE__*/ _jsx(DialogTitle, {
180
+ children: copy.title
181
+ }),
182
+ /*#__PURE__*/ _jsx(DialogContent, {
183
+ children: started && orgId ? /*#__PURE__*/ _jsx(AiJobFollow, {
184
+ job: started,
185
+ orgId: orgId,
186
+ user: user,
187
+ intro: AI_CAMPAIGN_CREATE_COPY[started.kind === 'email' ? 'email' : 'campaign'].started,
188
+ onOpenJobs: ()=>setOpen(false)
189
+ }) : /*#__PURE__*/ _jsxs(Stack, {
190
+ spacing: 2,
191
+ sx: {
192
+ pt: 1
193
+ },
194
+ children: [
195
+ hostId ? null : /*#__PURE__*/ _jsx(TextField, {
196
+ select: true,
197
+ size: "small",
198
+ label: "Site",
199
+ helperText: "The site the campaign is placed on and sent as.",
200
+ value: siteId,
201
+ onChange: (event)=>setSiteId(event.target.value),
202
+ disabled: busy,
203
+ children: sites.map((entry)=>/*#__PURE__*/ _jsx(MenuItem, {
204
+ value: entry.id,
205
+ children: entry.name || entry.id
206
+ }, entry.id))
207
+ }),
208
+ /*#__PURE__*/ _jsx(TextField, {
209
+ size: "small",
210
+ label: "Campaign name (optional)",
211
+ value: name,
212
+ onChange: (event)=>setName(event.target.value.slice(0, NAME_MAX_CHARS)),
213
+ disabled: busy
214
+ }),
215
+ /*#__PURE__*/ _jsx(TextField, {
216
+ label: "What is the campaign for?",
217
+ placeholder: "Announce the autumn menu to our regulars, and point them at the class page to book the Tuesday bread class",
218
+ multiline: true,
219
+ minRows: 4,
220
+ value: brief,
221
+ onChange: (event)=>setBrief(event.target.value.slice(0, BRIEF_MAX_CHARS)),
222
+ disabled: busy,
223
+ autoFocus: true
224
+ }),
225
+ /*#__PURE__*/ _jsxs(Typography, {
226
+ variant: "body2",
227
+ color: "text.secondary",
228
+ children: [
229
+ copy.next,
230
+ ' ',
231
+ /*#__PURE__*/ _jsx(Link, {
232
+ href: help.href,
233
+ target: "_blank",
234
+ rel: "noopener",
235
+ title: help.excerpt,
236
+ children: 'How it works'
237
+ })
238
+ ]
239
+ }),
240
+ notice ? /*#__PURE__*/ _jsx(Alert, {
241
+ severity: "warning",
242
+ children: notice
243
+ }) : null
244
+ ]
245
+ })
246
+ }),
247
+ /*#__PURE__*/ _jsxs(DialogActions, {
248
+ children: [
249
+ /*#__PURE__*/ _jsx(Button, {
250
+ onClick: ()=>setOpen(false),
251
+ disabled: busy,
252
+ children: started ? 'Close' : 'Cancel'
253
+ }),
254
+ started ? null : /*#__PURE__*/ _jsx(Button, {
255
+ variant: "contained",
256
+ onClick: ()=>void start(),
257
+ disabled: busy || !ready || !orgId || !site || !brief.trim(),
258
+ children: copy.submit
259
+ })
260
+ ]
261
+ })
262
+ ]
263
+ })
264
+ ]
265
+ });
266
+ }
267
+ AiCreateCampaignButton.displayName = 'AiCreateCampaignButton';
268
+ export default AiCreateCampaignButton;
269
+
270
+ //# sourceMappingURL=ai-campaign-create.component.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../../../../libs/plugins/ai/src/lib/components/ai-campaign-create.component.tsx"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n'use client'\n\nimport type { ConsoleWidgetEntitlementProps } from '@aglyn/aglyn/plugin-manager/feature-plugins'\nimport { lockdownRefusalText, parseLockdownRefusal } from '@aglyn/aglyn'\nimport { pluginDocsHelp } from '@aglyn/aglyn/app-utils/docs-help'\nimport { checkQuota } from '@aglyn/aglyn/app-utils/plan-entitlements'\nimport { mdiCreation } from '@aglyn/shared-data-mdi'\nimport { MdiIcon } from '@aglyn/shared-ui-jsx'\nimport { authorizedFetch } from '@aglyn/shared-util-http/authorized-token'\nimport { useHostOrgId, useOrgPlan, useUser } from '@aglyn/tenant-feature-instance'\nimport {\n Alert,\n Button,\n Dialog,\n DialogActions,\n DialogContent,\n DialogTitle,\n Link,\n MenuItem,\n Stack,\n TextField,\n Typography,\n} from '@mui/material'\nimport { useCallback, useEffect, useRef, useState } from 'react'\nimport type { AiJobSummary } from '../model/ai-jobs.types'\nimport { AiJobFollow } from './ai-job-follow.component'\nimport { publishAiJob } from './ai-jobs-store'\nimport { AiUpsellButton } from './ai-upsell-dialog.component'\n\n/**\n * \"Create with AI\" on the Campaigns section (AGL-3603), in the zone the\n * marketing plugin hosts beside Create campaign: a brief starts the\n * `campaign` job, which writes an email design and the DRAFT campaign that\n * would send it — aimed at nobody, scheduled for nothing, sent by nobody until\n * a member does — or, where the workspace's plan sends no campaign email, the\n * `email` job, which writes the design on its own.\n *\n * The choice is the runner's own: the campaign step and its admission ask\n * `checkQuota(org, 'emailSendsPerMonth', 0)`, and this widget asks the same of\n * the same org document before it offers either. A plan that changes between\n * the two is the door's to refuse, and the dialog then offers the design on\n * its own rather than a dead end.\n *\n * The campaign is the marketing plugin's and neither plugin imports the other:\n * the props below restate the half of the zone's contract this widget reads.\n */\n\n/** One site a campaign could be placed on, as the zone hands it over. */\nexport interface AiCampaignSite {\n id: string\n name: string\n}\n\n/** What the `hostCampaigns` zone hands this widget. */\nexport interface AiCreateCampaignButtonProps extends ConsoleWidgetEntitlementProps {\n hostId: string | null\n orgId: string | null\n sites: readonly AiCampaignSite[]\n}\n\n/** The longest brief a job admits. */\nconst BRIEF_MAX_CHARS = 4_000\n\n/** The longest name a campaign job reads. */\nconst NAME_MAX_CHARS = 120\n\nconst FAILED_COPY = 'The campaign could not be started. Try again.'\n\n/**\n * The campaign door's refusal for a plan that sends no campaign email, as the\n * campaign step words it, so a plan that changed after the dialog opened is\n * recognized and answered with the design-only path.\n */\nconst PLAN_REFUSAL_PREFIX = 'Campaign email is not included'\n\n/** What the dialog says for each of the two jobs it can start. */\nexport const AI_CAMPAIGN_CREATE_COPY = {\n campaign: {\n title: 'Create a campaign with AI',\n next:\n 'It writes an email design with three subject lines and three preheaders, and a draft ' +\n 'campaign that would send it. Nothing is sent or scheduled, and the campaign is aimed at ' +\n 'nobody until you pick its lists.',\n submit: 'Write the campaign',\n started:\n 'The campaign is being written. When it is done, open the draft campaign to pick who ' +\n 'receives it, check the email and schedule it.',\n },\n email: {\n title: 'Write a campaign email with AI',\n next:\n 'This workspace’s plan does not send campaign email, so this writes the email design on ' +\n 'its own, with three subject lines and three preheaders. Upgrade in Billing to draft a ' +\n 'campaign around it.',\n submit: 'Plan the email',\n started:\n 'The email is being planned. Review the plan here or in AI jobs, and confirm it to build. ' +\n 'The design is built as a draft and sent to nobody.',\n },\n} as const\n\nexport type AiCampaignJobKind = keyof typeof AI_CAMPAIGN_CREATE_COPY\n\n/** Which job a workspace's plan allows: a campaign where it sends campaign email, else the design alone. */\nexport function aiCampaignJobKind(org: object | null | undefined): AiCampaignJobKind {\n return checkQuota(org as never, 'emailSendsPerMonth', 0).allowed ? 'campaign' : 'email'\n}\n\n/** The job's inputs: the name the member gave it, when they gave one. */\nexport function aiCampaignJobInputs(name: string): Record<string, string> {\n const trimmed = name.replace(/\\s+/g, ' ').trim().slice(0, NAME_MAX_CHARS)\n return trimmed ? { name: trimmed } : {}\n}\n\nexport function AiCreateCampaignButton(props: AiCreateCampaignButtonProps) {\n const { hostId, sites } = props\n const { data: user } = useUser()\n const userRef = useRef(user)\n userRef.current = user\n const [open, setOpen] = useState(false)\n const [siteId, setSiteId] = useState<string>(hostId ?? sites[0]?.id ?? '')\n const site = hostId ?? siteId\n const siteOrgId = useHostOrgId(site || undefined) ?? undefined\n const orgId = props.orgId ?? siteOrgId\n const { org, ready } = useOrgPlan(site || undefined)\n const [refusedPlan, setRefusedPlan] = useState(false)\n const kind: AiCampaignJobKind = refusedPlan ? 'email' : aiCampaignJobKind(org)\n const copy = AI_CAMPAIGN_CREATE_COPY[kind]\n const [name, setName] = useState('')\n const [brief, setBrief] = useState('')\n const [busy, setBusy] = useState(false)\n const [notice, setNotice] = useState<string | null>(null)\n const [started, setStarted] = useState<AiJobSummary | null>(null)\n\n // The org hub's sites settle after the widget mounts; take the first once they do.\n useEffect(() => {\n if (!hostId && !siteId && sites[0]) setSiteId(sites[0].id)\n }, [hostId, siteId, sites])\n\n useEffect(() => {\n if (!open) return\n setNotice(null)\n setStarted(null)\n setRefusedPlan(false)\n }, [open])\n\n const start = useCallback(async () => {\n if (!orgId || !site || !brief.trim()) return\n setBusy(true)\n setNotice(null)\n try {\n const response = await authorizedFetch(userRef.current, '/api/ai/jobs', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n orgId,\n hostId: site,\n kind,\n brief: brief.trim(),\n inputs: aiCampaignJobInputs(name),\n }),\n })\n const payload = await response.json().catch(() => null)\n if (!response.ok) {\n const locked = parseLockdownRefusal(response.status, payload)\n const error = String(payload?.error ?? FAILED_COPY)\n if (kind === 'campaign' && response.status === 403 && error.startsWith(PLAN_REFUSAL_PREFIX)) {\n setRefusedPlan(true)\n }\n setNotice(locked ? lockdownRefusalText(locked) : error)\n return\n }\n const job = (payload?.job as AiJobSummary | undefined) ?? null\n if (!job) {\n setNotice(FAILED_COPY)\n return\n }\n publishAiJob(job)\n setStarted(job)\n setBrief('')\n setName('')\n } catch {\n setNotice(FAILED_COPY)\n } finally {\n setBusy(false)\n }\n }, [orgId, site, kind, brief, name])\n\n if (!hostId && !sites.length) return null\n // Drawn from the shell's gates alone (AGL-3601): nothing asks a server until\n // it is used, and a plan without the add-on gets the add-on's dialog.\n if (props.entitled === false) {\n return props.upgrade ? <AiUpsellButton kind=\"campaign\" upgrade={props.upgrade} /> : null\n }\n\n const help = pluginDocsHelp('aiMarketing', {\n anchor: '#create-a-campaign',\n excerpt:\n 'Writes an email design and a draft campaign that would send it, from a brief. Nothing is sent or scheduled, and the campaign is aimed at nobody until you pick its lists.',\n })\n\n return (\n <>\n <Button\n size=\"small\"\n variant=\"outlined\"\n startIcon={<MdiIcon path={mdiCreation.path} />}\n onClick={() => setOpen(true)}\n >\n {'Create with AI'}\n </Button>\n <Dialog open={open} onClose={busy ? undefined : () => setOpen(false)} fullWidth maxWidth=\"sm\">\n <DialogTitle>{copy.title}</DialogTitle>\n <DialogContent>\n {started && orgId ? (\n <AiJobFollow\n job={started}\n orgId={orgId}\n user={user}\n intro={AI_CAMPAIGN_CREATE_COPY[started.kind === 'email' ? 'email' : 'campaign'].started}\n onOpenJobs={() => setOpen(false)}\n />\n ) : (\n <Stack spacing={2} sx={{ pt: 1 }}>\n {hostId ? null : (\n <TextField\n select\n size=\"small\"\n label=\"Site\"\n helperText=\"The site the campaign is placed on and sent as.\"\n value={siteId}\n onChange={(event) => setSiteId(event.target.value)}\n disabled={busy}\n >\n {sites.map((entry) => (\n <MenuItem key={entry.id} value={entry.id}>\n {entry.name || entry.id}\n </MenuItem>\n ))}\n </TextField>\n )}\n <TextField\n size=\"small\"\n label=\"Campaign name (optional)\"\n value={name}\n onChange={(event) => setName(event.target.value.slice(0, NAME_MAX_CHARS))}\n disabled={busy}\n />\n <TextField\n label=\"What is the campaign for?\"\n placeholder=\"Announce the autumn menu to our regulars, and point them at the class page to book the Tuesday bread class\"\n multiline\n minRows={4}\n value={brief}\n onChange={(event) => setBrief(event.target.value.slice(0, BRIEF_MAX_CHARS))}\n disabled={busy}\n autoFocus\n />\n <Typography variant=\"body2\" color=\"text.secondary\">\n {copy.next}{' '}\n <Link href={help.href} target=\"_blank\" rel=\"noopener\" title={help.excerpt}>\n {'How it works'}\n </Link>\n </Typography>\n {notice ? <Alert severity=\"warning\">{notice}</Alert> : null}\n </Stack>\n )}\n </DialogContent>\n <DialogActions>\n <Button onClick={() => setOpen(false)} disabled={busy}>\n {started ? 'Close' : 'Cancel'}\n </Button>\n {started ? null : (\n <Button\n variant=\"contained\"\n onClick={() => void start()}\n disabled={busy || !ready || !orgId || !site || !brief.trim()}\n >\n {copy.submit}\n </Button>\n )}\n </DialogActions>\n </Dialog>\n </>\n )\n}\nAiCreateCampaignButton.displayName = 'AiCreateCampaignButton'\n\nexport default AiCreateCampaignButton\n"],"names":["lockdownRefusalText","parseLockdownRefusal","pluginDocsHelp","checkQuota","mdiCreation","MdiIcon","authorizedFetch","useHostOrgId","useOrgPlan","useUser","Alert","Button","Dialog","DialogActions","DialogContent","DialogTitle","Link","MenuItem","Stack","TextField","Typography","useCallback","useEffect","useRef","useState","AiJobFollow","publishAiJob","AiUpsellButton","BRIEF_MAX_CHARS","NAME_MAX_CHARS","FAILED_COPY","PLAN_REFUSAL_PREFIX","AI_CAMPAIGN_CREATE_COPY","campaign","title","next","submit","started","email","aiCampaignJobKind","org","allowed","aiCampaignJobInputs","name","trimmed","replace","trim","slice","AiCreateCampaignButton","props","hostId","sites","data","user","userRef","current","open","setOpen","siteId","setSiteId","id","site","siteOrgId","undefined","orgId","ready","refusedPlan","setRefusedPlan","kind","copy","setName","brief","setBrief","busy","setBusy","notice","setNotice","setStarted","start","response","method","headers","body","JSON","stringify","inputs","payload","json","catch","ok","locked","status","error","String","startsWith","job","length","entitled","upgrade","help","anchor","excerpt","size","variant","startIcon","path","onClick","onClose","fullWidth","maxWidth","intro","onOpenJobs","spacing","sx","pt","select","label","helperText","value","onChange","event","target","disabled","map","entry","placeholder","multiline","minRows","autoFocus","color","href","rel","severity","displayName"],"mappings":"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"}
@@ -1,3 +1,4 @@
1
+ import type { ConsoleWidgetEntitlementProps } from '@aglyn/aglyn/plugin-manager/feature-plugins';
1
2
  import type { ConsoleHostAutomationsZoneProps } from './ai-automation-zones';
2
3
  import { useAiJobRun } from './use-ai-job-run';
3
4
  export declare const AI_AUTOMATION_BRIEF_COPY: {
@@ -24,8 +25,12 @@ export interface AiAutomationBriefDialogProps {
24
25
  }
25
26
  export declare function AiAutomationBriefDialog(props: AiAutomationBriefDialogProps): import("react").JSX.Element;
26
27
  /**
27
- * Renders nothing until the jobs route has answered for this workspace, and
28
- * nothing when it says the feature is not this workspace's.
28
+ * Drawn at once, from the gates the shell resolved before mounting it (the
29
+ * plan, `ai.generate`, the site's AI switch and the release flag); nothing is
30
+ * asked of a server to draw it (AGL-3601). The start door decides when the
31
+ * description is sent, and says why in the dialog if it refuses. On a plan
32
+ * that could buy the AI add-on, the shell mounts it with `entitled={false}`
33
+ * and the same button opens the add-on's dialog.
29
34
  */
30
- export declare function AiDescribeAutomationButton({ hostId, orgId, openAction }: ConsoleHostAutomationsZoneProps): import("react").JSX.Element;
35
+ export declare function AiDescribeAutomationButton({ hostId, orgId, openAction, entitled, upgrade, }: ConsoleHostAutomationsZoneProps & ConsoleWidgetEntitlementProps): import("react").JSX.Element;
31
36
  export default AiDescribeAutomationButton;
@@ -22,7 +22,8 @@ import { useUser } from "@aglyn/tenant-feature-instance";
22
22
  import { Alert, Button, CircularProgress, Dialog, DialogActions, DialogContent, DialogTitle, Link, Stack, TextField, Typography } from "@mui/material";
23
23
  import { useEffect, useState } from "react";
24
24
  import { openAiJobs } from "./ai-jobs-store.js";
25
- import { aiJobProblem, useAiJobRun, useAiJobsVerdict } from "./use-ai-job-run.js";
25
+ import { AiUpsellButton } from "./ai-upsell-dialog.component.js";
26
+ import { aiJobProblem, useAiJobRun } from "./use-ai-job-run.js";
26
27
  /**
27
28
  * "Create with AI" on the Automation page's Actions (AGL-2919), beside Add action
28
29
  * and Recipes through the `hostAutomations` zone: a description becomes a
@@ -212,13 +213,21 @@ export function AiAutomationBriefDialog(props) {
212
213
  });
213
214
  }
214
215
  /**
215
- * Renders nothing until the jobs route has answered for this workspace, and
216
- * nothing when it says the feature is not this workspace's.
217
- */ export function AiDescribeAutomationButton({ hostId, orgId, openAction }) {
216
+ * Drawn at once, from the gates the shell resolved before mounting it (the
217
+ * plan, `ai.generate`, the site's AI switch and the release flag); nothing is
218
+ * asked of a server to draw it (AGL-3601). The start door decides when the
219
+ * description is sent, and says why in the dialog if it refuses. On a plan
220
+ * that could buy the AI add-on, the shell mounts it with `entitled={false}`
221
+ * and the same button opens the add-on's dialog.
222
+ */ export function AiDescribeAutomationButton({ hostId, orgId, openAction, entitled, upgrade }) {
218
223
  const { data: user } = useUser();
219
- const verdict = useAiJobsVerdict(user, orgId);
220
224
  const [open, setOpen] = useState(false);
221
- if (verdict !== 'ready') return null;
225
+ if (entitled === false) {
226
+ return upgrade ? /*#__PURE__*/ _jsx(AiUpsellButton, {
227
+ kind: "workflow",
228
+ upgrade: upgrade
229
+ }) : null;
230
+ }
222
231
  return /*#__PURE__*/ _jsxs(_Fragment, {
223
232
  children: [
224
233
  /*#__PURE__*/ _jsx(Button, {
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../../../libs/plugins/ai/src/lib/components/ai-describe-automation.component.tsx"],"sourcesContent":["'use client'\n\n/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { pluginDocsHelp } from '@aglyn/aglyn/app-utils/docs-help'\nimport type { ConsoleHostAutomationsZoneProps } from './ai-automation-zones'\nimport { mdiCreation } from '@aglyn/shared-data-mdi'\nimport { MdiIcon } from '@aglyn/shared-ui-jsx'\nimport { useUser } from '@aglyn/tenant-feature-instance'\nimport {\n Alert,\n Button,\n CircularProgress,\n Dialog,\n DialogActions,\n DialogContent,\n DialogTitle,\n Link,\n Stack,\n TextField,\n Typography,\n} from '@mui/material'\nimport { useEffect, useState } from 'react'\nimport { openAiJobs } from './ai-jobs-store'\nimport { aiJobProblem, useAiJobRun, useAiJobsVerdict } from './use-ai-job-run'\n\n/**\n * \"Create with AI\" on the Automation page's Actions (AGL-2919), beside Add action\n * and Recipes through the `hostAutomations` zone: a description becomes a\n * `workflow` job that drafts one automation, switched off.\n *\n * The dialog follows the shared brief dialog's shape — one text box, what\n * happens next, and the action that starts the job — and then follows the\n * job, because an automation's draft needs no plan to confirm: when it is\n * written, the dialog says what to fill in and opens it in the Actions editor.\n */\n\n/** The longest description a job admits. */\nconst BRIEF_MAX_CHARS = 4_000\n\nexport const AI_AUTOMATION_BRIEF_COPY = {\n title: 'Describe an automation',\n briefLabel: 'What should happen, and when?',\n placeholder:\n 'When someone submits the newsletter form, add them to the newsletter list, make them ' +\n 'a lead and send them a welcome email',\n next:\n 'The automation is drafted switched off, using only the triggers and steps your plan ' +\n 'includes. Anything it needs that your site does not have yet is left for you to fill in.',\n submit: 'Draft the automation',\n started:\n 'The automation is being drafted. This can take a few minutes. You can close this ' +\n 'window: the draft appears in the list, switched off, when it is ready. Open AI ' +\n 'jobs to follow it meanwhile.',\n drafted: 'Drafted',\n review: 'Review it',\n notListed: 'The draft is saved. It appears in the list in a moment.',\n failed: 'The automation could not be drafted. Try again.',\n} as const\n\nexport interface AiAutomationBriefDialogProps {\n open: boolean\n onClose: () => void\n orgId: string | undefined\n hostId: string\n /** Who is signed in, whose token the requests carry. */\n user: Parameters<typeof useAiJobRun>[0]\n /** Opens a listed action in the Actions editor; `false` when the list has not read it yet. */\n openAction: (actionId: string) => boolean\n}\n\nexport function AiAutomationBriefDialog(props: AiAutomationBriefDialogProps) {\n const { open, onClose, orgId, hostId, user, openAction } = props\n const copy = AI_AUTOMATION_BRIEF_COPY\n const help = pluginDocsHelp('aiAutomations')\n const [brief, setBrief] = useState('')\n const [notListed, setNotListed] = useState(false)\n const run = useAiJobRun(user, copy.failed)\n const { job, starting, running, notice, reset } = run\n\n // Opening or closing starts over and stops following: a job still drafting\n // carries on in AI jobs, and its draft appears in the list when it is written.\n useEffect(() => {\n reset()\n setNotListed(false)\n }, [open, reset])\n\n const draft = job?.status === 'done' ? job.outputs.find((output) => output.resource === 'workflow') : undefined\n const problem = aiJobProblem(job, copy.failed) ?? (job?.status === 'done' && !draft ? copy.failed : null)\n const asking = !job || Boolean(notice)\n\n const start = async () => {\n const trimmed = brief.trim()\n if (!orgId || !trimmed) return\n setNotListed(false)\n if (await run.start({ orgId, hostId, kind: 'workflow', brief: trimmed, inputs: { mode: 'draft' } })) {\n setBrief('')\n }\n }\n\n const review = () => {\n if (!draft) return\n if (openAction(draft.id)) onClose()\n else setNotListed(true)\n }\n\n return (\n <Dialog open={open} onClose={starting ? undefined : onClose} fullWidth maxWidth=\"sm\">\n <DialogTitle>{copy.title}</DialogTitle>\n <DialogContent>\n {asking ? (\n <Stack spacing={2} sx={{ pt: 1 }}>\n <TextField\n label={copy.briefLabel}\n placeholder={copy.placeholder}\n multiline\n minRows={4}\n value={brief}\n onChange={(event) => setBrief(event.target.value.slice(0, BRIEF_MAX_CHARS))}\n helperText={`${brief.length.toLocaleString('en-US')} / ${BRIEF_MAX_CHARS.toLocaleString('en-US')}`}\n disabled={starting}\n autoFocus\n />\n <Typography variant=\"body2\" color=\"text.secondary\">\n {copy.next}{' '}\n <Link href={help.href} target=\"_blank\" rel=\"noopener\" title={help.excerpt}>\n {'How it works'}\n </Link>\n </Typography>\n {notice ? <Alert severity=\"warning\">{notice}</Alert> : null}\n </Stack>\n ) : (\n <Stack spacing={2} sx={{ pt: 1 }}>\n {running && job ? (\n <Alert\n severity=\"info\"\n icon={<CircularProgress size={18} aria-label=\"Drafting\" />}\n action={\n // Follows the job in the Assist panel (AGL-3593); the dialog\n // covers it, so it closes.\n <Button\n color=\"inherit\"\n size=\"small\"\n variant=\"outlined\"\n onClick={() => {\n openAiJobs({ jobId: job.id })\n onClose()\n }}\n >\n {'Open AI jobs'}\n </Button>\n }\n >\n {copy.started}\n </Alert>\n ) : null}\n {draft ? (\n <Alert severity=\"success\">\n <Typography variant=\"body2\" sx={{ fontWeight: 600 }}>\n {`${copy.drafted}: ${draft.label}`}\n </Typography>\n {draft.note ? <Typography variant=\"body2\">{draft.note}</Typography> : null}\n </Alert>\n ) : null}\n {problem ? <Alert severity={job?.status === 'failed' ? 'error' : 'warning'}>{problem}</Alert> : null}\n {notListed ? <Alert severity=\"info\">{copy.notListed}</Alert> : null}\n </Stack>\n )}\n </DialogContent>\n <DialogActions>\n <Button onClick={onClose} disabled={starting}>\n {asking ? 'Cancel' : 'Close'}\n </Button>\n {asking ? (\n <Button\n variant=\"contained\"\n onClick={() => void start()}\n disabled={starting || !orgId || !brief.trim()}\n >\n {copy.submit}\n </Button>\n ) : draft ? (\n <Button variant=\"contained\" onClick={review}>\n {copy.review}\n </Button>\n ) : null}\n </DialogActions>\n </Dialog>\n )\n}\n\n/**\n * Renders nothing until the jobs route has answered for this workspace, and\n * nothing when it says the feature is not this workspace's.\n */\nexport function AiDescribeAutomationButton({ hostId, orgId, openAction }: ConsoleHostAutomationsZoneProps) {\n const { data: user } = useUser()\n const verdict = useAiJobsVerdict(user, orgId)\n const [open, setOpen] = useState(false)\n\n if (verdict !== 'ready') return null\n return (\n <>\n <Button\n size=\"small\"\n variant=\"outlined\"\n startIcon={<MdiIcon path={mdiCreation.path} />}\n onClick={() => setOpen(true)}\n >\n {'Create with AI'}\n </Button>\n <AiAutomationBriefDialog\n open={open}\n onClose={() => setOpen(false)}\n orgId={orgId}\n hostId={hostId}\n user={user}\n openAction={openAction}\n />\n </>\n )\n}\n\nexport default AiDescribeAutomationButton\n"],"names":["pluginDocsHelp","mdiCreation","MdiIcon","useUser","Alert","Button","CircularProgress","Dialog","DialogActions","DialogContent","DialogTitle","Link","Stack","TextField","Typography","useEffect","useState","openAiJobs","aiJobProblem","useAiJobRun","useAiJobsVerdict","BRIEF_MAX_CHARS","AI_AUTOMATION_BRIEF_COPY","title","briefLabel","placeholder","next","submit","started","drafted","review","notListed","failed","AiAutomationBriefDialog","props","open","onClose","orgId","hostId","user","openAction","copy","help","brief","setBrief","setNotListed","run","job","starting","running","notice","reset","draft","status","outputs","find","output","resource","undefined","problem","asking","Boolean","start","trimmed","trim","kind","inputs","mode","id","fullWidth","maxWidth","spacing","sx","pt","label","multiline","minRows","value","onChange","event","target","slice","helperText","length","toLocaleString","disabled","autoFocus","variant","color","href","rel","excerpt","severity","icon","size","aria-label","action","onClick","jobId","fontWeight","note","AiDescribeAutomationButton","data","verdict","setOpen","startIcon","path"],"mappings":"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"}
1
+ {"version":3,"sources":["../../../../../../../libs/plugins/ai/src/lib/components/ai-describe-automation.component.tsx"],"sourcesContent":["'use client'\n\n/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { pluginDocsHelp } from '@aglyn/aglyn/app-utils/docs-help'\nimport type { ConsoleWidgetEntitlementProps } from '@aglyn/aglyn/plugin-manager/feature-plugins'\nimport type { ConsoleHostAutomationsZoneProps } from './ai-automation-zones'\nimport { mdiCreation } from '@aglyn/shared-data-mdi'\nimport { MdiIcon } from '@aglyn/shared-ui-jsx'\nimport { useUser } from '@aglyn/tenant-feature-instance'\nimport {\n Alert,\n Button,\n CircularProgress,\n Dialog,\n DialogActions,\n DialogContent,\n DialogTitle,\n Link,\n Stack,\n TextField,\n Typography,\n} from '@mui/material'\nimport { useEffect, useState } from 'react'\nimport { openAiJobs } from './ai-jobs-store'\nimport { AiUpsellButton } from './ai-upsell-dialog.component'\nimport { aiJobProblem, useAiJobRun } from './use-ai-job-run'\n\n/**\n * \"Create with AI\" on the Automation page's Actions (AGL-2919), beside Add action\n * and Recipes through the `hostAutomations` zone: a description becomes a\n * `workflow` job that drafts one automation, switched off.\n *\n * The dialog follows the shared brief dialog's shape — one text box, what\n * happens next, and the action that starts the job — and then follows the\n * job, because an automation's draft needs no plan to confirm: when it is\n * written, the dialog says what to fill in and opens it in the Actions editor.\n */\n\n/** The longest description a job admits. */\nconst BRIEF_MAX_CHARS = 4_000\n\nexport const AI_AUTOMATION_BRIEF_COPY = {\n title: 'Describe an automation',\n briefLabel: 'What should happen, and when?',\n placeholder:\n 'When someone submits the newsletter form, add them to the newsletter list, make them ' +\n 'a lead and send them a welcome email',\n next:\n 'The automation is drafted switched off, using only the triggers and steps your plan ' +\n 'includes. Anything it needs that your site does not have yet is left for you to fill in.',\n submit: 'Draft the automation',\n started:\n 'The automation is being drafted. This can take a few minutes. You can close this ' +\n 'window: the draft appears in the list, switched off, when it is ready. Open AI ' +\n 'jobs to follow it meanwhile.',\n drafted: 'Drafted',\n review: 'Review it',\n notListed: 'The draft is saved. It appears in the list in a moment.',\n failed: 'The automation could not be drafted. Try again.',\n} as const\n\nexport interface AiAutomationBriefDialogProps {\n open: boolean\n onClose: () => void\n orgId: string | undefined\n hostId: string\n /** Who is signed in, whose token the requests carry. */\n user: Parameters<typeof useAiJobRun>[0]\n /** Opens a listed action in the Actions editor; `false` when the list has not read it yet. */\n openAction: (actionId: string) => boolean\n}\n\nexport function AiAutomationBriefDialog(props: AiAutomationBriefDialogProps) {\n const { open, onClose, orgId, hostId, user, openAction } = props\n const copy = AI_AUTOMATION_BRIEF_COPY\n const help = pluginDocsHelp('aiAutomations')\n const [brief, setBrief] = useState('')\n const [notListed, setNotListed] = useState(false)\n const run = useAiJobRun(user, copy.failed)\n const { job, starting, running, notice, reset } = run\n\n // Opening or closing starts over and stops following: a job still drafting\n // carries on in AI jobs, and its draft appears in the list when it is written.\n useEffect(() => {\n reset()\n setNotListed(false)\n }, [open, reset])\n\n const draft = job?.status === 'done' ? job.outputs.find((output) => output.resource === 'workflow') : undefined\n const problem = aiJobProblem(job, copy.failed) ?? (job?.status === 'done' && !draft ? copy.failed : null)\n const asking = !job || Boolean(notice)\n\n const start = async () => {\n const trimmed = brief.trim()\n if (!orgId || !trimmed) return\n setNotListed(false)\n if (await run.start({ orgId, hostId, kind: 'workflow', brief: trimmed, inputs: { mode: 'draft' } })) {\n setBrief('')\n }\n }\n\n const review = () => {\n if (!draft) return\n if (openAction(draft.id)) onClose()\n else setNotListed(true)\n }\n\n return (\n <Dialog open={open} onClose={starting ? undefined : onClose} fullWidth maxWidth=\"sm\">\n <DialogTitle>{copy.title}</DialogTitle>\n <DialogContent>\n {asking ? (\n <Stack spacing={2} sx={{ pt: 1 }}>\n <TextField\n label={copy.briefLabel}\n placeholder={copy.placeholder}\n multiline\n minRows={4}\n value={brief}\n onChange={(event) => setBrief(event.target.value.slice(0, BRIEF_MAX_CHARS))}\n helperText={`${brief.length.toLocaleString('en-US')} / ${BRIEF_MAX_CHARS.toLocaleString('en-US')}`}\n disabled={starting}\n autoFocus\n />\n <Typography variant=\"body2\" color=\"text.secondary\">\n {copy.next}{' '}\n <Link href={help.href} target=\"_blank\" rel=\"noopener\" title={help.excerpt}>\n {'How it works'}\n </Link>\n </Typography>\n {notice ? <Alert severity=\"warning\">{notice}</Alert> : null}\n </Stack>\n ) : (\n <Stack spacing={2} sx={{ pt: 1 }}>\n {running && job ? (\n <Alert\n severity=\"info\"\n icon={<CircularProgress size={18} aria-label=\"Drafting\" />}\n action={\n // Follows the job in the Assist panel (AGL-3593); the dialog\n // covers it, so it closes.\n <Button\n color=\"inherit\"\n size=\"small\"\n variant=\"outlined\"\n onClick={() => {\n openAiJobs({ jobId: job.id })\n onClose()\n }}\n >\n {'Open AI jobs'}\n </Button>\n }\n >\n {copy.started}\n </Alert>\n ) : null}\n {draft ? (\n <Alert severity=\"success\">\n <Typography variant=\"body2\" sx={{ fontWeight: 600 }}>\n {`${copy.drafted}: ${draft.label}`}\n </Typography>\n {draft.note ? <Typography variant=\"body2\">{draft.note}</Typography> : null}\n </Alert>\n ) : null}\n {problem ? <Alert severity={job?.status === 'failed' ? 'error' : 'warning'}>{problem}</Alert> : null}\n {notListed ? <Alert severity=\"info\">{copy.notListed}</Alert> : null}\n </Stack>\n )}\n </DialogContent>\n <DialogActions>\n <Button onClick={onClose} disabled={starting}>\n {asking ? 'Cancel' : 'Close'}\n </Button>\n {asking ? (\n <Button\n variant=\"contained\"\n onClick={() => void start()}\n disabled={starting || !orgId || !brief.trim()}\n >\n {copy.submit}\n </Button>\n ) : draft ? (\n <Button variant=\"contained\" onClick={review}>\n {copy.review}\n </Button>\n ) : null}\n </DialogActions>\n </Dialog>\n )\n}\n\n/**\n * Drawn at once, from the gates the shell resolved before mounting it (the\n * plan, `ai.generate`, the site's AI switch and the release flag); nothing is\n * asked of a server to draw it (AGL-3601). The start door decides when the\n * description is sent, and says why in the dialog if it refuses. On a plan\n * that could buy the AI add-on, the shell mounts it with `entitled={false}`\n * and the same button opens the add-on's dialog.\n */\nexport function AiDescribeAutomationButton({\n hostId,\n orgId,\n openAction,\n entitled,\n upgrade,\n}: ConsoleHostAutomationsZoneProps & ConsoleWidgetEntitlementProps) {\n const { data: user } = useUser()\n const [open, setOpen] = useState(false)\n\n if (entitled === false) {\n return upgrade ? <AiUpsellButton kind=\"workflow\" upgrade={upgrade} /> : null\n }\n return (\n <>\n <Button\n size=\"small\"\n variant=\"outlined\"\n startIcon={<MdiIcon path={mdiCreation.path} />}\n onClick={() => setOpen(true)}\n >\n {'Create with AI'}\n </Button>\n <AiAutomationBriefDialog\n open={open}\n onClose={() => setOpen(false)}\n orgId={orgId}\n hostId={hostId}\n user={user}\n openAction={openAction}\n />\n </>\n )\n}\n\nexport default AiDescribeAutomationButton\n"],"names":["pluginDocsHelp","mdiCreation","MdiIcon","useUser","Alert","Button","CircularProgress","Dialog","DialogActions","DialogContent","DialogTitle","Link","Stack","TextField","Typography","useEffect","useState","openAiJobs","AiUpsellButton","aiJobProblem","useAiJobRun","BRIEF_MAX_CHARS","AI_AUTOMATION_BRIEF_COPY","title","briefLabel","placeholder","next","submit","started","drafted","review","notListed","failed","AiAutomationBriefDialog","props","open","onClose","orgId","hostId","user","openAction","copy","help","brief","setBrief","setNotListed","run","job","starting","running","notice","reset","draft","status","outputs","find","output","resource","undefined","problem","asking","Boolean","start","trimmed","trim","kind","inputs","mode","id","fullWidth","maxWidth","spacing","sx","pt","label","multiline","minRows","value","onChange","event","target","slice","helperText","length","toLocaleString","disabled","autoFocus","variant","color","href","rel","excerpt","severity","icon","size","aria-label","action","onClick","jobId","fontWeight","note","AiDescribeAutomationButton","entitled","upgrade","data","setOpen","startIcon","path"],"mappings":"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"}
@@ -14,20 +14,32 @@
14
14
  * See the License for the specific language governing permissions and
15
15
  * limitations under the License.
16
16
  */
17
- import type { ConsoleHostComponentsZoneProps, ConsoleHostLayoutsZoneProps, ConsoleHostScreensZoneProps, ConsoleHostTemplatesZoneProps } from '@aglyn/aglyn/plugin-manager/feature-plugins';
17
+ import type { ConsoleHostComponentsZoneProps, ConsoleHostLayoutsZoneProps, ConsoleHostScreensZoneProps, ConsoleHostTemplatesZoneProps, ConsoleWidgetEntitlementProps } from '@aglyn/aglyn/plugin-manager/feature-plugins';
18
18
  import { type AiBriefKind } from './ai-brief-dialog.component';
19
- export interface AiDescribeButtonProps extends ConsoleHostScreensZoneProps {
19
+ /**
20
+ * "Create with AI" (AGL-2907, AGL-3043, AGL-3051): a job from a brief, beside the
21
+ * create actions of the page that lists what the job makes — a page on
22
+ * Screens, a page template on Templates, a layout on Layouts, a form on Forms
23
+ * and a reusable component on Components — each mounted through that page's
24
+ * zone. The Assist panel's AI jobs opens the same dialog for a page.
25
+ */
26
+ export interface AiDescribeButtonProps extends ConsoleHostScreensZoneProps, ConsoleWidgetEntitlementProps {
20
27
  /** The job the brief starts: what the page the button sits on lists. */
21
28
  kind: AiBriefKind;
22
29
  }
23
30
  /**
24
- * Renders nothing until the jobs route has answered for this workspace: the
25
- * shell decided the plan, the member's permission and the site's AI switch
26
- * before mounting it, and the release flag is the route's to decide, so a 404
27
- * or a 403 there is this control staying absent. A lockdown is the start
28
- * door's to say, in the dialog, in its own words.
31
+ * Drawn at once, from the gates the shell already resolved client-side before
32
+ * mounting it: the plan, the member's `ai.generate`, the site's AI switch and
33
+ * the `release_ai_generative` flag (the widget's `releaseFlag`). Nothing is
34
+ * asked of a server to draw it (AGL-3601): the start door decides when the
35
+ * brief is sent, and its refusal — a plan, a permission, a lockdown — is said
36
+ * in the dialog, in its own words.
37
+ *
38
+ * On a plan that could buy the AI add-on and has not, the shell mounts it with
39
+ * `entitled={false}` and an `upgrade` link, and the same button opens the
40
+ * add-on's dialog instead of the brief, without asking anything either.
29
41
  */
30
- export declare function AiDescribeButton({ kind, hostId, orgId }: AiDescribeButtonProps): import("react").JSX.Element;
42
+ export declare function AiDescribeButton({ kind, hostId, orgId, entitled, upgrade, }: AiDescribeButtonProps): import("react").JSX.Element;
31
43
  /** A page template from a brief, on the Templates page (`hostTemplates`). */
32
44
  export declare function AiDescribeTemplateButton(props: ConsoleHostTemplatesZoneProps): import("react").JSX.Element;
33
45
  /** A layout from a brief, on the Layouts page (`hostLayouts`). */
@@ -3,48 +3,31 @@ import { _ as _extends } from "@swc/helpers/_/_extends";
3
3
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
4
4
  import { mdiCreation } from "@aglyn/shared-data-mdi";
5
5
  import { MdiIcon } from "@aglyn/shared-ui-jsx";
6
- import { authorizedFetch } from "@aglyn/shared-util-http/authorized-token";
7
6
  import { useUser } from "@aglyn/tenant-feature-instance";
8
7
  import { Button } from "@mui/material";
9
- import { useEffect, useRef, useState } from "react";
8
+ import { useState } from "react";
10
9
  import { AiBriefDialog } from "./ai-brief-dialog.component.js";
10
+ import { AiUpsellButton } from "./ai-upsell-dialog.component.js";
11
11
  /**
12
- * Renders nothing until the jobs route has answered for this workspace: the
13
- * shell decided the plan, the member's permission and the site's AI switch
14
- * before mounting it, and the release flag is the route's to decide, so a 404
15
- * or a 403 there is this control staying absent. A lockdown is the start
16
- * door's to say, in the dialog, in its own words.
17
- */ export function AiDescribeButton({ kind, hostId, orgId }) {
18
- var _ref;
12
+ * Drawn at once, from the gates the shell already resolved client-side before
13
+ * mounting it: the plan, the member's `ai.generate`, the site's AI switch and
14
+ * the `release_ai_generative` flag (the widget's `releaseFlag`). Nothing is
15
+ * asked of a server to draw it (AGL-3601): the start door decides when the
16
+ * brief is sent, and its refusal — a plan, a permission, a lockdown — is said
17
+ * in the dialog, in its own words.
18
+ *
19
+ * On a plan that could buy the AI add-on and has not, the shell mounts it with
20
+ * `entitled={false}` and an `upgrade` link, and the same button opens the
21
+ * add-on's dialog instead of the brief, without asking anything either.
22
+ */ export function AiDescribeButton({ kind, hostId, orgId, entitled, upgrade }) {
19
23
  const { data: user } = useUser();
20
- // Held in a ref so the probe keys on WHO is signed in, never on the
21
- // identity of the object that says so.
22
- const userRef = useRef(user);
23
- userRef.current = user;
24
- const uid = (_ref = user == null ? void 0 : user.uid) != null ? _ref : null;
25
- const [verdict, setVerdict] = useState('checking');
26
24
  const [open, setOpen] = useState(false);
27
- useEffect(()=>{
28
- if (!orgId || !uid) return;
29
- let active = true;
30
- void (async ()=>{
31
- try {
32
- const response = await authorizedFetch(userRef.current, `/api/ai/jobs?orgId=${encodeURIComponent(orgId)}&limit=1`);
33
- if (active) {
34
- setVerdict(response.status === 404 || response.status === 403 ? 'hidden' : 'ready');
35
- }
36
- } catch (unused) {
37
- if (active) setVerdict('hidden');
38
- }
39
- })();
40
- return ()=>{
41
- active = false;
42
- };
43
- }, [
44
- orgId,
45
- uid
46
- ]);
47
- if (verdict !== 'ready') return null;
25
+ if (entitled === false) {
26
+ return upgrade ? /*#__PURE__*/ _jsx(AiUpsellButton, {
27
+ kind: kind,
28
+ upgrade: upgrade
29
+ }) : null;
30
+ }
48
31
  return /*#__PURE__*/ _jsxs(_Fragment, {
49
32
  children: [
50
33
  /*#__PURE__*/ _jsx(Button, {
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../../../libs/plugins/ai/src/lib/components/ai-describe-button.component.tsx"],"sourcesContent":["'use client'\n\n/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport type {\n ConsoleHostComponentsZoneProps,\n ConsoleHostLayoutsZoneProps,\n ConsoleHostScreensZoneProps,\n ConsoleHostTemplatesZoneProps,\n} from '@aglyn/aglyn/plugin-manager/feature-plugins'\nimport { mdiCreation } from '@aglyn/shared-data-mdi'\nimport { MdiIcon } from '@aglyn/shared-ui-jsx'\nimport { authorizedFetch } from '@aglyn/shared-util-http/authorized-token'\nimport { useUser } from '@aglyn/tenant-feature-instance'\nimport { Button } from '@mui/material'\nimport { useEffect, useRef, useState } from 'react'\nimport { AiBriefDialog, type AiBriefKind } from './ai-brief-dialog.component'\n\n/**\n * \"Create with AI\" (AGL-2907, AGL-3043, AGL-3051): a job from a brief, beside the\n * create actions of the page that lists what the job makes — a page on\n * Screens, a page template on Templates, a layout on Layouts, a form on Forms\n * and a reusable component on Components — each mounted through that page's\n * zone. The Assist panel's AI jobs opens the same dialog for a page.\n */\n\ntype Verdict = 'checking' | 'ready' | 'hidden'\n\nexport interface AiDescribeButtonProps extends ConsoleHostScreensZoneProps {\n /** The job the brief starts: what the page the button sits on lists. */\n kind: AiBriefKind\n}\n\n/**\n * Renders nothing until the jobs route has answered for this workspace: the\n * shell decided the plan, the member's permission and the site's AI switch\n * before mounting it, and the release flag is the route's to decide, so a 404\n * or a 403 there is this control staying absent. A lockdown is the start\n * door's to say, in the dialog, in its own words.\n */\nexport function AiDescribeButton({ kind, hostId, orgId }: AiDescribeButtonProps) {\n const { data: user } = useUser()\n // Held in a ref so the probe keys on WHO is signed in, never on the\n // identity of the object that says so.\n const userRef = useRef(user)\n userRef.current = user\n const uid = user?.uid ?? null\n const [verdict, setVerdict] = useState<Verdict>('checking')\n const [open, setOpen] = useState(false)\n\n useEffect(() => {\n if (!orgId || !uid) return\n let active = true\n void (async () => {\n try {\n const response = await authorizedFetch(\n userRef.current,\n `/api/ai/jobs?orgId=${encodeURIComponent(orgId)}&limit=1`,\n )\n if (active) {\n setVerdict(response.status === 404 || response.status === 403 ? 'hidden' : 'ready')\n }\n } catch {\n if (active) setVerdict('hidden')\n }\n })()\n return () => {\n active = false\n }\n }, [orgId, uid])\n\n if (verdict !== 'ready') return null\n return (\n <>\n <Button\n size=\"small\"\n variant=\"outlined\"\n startIcon={<MdiIcon path={mdiCreation.path} />}\n onClick={() => setOpen(true)}\n >\n {'Create with AI'}\n </Button>\n <AiBriefDialog\n kind={kind}\n open={open}\n onClose={() => setOpen(false)}\n orgId={orgId}\n hostId={hostId}\n user={user}\n />\n </>\n )\n}\n\n/** A page template from a brief, on the Templates page (`hostTemplates`). */\nexport function AiDescribeTemplateButton(props: ConsoleHostTemplatesZoneProps) {\n return <AiDescribeButton {...props} kind=\"template\" />\n}\n\n/** A layout from a brief, on the Layouts page (`hostLayouts`). */\nexport function AiDescribeLayoutButton(props: ConsoleHostLayoutsZoneProps) {\n return <AiDescribeButton {...props} kind=\"layout\" />\n}\n\n/**\n * A form from a brief, on the Forms page (`hostForms`, which the forms plugin\n * hosts on the `hostScreens` contract).\n */\nexport function AiDescribeFormButton(props: ConsoleHostScreensZoneProps) {\n return <AiDescribeButton {...props} kind=\"form\" />\n}\n\n/** A reusable component from a brief, on the Components page (`hostComponents`). */\nexport function AiDescribeComponentButton(props: ConsoleHostComponentsZoneProps) {\n return <AiDescribeButton {...props} kind=\"component\" />\n}\n\nexport default AiDescribeButton\n"],"names":["mdiCreation","MdiIcon","authorizedFetch","useUser","Button","useEffect","useRef","useState","AiBriefDialog","AiDescribeButton","kind","hostId","orgId","data","user","userRef","current","uid","verdict","setVerdict","open","setOpen","active","response","encodeURIComponent","status","size","variant","startIcon","path","onClick","onClose","AiDescribeTemplateButton","props","AiDescribeLayoutButton","AiDescribeFormButton","AiDescribeComponentButton"],"mappings":"AAAA;;;AAyBA,SAASA,WAAW,QAAQ,yBAAwB;AACpD,SAASC,OAAO,QAAQ,uBAAsB;AAC9C,SAASC,eAAe,QAAQ,2CAA0C;AAC1E,SAASC,OAAO,QAAQ,iCAAgC;AACxD,SAASC,MAAM,QAAQ,gBAAe;AACtC,SAASC,SAAS,EAAEC,MAAM,EAAEC,QAAQ,QAAQ,QAAO;AACnD,SAASC,aAAa,QAA0B,iCAA6B;AAiB7E;;;;;;CAMC,GACD,OAAO,SAASC,iBAAiB,EAAEC,IAAI,EAAEC,MAAM,EAAEC,KAAK,EAAyB;;IAC7E,MAAM,EAAEC,MAAMC,IAAI,EAAE,GAAGX;IACvB,oEAAoE;IACpE,uCAAuC;IACvC,MAAMY,UAAUT,OAAOQ;IACvBC,QAAQC,OAAO,GAAGF;IAClB,MAAMG,cAAMH,wBAAAA,KAAMG,GAAG,mBAAI;IACzB,MAAM,CAACC,SAASC,WAAW,GAAGZ,SAAkB;IAChD,MAAM,CAACa,MAAMC,QAAQ,GAAGd,SAAS;IAEjCF,UAAU;QACR,IAAI,CAACO,SAAS,CAACK,KAAK;QACpB,IAAIK,SAAS;QACb,KAAK,AAAC,CAAA;YACJ,IAAI;gBACF,MAAMC,WAAW,MAAMrB,gBACrBa,QAAQC,OAAO,EACf,CAAC,mBAAmB,EAAEQ,mBAAmBZ,OAAO,QAAQ,CAAC;gBAE3D,IAAIU,QAAQ;oBACVH,WAAWI,SAASE,MAAM,KAAK,OAAOF,SAASE,MAAM,KAAK,MAAM,WAAW;gBAC7E;YACF,EAAE,eAAM;gBACN,IAAIH,QAAQH,WAAW;YACzB;QACF,CAAA;QACA,OAAO;YACLG,SAAS;QACX;IACF,GAAG;QAACV;QAAOK;KAAI;IAEf,IAAIC,YAAY,SAAS,OAAO;IAChC,qBACE;;0BACE,KAACd;gBACCsB,MAAK;gBACLC,SAAQ;gBACRC,yBAAW,KAAC3B;oBAAQ4B,MAAM7B,YAAY6B,IAAI;;gBAC1CC,SAAS,IAAMT,QAAQ;0BAEtB;;0BAEH,KAACb;gBACCE,MAAMA;gBACNU,MAAMA;gBACNW,SAAS,IAAMV,QAAQ;gBACvBT,OAAOA;gBACPD,QAAQA;gBACRG,MAAMA;;;;AAId;AAEA,2EAA2E,GAC3E,OAAO,SAASkB,yBAAyBC,KAAoC;IAC3E,qBAAO,KAACxB,+BAAqBwB;QAAOvB,MAAK;;AAC3C;AAEA,gEAAgE,GAChE,OAAO,SAASwB,uBAAuBD,KAAkC;IACvE,qBAAO,KAACxB,+BAAqBwB;QAAOvB,MAAK;;AAC3C;AAEA;;;CAGC,GACD,OAAO,SAASyB,qBAAqBF,KAAkC;IACrE,qBAAO,KAACxB,+BAAqBwB;QAAOvB,MAAK;;AAC3C;AAEA,kFAAkF,GAClF,OAAO,SAAS0B,0BAA0BH,KAAqC;IAC7E,qBAAO,KAACxB,+BAAqBwB;QAAOvB,MAAK;;AAC3C;AAEA,eAAeD,iBAAgB"}
1
+ {"version":3,"sources":["../../../../../../../libs/plugins/ai/src/lib/components/ai-describe-button.component.tsx"],"sourcesContent":["'use client'\n\n/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport type {\n ConsoleHostComponentsZoneProps,\n ConsoleHostLayoutsZoneProps,\n ConsoleHostScreensZoneProps,\n ConsoleHostTemplatesZoneProps,\n ConsoleWidgetEntitlementProps,\n} from '@aglyn/aglyn/plugin-manager/feature-plugins'\nimport { mdiCreation } from '@aglyn/shared-data-mdi'\nimport { MdiIcon } from '@aglyn/shared-ui-jsx'\nimport { useUser } from '@aglyn/tenant-feature-instance'\nimport { Button } from '@mui/material'\nimport { useState } from 'react'\nimport { AiBriefDialog, type AiBriefKind } from './ai-brief-dialog.component'\nimport { AiUpsellButton } from './ai-upsell-dialog.component'\n\n/**\n * \"Create with AI\" (AGL-2907, AGL-3043, AGL-3051): a job from a brief, beside the\n * create actions of the page that lists what the job makes — a page on\n * Screens, a page template on Templates, a layout on Layouts, a form on Forms\n * and a reusable component on Components — each mounted through that page's\n * zone. The Assist panel's AI jobs opens the same dialog for a page.\n */\n\nexport interface AiDescribeButtonProps\n extends ConsoleHostScreensZoneProps,\n ConsoleWidgetEntitlementProps {\n /** The job the brief starts: what the page the button sits on lists. */\n kind: AiBriefKind\n}\n\n/**\n * Drawn at once, from the gates the shell already resolved client-side before\n * mounting it: the plan, the member's `ai.generate`, the site's AI switch and\n * the `release_ai_generative` flag (the widget's `releaseFlag`). Nothing is\n * asked of a server to draw it (AGL-3601): the start door decides when the\n * brief is sent, and its refusal — a plan, a permission, a lockdown — is said\n * in the dialog, in its own words.\n *\n * On a plan that could buy the AI add-on and has not, the shell mounts it with\n * `entitled={false}` and an `upgrade` link, and the same button opens the\n * add-on's dialog instead of the brief, without asking anything either.\n */\nexport function AiDescribeButton({\n kind,\n hostId,\n orgId,\n entitled,\n upgrade,\n}: AiDescribeButtonProps) {\n const { data: user } = useUser()\n const [open, setOpen] = useState(false)\n\n if (entitled === false) {\n return upgrade ? <AiUpsellButton kind={kind} upgrade={upgrade} /> : null\n }\n return (\n <>\n <Button\n size=\"small\"\n variant=\"outlined\"\n startIcon={<MdiIcon path={mdiCreation.path} />}\n onClick={() => setOpen(true)}\n >\n {'Create with AI'}\n </Button>\n <AiBriefDialog\n kind={kind}\n open={open}\n onClose={() => setOpen(false)}\n orgId={orgId}\n hostId={hostId}\n user={user}\n />\n </>\n )\n}\n\n/** A page template from a brief, on the Templates page (`hostTemplates`). */\nexport function AiDescribeTemplateButton(props: ConsoleHostTemplatesZoneProps) {\n return <AiDescribeButton {...props} kind=\"template\" />\n}\n\n/** A layout from a brief, on the Layouts page (`hostLayouts`). */\nexport function AiDescribeLayoutButton(props: ConsoleHostLayoutsZoneProps) {\n return <AiDescribeButton {...props} kind=\"layout\" />\n}\n\n/**\n * A form from a brief, on the Forms page (`hostForms`, which the forms plugin\n * hosts on the `hostScreens` contract).\n */\nexport function AiDescribeFormButton(props: ConsoleHostScreensZoneProps) {\n return <AiDescribeButton {...props} kind=\"form\" />\n}\n\n/** A reusable component from a brief, on the Components page (`hostComponents`). */\nexport function AiDescribeComponentButton(props: ConsoleHostComponentsZoneProps) {\n return <AiDescribeButton {...props} kind=\"component\" />\n}\n\nexport default AiDescribeButton\n"],"names":["mdiCreation","MdiIcon","useUser","Button","useState","AiBriefDialog","AiUpsellButton","AiDescribeButton","kind","hostId","orgId","entitled","upgrade","data","user","open","setOpen","size","variant","startIcon","path","onClick","onClose","AiDescribeTemplateButton","props","AiDescribeLayoutButton","AiDescribeFormButton","AiDescribeComponentButton"],"mappings":"AAAA;;;AA0BA,SAASA,WAAW,QAAQ,yBAAwB;AACpD,SAASC,OAAO,QAAQ,uBAAsB;AAC9C,SAASC,OAAO,QAAQ,iCAAgC;AACxD,SAASC,MAAM,QAAQ,gBAAe;AACtC,SAASC,QAAQ,QAAQ,QAAO;AAChC,SAASC,aAAa,QAA0B,iCAA6B;AAC7E,SAASC,cAAc,QAAQ,kCAA8B;AAiB7D;;;;;;;;;;;CAWC,GACD,OAAO,SAASC,iBAAiB,EAC/BC,IAAI,EACJC,MAAM,EACNC,KAAK,EACLC,QAAQ,EACRC,OAAO,EACe;IACtB,MAAM,EAAEC,MAAMC,IAAI,EAAE,GAAGZ;IACvB,MAAM,CAACa,MAAMC,QAAQ,GAAGZ,SAAS;IAEjC,IAAIO,aAAa,OAAO;QACtB,OAAOC,wBAAU,KAACN;YAAeE,MAAMA;YAAMI,SAASA;aAAc;IACtE;IACA,qBACE;;0BACE,KAACT;gBACCc,MAAK;gBACLC,SAAQ;gBACRC,yBAAW,KAAClB;oBAAQmB,MAAMpB,YAAYoB,IAAI;;gBAC1CC,SAAS,IAAML,QAAQ;0BAEtB;;0BAEH,KAACX;gBACCG,MAAMA;gBACNO,MAAMA;gBACNO,SAAS,IAAMN,QAAQ;gBACvBN,OAAOA;gBACPD,QAAQA;gBACRK,MAAMA;;;;AAId;AAEA,2EAA2E,GAC3E,OAAO,SAASS,yBAAyBC,KAAoC;IAC3E,qBAAO,KAACjB,+BAAqBiB;QAAOhB,MAAK;;AAC3C;AAEA,gEAAgE,GAChE,OAAO,SAASiB,uBAAuBD,KAAkC;IACvE,qBAAO,KAACjB,+BAAqBiB;QAAOhB,MAAK;;AAC3C;AAEA;;;CAGC,GACD,OAAO,SAASkB,qBAAqBF,KAAkC;IACrE,qBAAO,KAACjB,+BAAqBiB;QAAOhB,MAAK;;AAC3C;AAEA,kFAAkF,GAClF,OAAO,SAASmB,0BAA0BH,KAAqC;IAC7E,qBAAO,KAACjB,+BAAqBiB;QAAOhB,MAAK;;AAC3C;AAEA,eAAeD,iBAAgB"}