@aglyn/plugins-ai 1.0.0-beta.230 → 1.0.0-beta.232

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 (305) hide show
  1. package/package.json +17 -17
  2. package/src/lib/activity/ai-activity-actions.js +8 -4
  3. package/src/lib/activity/ai-activity-actions.js.map +1 -1
  4. package/src/lib/components/ai-assist-provider-on-host.component.d.ts +66 -0
  5. package/src/lib/components/ai-assist-provider-on-host.component.js +78 -0
  6. package/src/lib/components/ai-assist-provider-on-host.component.js.map +1 -0
  7. package/src/lib/components/ai-assist-provider.component.js +9 -10
  8. package/src/lib/components/ai-assist-provider.component.js.map +1 -1
  9. package/src/lib/components/ai-job-follow.component.js +1 -0
  10. package/src/lib/components/ai-job-follow.component.js.map +1 -1
  11. package/src/lib/components/ai-job-links.js +13 -0
  12. package/src/lib/components/ai-job-links.js.map +1 -1
  13. package/src/lib/components/ai-job-plan.component.js +3 -1
  14. package/src/lib/components/ai-job-plan.component.js.map +1 -1
  15. package/src/lib/components/ai-jobs-list-page.component.js +1 -0
  16. package/src/lib/components/ai-jobs-list-page.component.js.map +1 -1
  17. package/src/lib/components/ai-media-create.component.d.ts +20 -7
  18. package/src/lib/components/ai-media-create.component.js +107 -55
  19. package/src/lib/components/ai-media-create.component.js.map +1 -1
  20. package/src/lib/components/ai-permissions-on-host.component.d.ts +3 -46
  21. package/src/lib/components/ai-permissions-on-host.component.js +5 -53
  22. package/src/lib/components/ai-permissions-on-host.component.js.map +1 -1
  23. package/src/lib/components/ai-seo-fields-card.component.js +1 -0
  24. package/src/lib/components/ai-seo-fields-card.component.js.map +1 -1
  25. package/src/lib/components/ai-site-build-page.component.js +20 -8
  26. package/src/lib/components/ai-site-build-page.component.js.map +1 -1
  27. package/src/lib/components/ai-site-memory-card.component.d.ts +32 -0
  28. package/src/lib/components/ai-site-memory-card.component.js +187 -0
  29. package/src/lib/components/ai-site-memory-card.component.js.map +1 -0
  30. package/src/lib/components/ai-site-start-card.component.js +80 -77
  31. package/src/lib/components/ai-site-start-card.component.js.map +1 -1
  32. package/src/lib/components/ai-theme-proposal-card.component.js +4 -0
  33. package/src/lib/components/ai-theme-proposal-card.component.js.map +1 -1
  34. package/src/lib/components/ai-usage-strip.component.js +1 -0
  35. package/src/lib/components/ai-usage-strip.component.js.map +1 -1
  36. package/src/lib/components/assist-panel.component.d.ts +10 -0
  37. package/src/lib/components/assist-panel.component.js +119 -9
  38. package/src/lib/components/assist-panel.component.js.map +1 -1
  39. package/src/lib/components/assist-signals-page.component.js +2 -0
  40. package/src/lib/components/assist-signals-page.component.js.map +1 -1
  41. package/src/lib/components/billing-ai-allotments.component.js +3 -0
  42. package/src/lib/components/billing-ai-allotments.component.js.map +1 -1
  43. package/src/lib/components/billing-ai-top-users.component.js +1 -0
  44. package/src/lib/components/billing-ai-top-users.component.js.map +1 -1
  45. package/src/lib/components/billing-assist-overage-card.component.js +2 -0
  46. package/src/lib/components/billing-assist-overage-card.component.js.map +1 -1
  47. package/src/lib/components/member-ai-usage-card.component.js +10 -0
  48. package/src/lib/components/member-ai-usage-card.component.js.map +1 -1
  49. package/src/lib/components/staff-org-ai-card.component.js +1 -0
  50. package/src/lib/components/staff-org-ai-card.component.js.map +1 -1
  51. package/src/lib/components/staff-org-ai-conversations.component.d.ts +23 -0
  52. package/src/lib/components/staff-org-ai-conversations.component.js +346 -0
  53. package/src/lib/components/staff-org-ai-conversations.component.js.map +1 -0
  54. package/src/lib/jobs/ai-build-capabilities.d.ts +13 -1
  55. package/src/lib/jobs/ai-build-capabilities.js +101 -7
  56. package/src/lib/jobs/ai-build-capabilities.js.map +1 -1
  57. package/src/lib/jobs/ai-build-unit-outcome.js +4 -2
  58. package/src/lib/jobs/ai-build-unit-outcome.js.map +1 -1
  59. package/src/lib/jobs/ai-business-profile-prefill.d.ts +29 -0
  60. package/src/lib/jobs/ai-business-profile-prefill.js +85 -0
  61. package/src/lib/jobs/ai-business-profile-prefill.js.map +1 -0
  62. package/src/lib/jobs/ai-job-auto-confirm.d.ts +8 -0
  63. package/src/lib/jobs/ai-job-auto-confirm.js +30 -6
  64. package/src/lib/jobs/ai-job-auto-confirm.js.map +1 -1
  65. package/src/lib/jobs/ai-job-build-step.js +14 -1
  66. package/src/lib/jobs/ai-job-build-step.js.map +1 -1
  67. package/src/lib/jobs/ai-job-edit-step.d.ts +225 -0
  68. package/src/lib/jobs/ai-job-edit-step.js +631 -0
  69. package/src/lib/jobs/ai-job-edit-step.js.map +1 -0
  70. package/src/lib/jobs/ai-job-generation.d.ts +8 -0
  71. package/src/lib/jobs/ai-job-generation.js +13 -2
  72. package/src/lib/jobs/ai-job-generation.js.map +1 -1
  73. package/src/lib/jobs/ai-job-insight-step.js +29 -5
  74. package/src/lib/jobs/ai-job-insight-step.js.map +1 -1
  75. package/src/lib/jobs/ai-job-layout-language.d.ts +78 -0
  76. package/src/lib/jobs/ai-job-layout-language.js +200 -0
  77. package/src/lib/jobs/ai-job-layout-language.js.map +1 -0
  78. package/src/lib/jobs/ai-job-layout-site-pages.d.ts +13 -2
  79. package/src/lib/jobs/ai-job-layout-site-pages.js +18 -2
  80. package/src/lib/jobs/ai-job-layout-site-pages.js.map +1 -1
  81. package/src/lib/jobs/ai-job-layout-step.d.ts +5 -0
  82. package/src/lib/jobs/ai-job-layout-step.js +107 -6
  83. package/src/lib/jobs/ai-job-layout-step.js.map +1 -1
  84. package/src/lib/jobs/ai-job-logic-step.d.ts +20 -0
  85. package/src/lib/jobs/ai-job-logic-step.js +87 -6
  86. package/src/lib/jobs/ai-job-logic-step.js.map +1 -1
  87. package/src/lib/jobs/ai-job-page-language.d.ts +194 -0
  88. package/src/lib/jobs/ai-job-page-language.js +418 -0
  89. package/src/lib/jobs/ai-job-page-language.js.map +1 -0
  90. package/src/lib/jobs/ai-job-page-sections.d.ts +37 -1
  91. package/src/lib/jobs/ai-job-page-sections.js +93 -11
  92. package/src/lib/jobs/ai-job-page-sections.js.map +1 -1
  93. package/src/lib/jobs/ai-job-page-step.d.ts +4 -4
  94. package/src/lib/jobs/ai-job-page-step.js +115 -14
  95. package/src/lib/jobs/ai-job-page-step.js.map +1 -1
  96. package/src/lib/jobs/ai-job-plan-step.d.ts +20 -6
  97. package/src/lib/jobs/ai-job-plan-step.js +62 -22
  98. package/src/lib/jobs/ai-job-plan-step.js.map +1 -1
  99. package/src/lib/jobs/ai-job-site-content.d.ts +163 -0
  100. package/src/lib/jobs/ai-job-site-content.js +443 -0
  101. package/src/lib/jobs/ai-job-site-content.js.map +1 -0
  102. package/src/lib/jobs/ai-job-site-look.d.ts +112 -0
  103. package/src/lib/jobs/ai-job-site-look.js +322 -0
  104. package/src/lib/jobs/ai-job-site-look.js.map +1 -0
  105. package/src/lib/jobs/ai-job-site-step.d.ts +30 -5
  106. package/src/lib/jobs/ai-job-site-step.js +183 -27
  107. package/src/lib/jobs/ai-job-site-step.js.map +1 -1
  108. package/src/lib/jobs/ai-job-workflow-step.js +2 -2
  109. package/src/lib/jobs/ai-job-workflow-step.js.map +1 -1
  110. package/src/lib/jobs/ai-jobs-notify.d.ts +6 -1
  111. package/src/lib/jobs/ai-jobs-notify.js +15 -3
  112. package/src/lib/jobs/ai-jobs-notify.js.map +1 -1
  113. package/src/lib/jobs/ai-jobs.d.ts +1 -1
  114. package/src/lib/jobs/ai-jobs.js +17 -8
  115. package/src/lib/jobs/ai-jobs.js.map +1 -1
  116. package/src/lib/jobs/ai-layout-full-height.d.ts +40 -0
  117. package/src/lib/jobs/ai-layout-full-height.js +82 -0
  118. package/src/lib/jobs/ai-layout-full-height.js.map +1 -0
  119. package/src/lib/jobs/ai-layout-site-facts.d.ts +54 -0
  120. package/src/lib/jobs/ai-layout-site-facts.js +153 -0
  121. package/src/lib/jobs/ai-layout-site-facts.js.map +1 -0
  122. package/src/lib/layout-language/ai-layout-compiler.d.ts +154 -0
  123. package/src/lib/layout-language/ai-layout-compiler.js +1235 -0
  124. package/src/lib/layout-language/ai-layout-compiler.js.map +1 -0
  125. package/src/lib/layout-language/ai-layout-copy.d.ts +73 -0
  126. package/src/lib/layout-language/ai-layout-copy.js +137 -0
  127. package/src/lib/layout-language/ai-layout-copy.js.map +1 -0
  128. package/src/lib/layout-language/ai-layout-frame.d.ts +52 -0
  129. package/src/lib/layout-language/ai-layout-frame.js +458 -0
  130. package/src/lib/layout-language/ai-layout-frame.js.map +1 -0
  131. package/src/lib/layout-language/ai-layout-gaps.d.ts +63 -0
  132. package/src/lib/layout-language/ai-layout-gaps.js +345 -0
  133. package/src/lib/layout-language/ai-layout-gaps.js.map +1 -0
  134. package/src/lib/layout-language/ai-layout-language.d.ts +168 -0
  135. package/src/lib/layout-language/ai-layout-language.js +529 -0
  136. package/src/lib/layout-language/ai-layout-language.js.map +1 -0
  137. package/src/lib/layout-language/ai-layout-links.d.ts +80 -0
  138. package/src/lib/layout-language/ai-layout-links.js +109 -0
  139. package/src/lib/layout-language/ai-layout-links.js.map +1 -0
  140. package/src/lib/layout-language/ai-layout-pictures.d.ts +144 -0
  141. package/src/lib/layout-language/ai-layout-pictures.js +214 -0
  142. package/src/lib/layout-language/ai-layout-pictures.js.map +1 -0
  143. package/src/lib/layout-language/ai-layout-store.d.ts +41 -0
  144. package/src/lib/layout-language/ai-layout-store.js +75 -0
  145. package/src/lib/layout-language/ai-layout-store.js.map +1 -0
  146. package/src/lib/layout-language/ai-layout-tree.d.ts +59 -0
  147. package/src/lib/layout-language/ai-layout-tree.js +84 -0
  148. package/src/lib/layout-language/ai-layout-tree.js.map +1 -0
  149. package/src/lib/lazy-widget.d.ts +45 -0
  150. package/src/lib/lazy-widget.js +53 -0
  151. package/src/lib/lazy-widget.js.map +1 -0
  152. package/src/lib/model/ai-build-job.js +2 -1
  153. package/src/lib/model/ai-build-job.js.map +1 -1
  154. package/src/lib/model/ai-build-progress.d.ts +20 -3
  155. package/src/lib/model/ai-build-progress.js +52 -7
  156. package/src/lib/model/ai-build-progress.js.map +1 -1
  157. package/src/lib/model/ai-edit-job.d.ts +109 -0
  158. package/src/lib/model/ai-edit-job.js +157 -0
  159. package/src/lib/model/ai-edit-job.js.map +1 -0
  160. package/src/lib/model/ai-host-publish-context.d.ts +51 -0
  161. package/src/lib/model/ai-host-publish-context.js +104 -0
  162. package/src/lib/model/ai-host-publish-context.js.map +1 -0
  163. package/src/lib/model/ai-job-activity.d.ts +22 -0
  164. package/src/lib/model/ai-job-activity.js +23 -1
  165. package/src/lib/model/ai-job-activity.js.map +1 -1
  166. package/src/lib/model/ai-job-failure-copy.d.ts +38 -1
  167. package/src/lib/model/ai-job-failure-copy.js +56 -1
  168. package/src/lib/model/ai-job-failure-copy.js.map +1 -1
  169. package/src/lib/model/ai-job-notice.d.ts +3 -1
  170. package/src/lib/model/ai-job-notice.js +31 -9
  171. package/src/lib/model/ai-job-notice.js.map +1 -1
  172. package/src/lib/model/ai-jobs.types.d.ts +22 -1
  173. package/src/lib/model/ai-jobs.types.js.map +1 -1
  174. package/src/lib/model/ai-logic-job.d.ts +18 -1
  175. package/src/lib/model/ai-logic-job.js +24 -3
  176. package/src/lib/model/ai-logic-job.js.map +1 -1
  177. package/src/lib/model/ai-media-credits.d.ts +8 -4
  178. package/src/lib/model/ai-media-credits.js +11 -4
  179. package/src/lib/model/ai-media-credits.js.map +1 -1
  180. package/src/lib/model/ai-media-kinds.d.ts +68 -0
  181. package/src/lib/model/ai-media-kinds.js +98 -0
  182. package/src/lib/model/ai-media-kinds.js.map +1 -0
  183. package/src/lib/model/ai-site-build-progress.d.ts +9 -1
  184. package/src/lib/model/ai-site-build-progress.js +54 -14
  185. package/src/lib/model/ai-site-build-progress.js.map +1 -1
  186. package/src/lib/model/ai-site-context.d.ts +111 -0
  187. package/src/lib/model/ai-site-context.js +222 -0
  188. package/src/lib/model/ai-site-context.js.map +1 -0
  189. package/src/lib/model/ai-site-job.d.ts +18 -2
  190. package/src/lib/model/ai-site-job.js +21 -5
  191. package/src/lib/model/ai-site-job.js.map +1 -1
  192. package/src/lib/model/ai-site-kinds.d.ts +164 -0
  193. package/src/lib/model/ai-site-kinds.js +1942 -0
  194. package/src/lib/model/ai-site-kinds.js.map +1 -0
  195. package/src/lib/model/ai-site-look.d.ts +150 -0
  196. package/src/lib/model/ai-site-look.js +1236 -0
  197. package/src/lib/model/ai-site-look.js.map +1 -0
  198. package/src/lib/model/ai-site-memory.d.ts +80 -0
  199. package/src/lib/model/ai-site-memory.js +171 -0
  200. package/src/lib/model/ai-site-memory.js.map +1 -0
  201. package/src/lib/model/ai-site-start-seo.d.ts +1 -1
  202. package/src/lib/model/ai-site-start.d.ts +15 -3
  203. package/src/lib/model/ai-site-start.js +21 -4
  204. package/src/lib/model/ai-site-start.js.map +1 -1
  205. package/src/lib/model/assist-follow-up.d.ts +92 -0
  206. package/src/lib/model/assist-follow-up.js +128 -0
  207. package/src/lib/model/assist-follow-up.js.map +1 -0
  208. package/src/lib/plugin-config.js +2 -0
  209. package/src/lib/plugin-config.js.map +1 -1
  210. package/src/lib/plugin.js +99 -48
  211. package/src/lib/plugin.js.map +1 -1
  212. package/src/lib/providers/anthropic.d.ts +9 -1
  213. package/src/lib/providers/anthropic.js +143 -9
  214. package/src/lib/providers/anthropic.js.map +1 -1
  215. package/src/lib/providers/catalog.d.ts +38 -8
  216. package/src/lib/providers/catalog.js +106 -14
  217. package/src/lib/providers/catalog.js.map +1 -1
  218. package/src/lib/providers/contract.d.ts +29 -0
  219. package/src/lib/providers/contract.js.map +1 -1
  220. package/src/lib/providers/image-contract.d.ts +22 -1
  221. package/src/lib/providers/image-contract.js +40 -1
  222. package/src/lib/providers/image-contract.js.map +1 -1
  223. package/src/lib/providers/image-endpoints.d.ts +24 -0
  224. package/src/lib/providers/image-endpoints.js +28 -0
  225. package/src/lib/providers/image-endpoints.js.map +1 -0
  226. package/src/lib/providers/model-choice.js +23 -2
  227. package/src/lib/providers/model-choice.js.map +1 -1
  228. package/src/lib/providers/routing.js +18 -0
  229. package/src/lib/providers/routing.js.map +1 -1
  230. package/src/lib/providers/vertex-image-endpoint.d.ts +48 -0
  231. package/src/lib/providers/vertex-image-endpoint.js +80 -0
  232. package/src/lib/providers/vertex-image-endpoint.js.map +1 -0
  233. package/src/lib/providers/vertex-image.d.ts +13 -27
  234. package/src/lib/providers/vertex-image.js +15 -42
  235. package/src/lib/providers/vertex-image.js.map +1 -1
  236. package/src/lib/runtime/ai-blog-post-generation.d.ts +62 -0
  237. package/src/lib/runtime/ai-blog-post-generation.js +89 -0
  238. package/src/lib/runtime/ai-blog-post-generation.js.map +1 -0
  239. package/src/lib/runtime/ai-dev-env.d.ts +53 -0
  240. package/src/lib/runtime/ai-dev-env.js +72 -0
  241. package/src/lib/runtime/ai-dev-env.js.map +1 -0
  242. package/src/lib/runtime/ai-dev-replay.d.ts +116 -0
  243. package/src/lib/runtime/ai-dev-replay.js +313 -0
  244. package/src/lib/runtime/ai-dev-replay.js.map +1 -0
  245. package/src/lib/runtime/ai-doctrine-validators.d.ts +82 -0
  246. package/src/lib/runtime/ai-doctrine-validators.js +436 -4
  247. package/src/lib/runtime/ai-doctrine-validators.js.map +1 -1
  248. package/src/lib/runtime/ai-doctrine.js +16 -3
  249. package/src/lib/runtime/ai-doctrine.js.map +1 -1
  250. package/src/lib/runtime/ai-eval-live.js +4 -0
  251. package/src/lib/runtime/ai-eval-live.js.map +1 -1
  252. package/src/lib/runtime/ai-eval.d.ts +13 -1
  253. package/src/lib/runtime/ai-eval.js +84 -1
  254. package/src/lib/runtime/ai-eval.js.map +1 -1
  255. package/src/lib/runtime/ai-icon-library.d.ts +257 -0
  256. package/src/lib/runtime/ai-icon-library.js +254 -0
  257. package/src/lib/runtime/ai-icon-library.js.map +1 -0
  258. package/src/lib/runtime/ai-live-batch.d.ts +45 -0
  259. package/src/lib/runtime/ai-live-batch.js +89 -0
  260. package/src/lib/runtime/ai-live-batch.js.map +1 -0
  261. package/src/lib/runtime/ai-node-tree.d.ts +9 -0
  262. package/src/lib/runtime/ai-node-tree.js +30 -4
  263. package/src/lib/runtime/ai-node-tree.js.map +1 -1
  264. package/src/lib/runtime/ai-palette.d.ts +6 -0
  265. package/src/lib/runtime/ai-palette.generated.js +70 -0
  266. package/src/lib/runtime/ai-palette.generated.js.map +1 -1
  267. package/src/lib/runtime/ai-palette.js.map +1 -1
  268. package/src/lib/runtime/ai-runtime.js +46 -2
  269. package/src/lib/runtime/ai-runtime.js.map +1 -1
  270. package/src/lib/runtime/site-context.d.ts +58 -0
  271. package/src/lib/runtime/site-context.js +127 -0
  272. package/src/lib/runtime/site-context.js.map +1 -0
  273. package/src/lib/server/ai-admin-conversations.d.ts +22 -0
  274. package/src/lib/server/ai-admin-conversations.js +197 -0
  275. package/src/lib/server/ai-admin-conversations.js.map +1 -0
  276. package/src/lib/server/ai-media-image.d.ts +5 -5
  277. package/src/lib/server/ai-media-image.js +25 -11
  278. package/src/lib/server/ai-media-image.js.map +1 -1
  279. package/src/lib/server/ai-media-raster-prompt.d.ts +34 -0
  280. package/src/lib/server/ai-media-raster-prompt.js +53 -0
  281. package/src/lib/server/ai-media-raster-prompt.js.map +1 -0
  282. package/src/lib/server/assist-chat.d.ts +11 -0
  283. package/src/lib/server/assist-chat.js +57 -18
  284. package/src/lib/server/assist-chat.js.map +1 -1
  285. package/src/lib/server/assist-edit-applied.js +16 -3
  286. package/src/lib/server/assist-edit-applied.js.map +1 -1
  287. package/src/lib/server/assist-view-context.d.ts +19 -1
  288. package/src/lib/server/assist-view-context.js +38 -1
  289. package/src/lib/server/assist-view-context.js.map +1 -1
  290. package/src/lib/server.js +10 -0
  291. package/src/lib/server.js.map +1 -1
  292. package/src/lib/subprocessors.js +17 -1
  293. package/src/lib/subprocessors.js.map +1 -1
  294. package/src/lib/tools/ai-blog-post-tool.d.ts +60 -0
  295. package/src/lib/tools/ai-blog-post-tool.js +175 -0
  296. package/src/lib/tools/ai-blog-post-tool.js.map +1 -0
  297. package/src/lib/tools/ai-workflow-tool.d.ts +6 -2
  298. package/src/lib/tools/ai-workflow-tool.js +16 -14
  299. package/src/lib/tools/ai-workflow-tool.js.map +1 -1
  300. package/src/lib/usage/assist-usage.d.ts +3 -0
  301. package/src/lib/usage/assist-usage.js +4 -2
  302. package/src/lib/usage/assist-usage.js.map +1 -1
  303. package/src/lib/usage/staff-org-ai-conversations.d.ts +103 -0
  304. package/src/lib/usage/staff-org-ai-conversations.js +152 -0
  305. package/src/lib/usage/staff-org-ai-conversations.js.map +1 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aglyn/plugins-ai",
3
- "version": "1.0.0-beta.230",
3
+ "version": "1.0.0-beta.232",
4
4
  "license": "Apache-2.0",
5
5
  "homepage": "https://aglyn.com",
6
6
  "repository": {
@@ -25,22 +25,22 @@
25
25
  "./package.json": "./package.json"
26
26
  },
27
27
  "dependencies": {
28
- "@aglyn/aglyn": "1.0.0-beta.230",
29
- "@aglyn/shared-data-enums": "1.0.0-beta.230",
30
- "@aglyn/shared-data-mdi": "1.0.0-beta.230",
31
- "@aglyn/shared-data-types": "1.0.0-beta.230",
32
- "@aglyn/shared-ui-email-campaigns": "1.0.0-beta.230",
33
- "@aglyn/shared-ui-jsx": "1.0.0-beta.230",
34
- "@aglyn/shared-ui-snackstack": "1.0.0-beta.230",
35
- "@aglyn/shared-ui-theme": "1.0.0-beta.230",
36
- "@aglyn/shared-util-email": "1.0.0-beta.230",
37
- "@aglyn/shared-util-errors": "1.0.0-beta.230",
38
- "@aglyn/shared-util-http": "1.0.0-beta.230",
39
- "@aglyn/shared-util-timestamp": "1.0.0-beta.230",
40
- "@aglyn/shared-util-tools": "1.0.0-beta.230",
41
- "@aglyn/tenant-data-admin": "1.0.0-beta.230",
42
- "@aglyn/tenant-feature-instance": "1.0.0-beta.230",
43
- "@aglyn/tenant-runtime": "1.0.0-beta.230",
28
+ "@aglyn/aglyn": "1.0.0-beta.232",
29
+ "@aglyn/shared-data-enums": "1.0.0-beta.232",
30
+ "@aglyn/shared-data-mdi": "1.0.0-beta.232",
31
+ "@aglyn/shared-data-types": "1.0.0-beta.232",
32
+ "@aglyn/shared-ui-email-campaigns": "1.0.0-beta.232",
33
+ "@aglyn/shared-ui-jsx": "1.0.0-beta.232",
34
+ "@aglyn/shared-ui-snackstack": "1.0.0-beta.232",
35
+ "@aglyn/shared-ui-theme": "1.0.0-beta.232",
36
+ "@aglyn/shared-util-email": "1.0.0-beta.232",
37
+ "@aglyn/shared-util-errors": "1.0.0-beta.232",
38
+ "@aglyn/shared-util-http": "1.0.0-beta.232",
39
+ "@aglyn/shared-util-timestamp": "1.0.0-beta.232",
40
+ "@aglyn/shared-util-tools": "1.0.0-beta.232",
41
+ "@aglyn/tenant-data-admin": "1.0.0-beta.232",
42
+ "@aglyn/tenant-feature-instance": "1.0.0-beta.232",
43
+ "@aglyn/tenant-runtime": "1.0.0-beta.232",
44
44
  "@swc/helpers": "0.5.23"
45
45
  },
46
46
  "peerDependencies": {
@@ -110,7 +110,9 @@ export const AI_JOB_NEEDS_INPUT_REASON_LABELS = {
110
110
  // A logic proposal (AGL-3603) writes nothing either.
111
111
  logic: 'content',
112
112
  // So does an org automation's (AGL-3603): the editor's Save is the write.
113
- orgAutomation: 'content'
113
+ orgAutomation: 'content',
114
+ // A blog post a guided start wrote (AGL-3676) is the site's content.
115
+ entry: 'content'
114
116
  };
115
117
  export function aiOutputTargetType(resource) {
116
118
  return AI_OUTPUT_TARGET_TYPES[resource];
@@ -186,11 +188,13 @@ export function aiOutputTargetType(resource) {
186
188
  label: AI_ACTIVITY_FILTER_LABEL,
187
189
  staffAuditPrefixes: AI_STAFF_AUDIT_ACTION_PREFIXES.filter((prefix)=>prefix !== 'ai.'),
188
190
  // The staff cards opening on an org (AGL-2930) and on one account
189
- // (AGL-2928). Neither writes these any more; the rows already in the
190
- // log still classify as reads rather than changes.
191
+ // (AGL-2928), which no longer write these, so the rows already in the
192
+ // log still classify as reads; and a staff member reading what an org
193
+ // asked Aglyn AI (AGL-3675), which writes one per page.
191
194
  staffAuditAccessActions: [
192
195
  'org.ai-viewed',
193
- 'user.ai-usage-viewed'
196
+ 'user.ai-usage-viewed',
197
+ 'org.ai-conversations-viewed'
194
198
  ]
195
199
  },
196
200
  actions: AI_ACTIVITY_ACTION_LIST.map((key)=>({
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../../../libs/plugins/ai/src/lib/activity/ai-activity-actions.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 * The AI actions an activity log can carry (AGL-2929).\n *\n * Every other action in `orgs/{orgId}/activity` and `hosts/{hostId}/activity`\n * is a prose sentence written at the call site — \"Saved the screen\". The AI\n * rows are CODES instead, because they are read by more than a person: the\n * org feed's \"AI\" chip, the staff audit facet and the actor table all need\n * to recognize an AI row without parsing a sentence, and a sentence that\n * three writers phrase three ways is three rows that look unrelated.\n *\n * One list, so the writers in `ai-activity.ts`, the feed presenter and the\n * staff facet cannot disagree about what counts as AI. A code missing from\n * `AI_ACTIVITY_ACTION_LABELS` fails the type, not the reader.\n */\n\nimport type { AiJobOutputResource } from '../model/ai-jobs.types'\nimport {\n pluginStaffAuditActionGroup,\n pluginStaffAuditActionGroupLabel,\n registerPluginActivityActions,\n type PluginActivityScope,\n} from '@aglyn/aglyn/plugin-manager/plugin-activity-actions'\n\n/** The action code each AI writer stores. */\nexport const AI_ACTIVITY_ACTIONS = {\n jobCreated: 'ai.job.created',\n jobOutput: 'ai.job.output',\n jobCanceled: 'ai.job.canceled',\n jobNeedsInput: 'ai.job.needs_input',\n editApplied: 'ai.edit.applied',\n seoApplied: 'ai.seo.applied',\n assistSection: 'ai.assist.section',\n overageHardCap: 'ai.overage.hardCap',\n overageCap: 'ai.overage.cap',\n allotmentChanged: 'ai.allotment.changed',\n permissionChanged: 'ai.permission.changed',\n addonPurchased: 'ai.addon.purchased',\n addonRemoved: 'ai.addon.removed',\n} as const\n\nexport type AiActivityAction =\n (typeof AI_ACTIVITY_ACTIONS)[keyof typeof AI_ACTIVITY_ACTIONS]\n\n/** What a person reads for each code, in the feed and the actor table. */\nexport const AI_ACTIVITY_ACTION_LABELS: Record<AiActivityAction, string> = {\n 'ai.job.created': 'Started an AI generation',\n 'ai.job.output': 'AI generated',\n 'ai.job.canceled': 'Canceled an AI generation',\n 'ai.job.needs_input': 'AI generation paused for input',\n 'ai.edit.applied': 'Applied AI edits',\n 'ai.seo.applied': 'Applied AI SEO fixes as drafts',\n 'ai.assist.section': 'AI generated a section',\n 'ai.overage.hardCap': 'AI stop-at-band switch',\n 'ai.overage.cap': 'AI overage ceiling',\n 'ai.allotment.changed': 'AI allotment changed',\n 'ai.permission.changed': 'AI permission changed',\n 'ai.addon.purchased': 'Added the AI add-on',\n 'ai.addon.removed': 'Removed the AI add-on',\n}\n\n/** Every code, in catalog order — what a filter sends as `isAnyOf`. */\nexport const AI_ACTIVITY_ACTION_LIST: readonly AiActivityAction[] =\n Object.values(AI_ACTIVITY_ACTIONS)\n\n/** The feed's filter chip and the staff facet's group, by one name. */\nexport const AI_ACTIVITY_FILTER_LABEL = 'AI'\n\n/**\n * Why a generation stopped and asked for a person (AGL-2904): the plan's\n * band ran out, the org's own ceiling refused, the monthly message cap or\n * the job's own token budget did — or, on the Free taste (AGL-2925), one of\n * its own precautions: the account's credits, its daily request cap, a\n * pause after declined briefs, or the platform's day of free spend. Those\n * are the meter's `AssistRefusedBy` less its `null`, so a ceiling the meter\n * can name is one the feed can label. The last three are the job's own: its\n * plan is ready for review, or an answer broke a building rule on its re-ask\n * (AGL-2935), or the site is at an allowance its plan sets for what the job\n * writes (AGL-2909).\n */\nexport type AiJobNeedsInputReason =\n | 'band'\n | 'cap'\n | 'messages'\n | 'budget'\n | 'allotment'\n | 'account'\n | 'requests'\n | 'refusals'\n | 'platform'\n | 'plan'\n | 'doctrine'\n | 'limit'\n\nexport const AI_JOB_NEEDS_INPUT_REASON_LABELS: Record<\n AiJobNeedsInputReason,\n string\n> = {\n plan: 'its plan is ready for review',\n doctrine: 'its answer broke a building rule twice',\n limit: 'the site reached an allowance of its plan',\n band: 'the included AI band is used up',\n cap: 'the overage ceiling was reached',\n messages: 'the monthly message cap was reached',\n budget: 'the job budget was reached',\n allotment: 'the creator’s or the site’s AI allotment is used up',\n account: 'the account’s free AI credits are used up',\n requests: 'the daily free request cap was reached',\n refusals: 'free generation is paused for the day after declined briefs',\n platform: 'free AI generation is paused for the day',\n}\n\n/**\n * The feed target types a generation job's output can be filed under: the\n * kinds both activity logs know, so the org row and its host copy share a\n * shape.\n */\nexport type AiOutputTargetType =\n | 'screen'\n | 'layout'\n | 'component'\n | 'template'\n | 'workflow'\n | 'content'\n | 'theme'\n\n/**\n * Where the feed files each resource kind a job can write (AGL-2904).\n *\n * A job names its output by the resource it wrote, and the activity logs\n * know a narrower set of targets. The map is total, so a resource kind\n * added to the job document must say where the feed shows it before the\n * machine can log it. `reusableComponent` is the feed's `component`; a\n * `text` output is copy, which the feed files as `content`; a `theme`\n * proposal is filed under the site's theme, which the host feed links to the\n * Theme section (AGL-2938); the kinds whose runners have not shipped are\n * content of the site too, and are filed there until a target of their own\n * exists.\n */\nconst AI_OUTPUT_TARGET_TYPES: Record<AiJobOutputResource, AiOutputTargetType> = {\n screen: 'screen',\n reusableComponent: 'component',\n layout: 'layout',\n template: 'template',\n form: 'content',\n emailScreen: 'content',\n campaign: 'content',\n product: 'content',\n experiment: 'content',\n workflow: 'workflow',\n // An SEO proposal (AGL-2910) is about the site's content, and is filed there.\n seo: 'content',\n text: 'content',\n theme: 'theme',\n // An insight answer (AGL-2915) is about the site's figures; the feed row\n // names it and never what it says.\n insight: 'content',\n // A CRM proposal (AGL-2917) writes nothing; the feed files it with content.\n crm: 'content',\n // Another plugin's draft a build asked its writer for (AGL-3616).\n draft: 'content',\n // A logic proposal (AGL-3603) writes nothing either.\n logic: 'content',\n // So does an org automation's (AGL-3603): the editor's Save is the write.\n orgAutomation: 'content',\n}\n\nexport function aiOutputTargetType(resource: AiJobOutputResource): AiOutputTargetType {\n return AI_OUTPUT_TARGET_TYPES[resource]\n}\n\n/** Whether a stored action is one of the AI codes above. */\nexport function isAiActivityAction(action: unknown): action is AiActivityAction {\n return (\n typeof action === 'string' &&\n (AI_ACTIVITY_ACTION_LIST as readonly string[]).includes(action)\n )\n}\n\n/** The readable label for an AI code; `undefined` for any other action. */\nexport function aiActivityActionLabel(action: unknown): string | undefined {\n return isAiActivityAction(action)\n ? AI_ACTIVITY_ACTION_LABELS[action]\n : undefined\n}\n\n/**\n * Staff audit rows that are ABOUT AI without carrying an `ai.` code: the\n * customer's overage controls already write `billing.assistOverage.*`, and\n * the platform's free-spend auto-pause writes `platform.aiFreeSpend.*`\n * (AGL-2925). The audit page's facet folds them under the same group as the\n * codes, because \"what did we do about AI this week\" is one question.\n */\nexport const AI_STAFF_AUDIT_ACTION_PREFIXES: readonly string[] = [\n 'ai.',\n 'billing.assistOverage.',\n 'platform.aiFreeSpend.',\n]\n\n/** The facet group an `adminAudit` action belongs to. */\nexport const STAFF_AUDIT_AI_GROUP = 'ai'\n\n/**\n * Which log each code is written to. The job and edit codes land in both\n * the org feed and the host's copy; the billing and permission codes are\n * org-level facts and land in the org feed alone.\n */\nconst AI_ACTIVITY_ACTION_SCOPES: Record<\n AiActivityAction,\n PluginActivityScope | readonly PluginActivityScope[]\n> = {\n 'ai.job.created': ['org', 'host'],\n 'ai.job.output': ['org', 'host'],\n 'ai.job.canceled': ['org', 'host'],\n 'ai.job.needs_input': ['org', 'host'],\n 'ai.edit.applied': ['org', 'host'],\n 'ai.seo.applied': ['org', 'host'],\n 'ai.assist.section': ['org', 'host'],\n 'ai.overage.hardCap': 'org',\n 'ai.overage.cap': 'org',\n 'ai.allotment.changed': 'org',\n 'ai.permission.changed': 'org',\n 'ai.addon.purchased': 'org',\n 'ai.addon.removed': 'org',\n}\n\n/**\n * The catalog, declared through the generic activity-action seam\n * (AGL-2940) so the feed's chip, the actor table's filter and the staff\n * facet read it from the registry beside every other plugin's codes.\n * `registerAiDeclarations` calls it, in both apps and in the browser.\n */\nexport function registerAiActivityActions(): void {\n registerPluginActivityActions({\n pluginId: 'ai',\n group: {\n id: STAFF_AUDIT_AI_GROUP,\n label: AI_ACTIVITY_FILTER_LABEL,\n staffAuditPrefixes: AI_STAFF_AUDIT_ACTION_PREFIXES.filter(\n (prefix) => prefix !== 'ai.',\n ),\n // The staff cards opening on an org (AGL-2930) and on one account\n // (AGL-2928). Neither writes these any more; the rows already in the\n // log still classify as reads rather than changes.\n staffAuditAccessActions: ['org.ai-viewed', 'user.ai-usage-viewed'],\n },\n actions: AI_ACTIVITY_ACTION_LIST.map((key) => ({\n key,\n label: AI_ACTIVITY_ACTION_LABELS[key],\n scope: AI_ACTIVITY_ACTION_SCOPES[key],\n })),\n // A generation job (AGL-2904): the org feed names the job, and each of\n // its outputs names the resource it produced. Filed as `aiJob` since\n // before plugin target types were namespaced, so the noun is declared\n // here rather than read off the type (AGL-3080).\n targetTypes: { aiJob: 'AI generation' },\n })\n}\n\n/**\n * The group the staff audit facet files an action under: `ai` for every\n * AI row, otherwise the action's leading namespace (`billing`, `org`,\n * `plugins`). Roughly seventy distinct actions write to `adminAudit`, so\n * the facet offers namespaces rather than a seventy-entry menu. Answered\n * by the registry, so every plugin's group is filed the same way.\n */\nexport function staffAuditActionGroup(action: unknown): string {\n return pluginStaffAuditActionGroup(action)\n}\n\n/** How a facet group reads in the menu: `ai` → `AI`, `billing` → `billing`. */\nexport function staffAuditActionGroupLabel(group: string): string {\n return pluginStaffAuditActionGroupLabel(group)\n}\n"],"names":["pluginStaffAuditActionGroup","pluginStaffAuditActionGroupLabel","registerPluginActivityActions","AI_ACTIVITY_ACTIONS","jobCreated","jobOutput","jobCanceled","jobNeedsInput","editApplied","seoApplied","assistSection","overageHardCap","overageCap","allotmentChanged","permissionChanged","addonPurchased","addonRemoved","AI_ACTIVITY_ACTION_LABELS","AI_ACTIVITY_ACTION_LIST","Object","values","AI_ACTIVITY_FILTER_LABEL","AI_JOB_NEEDS_INPUT_REASON_LABELS","plan","doctrine","limit","band","cap","messages","budget","allotment","account","requests","refusals","platform","AI_OUTPUT_TARGET_TYPES","screen","reusableComponent","layout","template","form","emailScreen","campaign","product","experiment","workflow","seo","text","theme","insight","crm","draft","logic","orgAutomation","aiOutputTargetType","resource","isAiActivityAction","action","includes","aiActivityActionLabel","undefined","AI_STAFF_AUDIT_ACTION_PREFIXES","STAFF_AUDIT_AI_GROUP","AI_ACTIVITY_ACTION_SCOPES","registerAiActivityActions","pluginId","group","id","label","staffAuditPrefixes","filter","prefix","staffAuditAccessActions","actions","map","key","scope","targetTypes","aiJob","staffAuditActionGroup","staffAuditActionGroupLabel"],"mappings":"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"}
1
+ {"version":3,"sources":["../../../../../../../libs/plugins/ai/src/lib/activity/ai-activity-actions.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 * The AI actions an activity log can carry (AGL-2929).\n *\n * Every other action in `orgs/{orgId}/activity` and `hosts/{hostId}/activity`\n * is a prose sentence written at the call site — \"Saved the screen\". The AI\n * rows are CODES instead, because they are read by more than a person: the\n * org feed's \"AI\" chip, the staff audit facet and the actor table all need\n * to recognize an AI row without parsing a sentence, and a sentence that\n * three writers phrase three ways is three rows that look unrelated.\n *\n * One list, so the writers in `ai-activity.ts`, the feed presenter and the\n * staff facet cannot disagree about what counts as AI. A code missing from\n * `AI_ACTIVITY_ACTION_LABELS` fails the type, not the reader.\n */\n\nimport type { AiJobOutputResource } from '../model/ai-jobs.types'\nimport {\n pluginStaffAuditActionGroup,\n pluginStaffAuditActionGroupLabel,\n registerPluginActivityActions,\n type PluginActivityScope,\n} from '@aglyn/aglyn/plugin-manager/plugin-activity-actions'\n\n/** The action code each AI writer stores. */\nexport const AI_ACTIVITY_ACTIONS = {\n jobCreated: 'ai.job.created',\n jobOutput: 'ai.job.output',\n jobCanceled: 'ai.job.canceled',\n jobNeedsInput: 'ai.job.needs_input',\n editApplied: 'ai.edit.applied',\n seoApplied: 'ai.seo.applied',\n assistSection: 'ai.assist.section',\n overageHardCap: 'ai.overage.hardCap',\n overageCap: 'ai.overage.cap',\n allotmentChanged: 'ai.allotment.changed',\n permissionChanged: 'ai.permission.changed',\n addonPurchased: 'ai.addon.purchased',\n addonRemoved: 'ai.addon.removed',\n} as const\n\nexport type AiActivityAction =\n (typeof AI_ACTIVITY_ACTIONS)[keyof typeof AI_ACTIVITY_ACTIONS]\n\n/** What a person reads for each code, in the feed and the actor table. */\nexport const AI_ACTIVITY_ACTION_LABELS: Record<AiActivityAction, string> = {\n 'ai.job.created': 'Started an AI generation',\n 'ai.job.output': 'AI generated',\n 'ai.job.canceled': 'Canceled an AI generation',\n 'ai.job.needs_input': 'AI generation paused for input',\n 'ai.edit.applied': 'Applied AI edits',\n 'ai.seo.applied': 'Applied AI SEO fixes as drafts',\n 'ai.assist.section': 'AI generated a section',\n 'ai.overage.hardCap': 'AI stop-at-band switch',\n 'ai.overage.cap': 'AI overage ceiling',\n 'ai.allotment.changed': 'AI allotment changed',\n 'ai.permission.changed': 'AI permission changed',\n 'ai.addon.purchased': 'Added the AI add-on',\n 'ai.addon.removed': 'Removed the AI add-on',\n}\n\n/** Every code, in catalog order — what a filter sends as `isAnyOf`. */\nexport const AI_ACTIVITY_ACTION_LIST: readonly AiActivityAction[] =\n Object.values(AI_ACTIVITY_ACTIONS)\n\n/** The feed's filter chip and the staff facet's group, by one name. */\nexport const AI_ACTIVITY_FILTER_LABEL = 'AI'\n\n/**\n * Why a generation stopped and asked for a person (AGL-2904): the plan's\n * band ran out, the org's own ceiling refused, the monthly message cap or\n * the job's own token budget did — or, on the Free taste (AGL-2925), one of\n * its own precautions: the account's credits, its daily request cap, a\n * pause after declined briefs, or the platform's day of free spend. Those\n * are the meter's `AssistRefusedBy` less its `null`, so a ceiling the meter\n * can name is one the feed can label. The last three are the job's own: its\n * plan is ready for review, or an answer broke a building rule on its re-ask\n * (AGL-2935), or the site is at an allowance its plan sets for what the job\n * writes (AGL-2909).\n */\nexport type AiJobNeedsInputReason =\n | 'band'\n | 'cap'\n | 'messages'\n | 'budget'\n | 'allotment'\n | 'account'\n | 'requests'\n | 'refusals'\n | 'platform'\n | 'plan'\n | 'doctrine'\n | 'limit'\n\nexport const AI_JOB_NEEDS_INPUT_REASON_LABELS: Record<\n AiJobNeedsInputReason,\n string\n> = {\n plan: 'its plan is ready for review',\n doctrine: 'its answer broke a building rule twice',\n limit: 'the site reached an allowance of its plan',\n band: 'the included AI band is used up',\n cap: 'the overage ceiling was reached',\n messages: 'the monthly message cap was reached',\n budget: 'the job budget was reached',\n allotment: 'the creator’s or the site’s AI allotment is used up',\n account: 'the account’s free AI credits are used up',\n requests: 'the daily free request cap was reached',\n refusals: 'free generation is paused for the day after declined briefs',\n platform: 'free AI generation is paused for the day',\n}\n\n/**\n * The feed target types a generation job's output can be filed under: the\n * kinds both activity logs know, so the org row and its host copy share a\n * shape.\n */\nexport type AiOutputTargetType =\n | 'screen'\n | 'layout'\n | 'component'\n | 'template'\n | 'workflow'\n | 'content'\n | 'theme'\n\n/**\n * Where the feed files each resource kind a job can write (AGL-2904).\n *\n * A job names its output by the resource it wrote, and the activity logs\n * know a narrower set of targets. The map is total, so a resource kind\n * added to the job document must say where the feed shows it before the\n * machine can log it. `reusableComponent` is the feed's `component`; a\n * `text` output is copy, which the feed files as `content`; a `theme`\n * proposal is filed under the site's theme, which the host feed links to the\n * Theme section (AGL-2938); the kinds whose runners have not shipped are\n * content of the site too, and are filed there until a target of their own\n * exists.\n */\nconst AI_OUTPUT_TARGET_TYPES: Record<AiJobOutputResource, AiOutputTargetType> = {\n screen: 'screen',\n reusableComponent: 'component',\n layout: 'layout',\n template: 'template',\n form: 'content',\n emailScreen: 'content',\n campaign: 'content',\n product: 'content',\n experiment: 'content',\n workflow: 'workflow',\n // An SEO proposal (AGL-2910) is about the site's content, and is filed there.\n seo: 'content',\n text: 'content',\n theme: 'theme',\n // An insight answer (AGL-2915) is about the site's figures; the feed row\n // names it and never what it says.\n insight: 'content',\n // A CRM proposal (AGL-2917) writes nothing; the feed files it with content.\n crm: 'content',\n // Another plugin's draft a build asked its writer for (AGL-3616).\n draft: 'content',\n // A logic proposal (AGL-3603) writes nothing either.\n logic: 'content',\n // So does an org automation's (AGL-3603): the editor's Save is the write.\n orgAutomation: 'content',\n // A blog post a guided start wrote (AGL-3676) is the site's content.\n entry: 'content',\n}\n\nexport function aiOutputTargetType(resource: AiJobOutputResource): AiOutputTargetType {\n return AI_OUTPUT_TARGET_TYPES[resource]\n}\n\n/** Whether a stored action is one of the AI codes above. */\nexport function isAiActivityAction(action: unknown): action is AiActivityAction {\n return (\n typeof action === 'string' &&\n (AI_ACTIVITY_ACTION_LIST as readonly string[]).includes(action)\n )\n}\n\n/** The readable label for an AI code; `undefined` for any other action. */\nexport function aiActivityActionLabel(action: unknown): string | undefined {\n return isAiActivityAction(action)\n ? AI_ACTIVITY_ACTION_LABELS[action]\n : undefined\n}\n\n/**\n * Staff audit rows that are ABOUT AI without carrying an `ai.` code: the\n * customer's overage controls already write `billing.assistOverage.*`, and\n * the platform's free-spend auto-pause writes `platform.aiFreeSpend.*`\n * (AGL-2925). The audit page's facet folds them under the same group as the\n * codes, because \"what did we do about AI this week\" is one question.\n */\nexport const AI_STAFF_AUDIT_ACTION_PREFIXES: readonly string[] = [\n 'ai.',\n 'billing.assistOverage.',\n 'platform.aiFreeSpend.',\n]\n\n/** The facet group an `adminAudit` action belongs to. */\nexport const STAFF_AUDIT_AI_GROUP = 'ai'\n\n/**\n * Which log each code is written to. The job and edit codes land in both\n * the org feed and the host's copy; the billing and permission codes are\n * org-level facts and land in the org feed alone.\n */\nconst AI_ACTIVITY_ACTION_SCOPES: Record<\n AiActivityAction,\n PluginActivityScope | readonly PluginActivityScope[]\n> = {\n 'ai.job.created': ['org', 'host'],\n 'ai.job.output': ['org', 'host'],\n 'ai.job.canceled': ['org', 'host'],\n 'ai.job.needs_input': ['org', 'host'],\n 'ai.edit.applied': ['org', 'host'],\n 'ai.seo.applied': ['org', 'host'],\n 'ai.assist.section': ['org', 'host'],\n 'ai.overage.hardCap': 'org',\n 'ai.overage.cap': 'org',\n 'ai.allotment.changed': 'org',\n 'ai.permission.changed': 'org',\n 'ai.addon.purchased': 'org',\n 'ai.addon.removed': 'org',\n}\n\n/**\n * The catalog, declared through the generic activity-action seam\n * (AGL-2940) so the feed's chip, the actor table's filter and the staff\n * facet read it from the registry beside every other plugin's codes.\n * `registerAiDeclarations` calls it, in both apps and in the browser.\n */\nexport function registerAiActivityActions(): void {\n registerPluginActivityActions({\n pluginId: 'ai',\n group: {\n id: STAFF_AUDIT_AI_GROUP,\n label: AI_ACTIVITY_FILTER_LABEL,\n staffAuditPrefixes: AI_STAFF_AUDIT_ACTION_PREFIXES.filter(\n (prefix) => prefix !== 'ai.',\n ),\n // The staff cards opening on an org (AGL-2930) and on one account\n // (AGL-2928), which no longer write these, so the rows already in the\n // log still classify as reads; and a staff member reading what an org\n // asked Aglyn AI (AGL-3675), which writes one per page.\n staffAuditAccessActions: ['org.ai-viewed', 'user.ai-usage-viewed', 'org.ai-conversations-viewed'],\n },\n actions: AI_ACTIVITY_ACTION_LIST.map((key) => ({\n key,\n label: AI_ACTIVITY_ACTION_LABELS[key],\n scope: AI_ACTIVITY_ACTION_SCOPES[key],\n })),\n // A generation job (AGL-2904): the org feed names the job, and each of\n // its outputs names the resource it produced. Filed as `aiJob` since\n // before plugin target types were namespaced, so the noun is declared\n // here rather than read off the type (AGL-3080).\n targetTypes: { aiJob: 'AI generation' },\n })\n}\n\n/**\n * The group the staff audit facet files an action under: `ai` for every\n * AI row, otherwise the action's leading namespace (`billing`, `org`,\n * `plugins`). Roughly seventy distinct actions write to `adminAudit`, so\n * the facet offers namespaces rather than a seventy-entry menu. Answered\n * by the registry, so every plugin's group is filed the same way.\n */\nexport function staffAuditActionGroup(action: unknown): string {\n return pluginStaffAuditActionGroup(action)\n}\n\n/** How a facet group reads in the menu: `ai` → `AI`, `billing` → `billing`. */\nexport function staffAuditActionGroupLabel(group: string): string {\n return pluginStaffAuditActionGroupLabel(group)\n}\n"],"names":["pluginStaffAuditActionGroup","pluginStaffAuditActionGroupLabel","registerPluginActivityActions","AI_ACTIVITY_ACTIONS","jobCreated","jobOutput","jobCanceled","jobNeedsInput","editApplied","seoApplied","assistSection","overageHardCap","overageCap","allotmentChanged","permissionChanged","addonPurchased","addonRemoved","AI_ACTIVITY_ACTION_LABELS","AI_ACTIVITY_ACTION_LIST","Object","values","AI_ACTIVITY_FILTER_LABEL","AI_JOB_NEEDS_INPUT_REASON_LABELS","plan","doctrine","limit","band","cap","messages","budget","allotment","account","requests","refusals","platform","AI_OUTPUT_TARGET_TYPES","screen","reusableComponent","layout","template","form","emailScreen","campaign","product","experiment","workflow","seo","text","theme","insight","crm","draft","logic","orgAutomation","entry","aiOutputTargetType","resource","isAiActivityAction","action","includes","aiActivityActionLabel","undefined","AI_STAFF_AUDIT_ACTION_PREFIXES","STAFF_AUDIT_AI_GROUP","AI_ACTIVITY_ACTION_SCOPES","registerAiActivityActions","pluginId","group","id","label","staffAuditPrefixes","filter","prefix","staffAuditAccessActions","actions","map","key","scope","targetTypes","aiJob","staffAuditActionGroup","staffAuditActionGroupLabel"],"mappings":"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"}
@@ -0,0 +1,66 @@
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 ComponentProps } from 'react';
18
+ import { AiAssistProvider } from './ai-assist-provider.component';
19
+ /**
20
+ * What the console shell hands a provider and the assistant dock (AGL-2984):
21
+ * the reader's verdict for every catalog key a plugin declared, on the site
22
+ * in view, with `loaded` false until every read behind it has answered.
23
+ */
24
+ export interface ShellPermissionsOnHost {
25
+ loaded: boolean;
26
+ granted: Readonly<Record<string, boolean>>;
27
+ }
28
+ /** The AI half of that answer, in the shape the AI surfaces hold on. */
29
+ export interface AiPermissionsAnswer {
30
+ loaded: boolean;
31
+ use: boolean;
32
+ generate: boolean;
33
+ }
34
+ /**
35
+ * The shell's answer read for the two AI keys. `undefined` while the shell
36
+ * has handed nothing, which the provider reads as pending; one object per
37
+ * verdict, so the callbacks keyed on it are not rebuilt on every render.
38
+ */
39
+ export declare function useAiPermissionsOnHost(answer: ShellPermissionsOnHost | undefined): AiPermissionsAnswer | undefined;
40
+ type ProviderProps = Omit<ComponentProps<typeof AiAssistProvider>, 'aiPermissions'> & {
41
+ permissionsOnHost?: ShellPermissionsOnHost;
42
+ /**
43
+ * The plugins that run on the site in view, as the shell resolved them
44
+ * (AGL-3028). Absent where the shell hands none, which reads as no site
45
+ * narrowing at all.
46
+ */
47
+ enabledPluginIds?: readonly string[];
48
+ };
49
+ /**
50
+ * The besigner copy assistant's provider, holding on the shell's permission
51
+ * answer.
52
+ *
53
+ * On a site with AI switched off (AGL-3028) it stays MOUNTED — it wraps every
54
+ * console page, and a provider that came and went per site would remount the
55
+ * whole tree beneath it — and opens nothing: a settled refusal publishes no
56
+ * callback, so no control can reach its dialogs.
57
+ *
58
+ * The one component the plugin registers eagerly (AGL-3649): a provider wraps
59
+ * the page, so one that loaded late would remount everything beneath it. It
60
+ * is in its own module so that loading it loads nothing of the dock's.
61
+ */
62
+ export declare function AiAssistProviderOnHost(props: ProviderProps): import("react").JSX.Element;
63
+ export declare namespace AiAssistProviderOnHost {
64
+ var displayName: string;
65
+ }
66
+ export {};
@@ -0,0 +1,78 @@
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 { _ as _extends } from "@swc/helpers/_/_extends";
18
+ import { _ as _object_without_properties_loose } from "@swc/helpers/_/_object_without_properties_loose";
19
+ import { jsx as _jsx } from "react/jsx-runtime";
20
+ import { useMemo } from "react";
21
+ import { AI_PLUGIN_ID } from "../constants.js";
22
+ import { aiPermissionsOf } from "../model/ai-permissions.js";
23
+ import { AiAssistProvider } from "./ai-assist-provider.component.js";
24
+ /**
25
+ * The shell's answer read for the two AI keys. `undefined` while the shell
26
+ * has handed nothing, which the provider reads as pending; one object per
27
+ * verdict, so the callbacks keyed on it are not rebuilt on every render.
28
+ */ export function useAiPermissionsOnHost(answer) {
29
+ const present = answer !== undefined;
30
+ const loaded = (answer == null ? void 0 : answer.loaded) === true;
31
+ const verdict = aiPermissionsOf(loaded ? answer == null ? void 0 : answer.granted : null);
32
+ const use = verdict['ai.use'];
33
+ const generate = verdict['ai.generate'];
34
+ return useMemo(()=>present ? {
35
+ loaded,
36
+ use,
37
+ generate
38
+ } : undefined, [
39
+ present,
40
+ loaded,
41
+ use,
42
+ generate
43
+ ]);
44
+ }
45
+ /**
46
+ * Every AI door closed, as a settled answer: what the provider holds on a site
47
+ * that switched AI off. One object, so the callbacks keyed on it are stable.
48
+ */ const OFF_FOR_SITE = {
49
+ loaded: true,
50
+ use: false,
51
+ generate: false
52
+ };
53
+ /**
54
+ * The besigner copy assistant's provider, holding on the shell's permission
55
+ * answer.
56
+ *
57
+ * On a site with AI switched off (AGL-3028) it stays MOUNTED — it wraps every
58
+ * console page, and a provider that came and went per site would remount the
59
+ * whole tree beneath it — and opens nothing: a settled refusal publishes no
60
+ * callback, so no control can reach its dialogs.
61
+ *
62
+ * The one component the plugin registers eagerly (AGL-3649): a provider wraps
63
+ * the page, so one that loaded late would remount everything beneath it. It
64
+ * is in its own module so that loading it loads nothing of the dock's.
65
+ */ export function AiAssistProviderOnHost(props) {
66
+ const { permissionsOnHost, enabledPluginIds } = props, rest = _object_without_properties_loose(props, [
67
+ "permissionsOnHost",
68
+ "enabledPluginIds"
69
+ ]);
70
+ const aiPermissions = useAiPermissionsOnHost(permissionsOnHost);
71
+ const offForSite = Boolean(enabledPluginIds) && !(enabledPluginIds == null ? void 0 : enabledPluginIds.includes(AI_PLUGIN_ID));
72
+ return /*#__PURE__*/ _jsx(AiAssistProvider, _extends({}, rest, {
73
+ aiPermissions: offForSite ? OFF_FOR_SITE : aiPermissions
74
+ }));
75
+ }
76
+ AiAssistProviderOnHost.displayName = 'AiAssistProviderOnHost';
77
+
78
+ //# sourceMappingURL=ai-assist-provider-on-host.component.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../../../../libs/plugins/ai/src/lib/components/ai-assist-provider-on-host.component.tsx"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n'use client'\n\nimport { useMemo, type ComponentProps } from 'react'\nimport { AI_PLUGIN_ID } from '../constants'\nimport { aiPermissionsOf } from '../model/ai-permissions'\nimport { AiAssistProvider } from './ai-assist-provider.component'\n\n/**\n * What the console shell hands a provider and the assistant dock (AGL-2984):\n * the reader's verdict for every catalog key a plugin declared, on the site\n * in view, with `loaded` false until every read behind it has answered.\n */\nexport interface ShellPermissionsOnHost {\n loaded: boolean\n granted: Readonly<Record<string, boolean>>\n}\n\n/** The AI half of that answer, in the shape the AI surfaces hold on. */\nexport interface AiPermissionsAnswer {\n loaded: boolean\n use: boolean\n generate: boolean\n}\n\n/**\n * The shell's answer read for the two AI keys. `undefined` while the shell\n * has handed nothing, which the provider reads as pending; one object per\n * verdict, so the callbacks keyed on it are not rebuilt on every render.\n */\nexport function useAiPermissionsOnHost(\n answer: ShellPermissionsOnHost | undefined,\n): AiPermissionsAnswer | undefined {\n const present = answer !== undefined\n const loaded = answer?.loaded === true\n const verdict = aiPermissionsOf(loaded ? answer?.granted : null)\n const use = verdict['ai.use']\n const generate = verdict['ai.generate']\n return useMemo(\n () => (present ? { loaded, use, generate } : undefined),\n [present, loaded, use, generate],\n )\n}\n\ntype ProviderProps = Omit<\n ComponentProps<typeof AiAssistProvider>,\n 'aiPermissions'\n> & {\n permissionsOnHost?: ShellPermissionsOnHost\n /**\n * The plugins that run on the site in view, as the shell resolved them\n * (AGL-3028). Absent where the shell hands none, which reads as no site\n * narrowing at all.\n */\n enabledPluginIds?: readonly string[]\n}\n\n/**\n * Every AI door closed, as a settled answer: what the provider holds on a site\n * that switched AI off. One object, so the callbacks keyed on it are stable.\n */\nconst OFF_FOR_SITE: AiPermissionsAnswer = {\n loaded: true,\n use: false,\n generate: false,\n}\n\n/**\n * The besigner copy assistant's provider, holding on the shell's permission\n * answer.\n *\n * On a site with AI switched off (AGL-3028) it stays MOUNTED — it wraps every\n * console page, and a provider that came and went per site would remount the\n * whole tree beneath it — and opens nothing: a settled refusal publishes no\n * callback, so no control can reach its dialogs.\n *\n * The one component the plugin registers eagerly (AGL-3649): a provider wraps\n * the page, so one that loaded late would remount everything beneath it. It\n * is in its own module so that loading it loads nothing of the dock's.\n */\nexport function AiAssistProviderOnHost(props: ProviderProps) {\n const { permissionsOnHost, enabledPluginIds, ...rest } = props\n const aiPermissions = useAiPermissionsOnHost(permissionsOnHost)\n const offForSite =\n Boolean(enabledPluginIds) && !enabledPluginIds?.includes(AI_PLUGIN_ID)\n return (\n <AiAssistProvider\n {...rest}\n aiPermissions={offForSite ? OFF_FOR_SITE : aiPermissions}\n />\n )\n}\nAiAssistProviderOnHost.displayName = 'AiAssistProviderOnHost'\n"],"names":["useMemo","AI_PLUGIN_ID","aiPermissionsOf","AiAssistProvider","useAiPermissionsOnHost","answer","present","undefined","loaded","verdict","granted","use","generate","OFF_FOR_SITE","AiAssistProviderOnHost","props","permissionsOnHost","enabledPluginIds","rest","aiPermissions","offForSite","Boolean","includes","displayName"],"mappings":"AAAA;;;;;;;;;;;;;;;CAeC,GAED;;;;AAEA,SAASA,OAAO,QAA6B,QAAO;AACpD,SAASC,YAAY,QAAQ,kBAAc;AAC3C,SAASC,eAAe,QAAQ,6BAAyB;AACzD,SAASC,gBAAgB,QAAQ,oCAAgC;AAmBjE;;;;CAIC,GACD,OAAO,SAASC,uBACdC,MAA0C;IAE1C,MAAMC,UAAUD,WAAWE;IAC3B,MAAMC,SAASH,CAAAA,0BAAAA,OAAQG,MAAM,MAAK;IAClC,MAAMC,UAAUP,gBAAgBM,SAASH,0BAAAA,OAAQK,OAAO,GAAG;IAC3D,MAAMC,MAAMF,OAAO,CAAC,SAAS;IAC7B,MAAMG,WAAWH,OAAO,CAAC,cAAc;IACvC,OAAOT,QACL,IAAOM,UAAU;YAAEE;YAAQG;YAAKC;QAAS,IAAIL,WAC7C;QAACD;QAASE;QAAQG;QAAKC;KAAS;AAEpC;AAeA;;;CAGC,GACD,MAAMC,eAAoC;IACxCL,QAAQ;IACRG,KAAK;IACLC,UAAU;AACZ;AAEA;;;;;;;;;;;;CAYC,GACD,OAAO,SAASE,uBAAuBC,KAAoB;IACzD,MAAM,EAAEC,iBAAiB,EAAEC,gBAAgB,EAAW,GAAGF,OAATG,wCAASH;;;;IACzD,MAAMI,gBAAgBf,uBAAuBY;IAC7C,MAAMI,aACJC,QAAQJ,qBAAqB,EAACA,oCAAAA,iBAAkBK,QAAQ,CAACrB;IAC3D,qBACE,KAACE,+BACKe;QACJC,eAAeC,aAAaP,eAAeM;;AAGjD;AACAL,uBAAuBS,WAAW,GAAG"}
@@ -16,8 +16,7 @@
16
16
  */ 'use client';
17
17
  import { _ as _extends } from "@swc/helpers/_/_extends";
18
18
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
19
- import * as Aglyn from "@aglyn/aglyn";
20
- import { checkEntitlement, lockdownRefusalText, parseLockdownRefusal } from "@aglyn/aglyn";
19
+ import { canvas, checkEntitlement, components, FEATURE_FLAG, FieldComponentType, lockdownRefusalText, NodeType, parseLockdownRefusal } from "@aglyn/aglyn";
21
20
  import { portableDefinitionToNested } from "@aglyn/aglyn/app-utils/node-definition-sanitizer";
22
21
  import { AiAssistActionsContext } from "./ai-assist-actions-context.js";
23
22
  import { assistNotOnPlanText } from "../usage/assist-credits.js";
@@ -79,8 +78,8 @@ const AI_GENERATE_REFUSED = 'Your role does not include AI generation — ask an
79
78
  var _ref, _ref1;
80
79
  var _schema_flags;
81
80
  const schema = node == null ? void 0 : node.componentSchema;
82
- const textEditable = (((_ref = schema == null ? void 0 : (_schema_flags = schema.flags) == null ? void 0 : _schema_flags.textEditable) != null ? _ref : Aglyn.FEATURE_FLAG.DISABLED) & Aglyn.FEATURE_FLAG.ENABLED) !== 0;
83
- const attributes = ((_ref1 = schema == null ? void 0 : schema.attributes) != null ? _ref1 : []).filter((field)=>field.component === Aglyn.FieldComponentType.TEXT_FIELD || field.component === Aglyn.FieldComponentType.TEXTAREA).map((field)=>{
81
+ const textEditable = (((_ref = schema == null ? void 0 : (_schema_flags = schema.flags) == null ? void 0 : _schema_flags.textEditable) != null ? _ref : FEATURE_FLAG.DISABLED) & FEATURE_FLAG.ENABLED) !== 0;
82
+ const attributes = ((_ref1 = schema == null ? void 0 : schema.attributes) != null ? _ref1 : []).filter((field)=>field.component === FieldComponentType.TEXT_FIELD || field.component === FieldComponentType.TEXTAREA).map((field)=>{
84
83
  var _field_label;
85
84
  return {
86
85
  prop: String(field.name),
@@ -143,7 +142,7 @@ const AI_GENERATE_REFUSED = 'Your role does not include AI generation — ask an
143
142
  setBusy(true);
144
143
  try {
145
144
  var _current_props;
146
- const current = Aglyn.canvas.toJSON().nodes[node.$id];
145
+ const current = canvas.toJSON().nodes[node.$id];
147
146
  const text = typeof (current == null ? void 0 : (_current_props = current.props) == null ? void 0 : _current_props[effectiveTarget]) === 'string' ? current.props[effectiveTarget] : '';
148
147
  const response = await authorizedFetch(user, '/api/ai/assist', {
149
148
  method: 'POST',
@@ -185,7 +184,7 @@ const AI_GENERATE_REFUSED = 'Your role does not include AI generation — ask an
185
184
  allowDuplicate: true
186
185
  });
187
186
  }
188
- Aglyn.canvas.updateNodeProps(node, _extends({}, current == null ? void 0 : current.props, {
187
+ canvas.updateNodeProps(node, _extends({}, current == null ? void 0 : current.props, {
189
188
  [effectiveTarget]: payload.text
190
189
  }, effectiveTarget === 'children' ? {
191
190
  html: undefined
@@ -305,17 +304,17 @@ const AI_GENERATE_REFUSED = 'Your role does not include AI generation — ask an
305
304
  // and the subtree lands at the end of the canvas root.
306
305
  const stamped = function stamp(node) {
307
306
  var _node_nodes;
308
- const schema = Aglyn.components.getSchema(node.componentId);
307
+ const schema = components.getSchema(node.componentId);
309
308
  return _extends({}, node, (schema == null ? void 0 : schema.pluginId) ? {
310
309
  pluginId: schema.pluginId
311
310
  } : {}, {
312
311
  nodes: ((_node_nodes = node.nodes) != null ? _node_nodes : []).map(stamp)
313
312
  });
314
313
  }(nested);
315
- Aglyn.canvas.addNodeFromPreset({
316
- type: Aglyn.NodeType.PRESET,
314
+ canvas.addNodeFromPreset({
315
+ type: NodeType.PRESET,
317
316
  data: stamped
318
- }, Aglyn.canvas.rootNode);
317
+ }, canvas.rootNode);
319
318
  setSectionOpen(false);
320
319
  enqueueSnackbar('Section added — undo removes it', {
321
320
  variant: 'success',
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../../../libs/plugins/ai/src/lib/components/ai-assist-provider.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 * as Aglyn from '@aglyn/aglyn'\nimport {\n checkEntitlement,\n lockdownRefusalText,\n parseLockdownRefusal,\n} from '@aglyn/aglyn'\nimport { portableDefinitionToNested } from '@aglyn/aglyn/app-utils/node-definition-sanitizer'\nimport { AiAssistActionsContext } from './ai-assist-actions-context'\nimport { assistNotOnPlanText } from '../usage/assist-credits'\nimport { useSnackbar } from '@aglyn/shared-ui-snackstack'\nimport {\n Button,\n CircularProgress,\n Dialog,\n DialogActions,\n DialogContent,\n DialogTitle,\n MenuItem,\n TextField,\n Typography,\n} from '@mui/material'\nimport { useCallback, useMemo, useState } from 'react'\nimport { useUser } from '@aglyn/tenant-feature-instance'\nimport { authorizedFetch } from '@aglyn/shared-util-http/authorized-token'\nimport { AiModelSelector } from './ai-model-selector.component'\nimport { AiUsageStrip } from './ai-usage-strip.component'\nimport { useAiModelChoice } from './use-ai-model-choice'\nimport { usePublishAiUsageMeter } from './use-ai-usage-meter'\n\n\nexport interface AiAssistProviderProps {\n /** Org billing doc for the entitlement gate (mounted by the shell). */\n org?: unknown\n /**\n * True once `org` is a trustworthy answer (AGL-1380). The shell mounts\n * this provider above the whole console route tree, so it cannot hold its\n * render until the billing doc settles the way the plugin-page route does\n * — and an undefined `org` is not \"unknown\" to `checkEntitlement`, it is\n * the free tier. Without this flag the gates below told a Pro org that AI\n * assist is not on its plan for as long as the read was in flight.\n */\n orgReady?: boolean\n /**\n * The org every assist call is metered against (AGL-2073). The route no\n * longer resolves it from the signed-in user — a user with one paid org was\n * getting assist on all of their free ones, and their spend was landing on\n * whichever org the server happened to resolve.\n */\n orgId?: string\n /**\n * The site the canvas belongs to (AGL-2927), sent with every assist call\n * so the door can decide a site collaborator's permission on THAT site.\n * Null off a host route, where there is no canvas to assist on.\n */\n hostId?: string | null\n /**\n * The reader's AI verdict, resolved by the shell (AGL-2927). The gates\n * below HOLD until `loaded` — a door opened on a pending answer would\n * spend the workspace's credits on a permission nobody has confirmed —\n * and a refused key removes its callback from the context, so the\n * designer draws no control for it. Omitted, the answer is pending.\n */\n aiPermissions?: { loaded: boolean; use: boolean; generate: boolean }\n children?: JSX.Children\n}\n\nconst PERMISSIONS_PENDING = 'Checking your permissions — try again in a moment'\nconst AI_USE_REFUSED =\n 'Your role does not include AI assistance — ask an organization admin'\nconst AI_GENERATE_REFUSED =\n 'Your role does not include AI generation — ask an organization admin'\n\n/**\n * Console-side AI copy assist (AGL-89): provides the designer's \"Rewrite\n * with AI\" callback, hosts the instruction dialog, and calls the assist API\n * (which 501-degrades when no AI provider is configured). The commit\n * spreads the node's current props — `updateNodeProps` REPLACES the props\n * object — and clears any stale rich-text `html` so the new text renders.\n */\nexport function AiAssistProvider(props: AiAssistProviderProps) {\n const org = props.org\n const orgReady = props.orgReady\n const orgId = props.orgId\n const hostId = props.hostId ?? null\n const aiPermissions = props.aiPermissions\n const { children } = props\n const { enqueueSnackbar } = useSnackbar()\n const { data: user } = useUser()\n const [node, setNode] = useState<Aglyn.NodeSchema<any> | null>(null)\n const [instruction, setInstruction] = useState('')\n // Rewrite target (AGL-130): 'children' for text-editable elements, or\n // any text attribute the element's schema declares (alt text, labels…).\n const [targetProp, setTargetProp] = useState('children')\n const [busy, setBusy] = useState(false)\n // Generate section (AGL-169).\n const [sectionOpen, setSectionOpen] = useState(false)\n const [sectionPrompt, setSectionPrompt] = useState('')\n // The model switch and the usage strip in both dialogs (AGL-2942). Each\n // dialog remembers its own pick; one envelope store serves both strips\n // and the assistant panel's.\n const copyModel = useAiModelChoice({ orgId, hostId, surface: 'copy', kind: 'copy.element' })\n const sectionModel = useAiModelChoice({\n orgId,\n hostId,\n surface: 'section',\n kind: 'copy.section',\n })\n const publishMeter = usePublishAiUsageMeter(orgId)\n\n const textTargets = useMemo(() => {\n const schema = node?.componentSchema\n const textEditable =\n ((schema?.flags?.textEditable ?? Aglyn.FEATURE_FLAG.DISABLED) &\n Aglyn.FEATURE_FLAG.ENABLED) !==\n 0\n const attributes = (schema?.attributes ?? [])\n .filter(\n (field: any) =>\n field.component === Aglyn.FieldComponentType.TEXT_FIELD ||\n field.component === Aglyn.FieldComponentType.TEXTAREA,\n )\n .map((field: any) => ({\n prop: String(field.name),\n label: String(field.label ?? field.name),\n }))\n return textEditable\n ? [{ prop: 'children', label: 'Element text' }, ...attributes]\n : attributes\n }, [node])\n\n const handleRewrite = useCallback(\n (target: Aglyn.NodeSchema<any>) => {\n // The permission first (AGL-2927): it is a fact about the reader, and\n // pending asserts nothing here either. The refusal is unreachable\n // through the designer — a refused key publishes no callback — and\n // stands for any other caller of the context.\n if (!aiPermissions?.loaded) {\n return void enqueueSnackbar(PERMISSIONS_PENDING, {\n variant: 'info',\n persist: false,\n })\n }\n if (!aiPermissions.use) {\n return void enqueueSnackbar(AI_USE_REFUSED, {\n variant: 'warning',\n persist: false,\n })\n }\n // AGL-1380: pending asserts nothing. See `orgReady` on the props.\n if (!orgReady) {\n return void enqueueSnackbar(\n 'Checking your plan — try again in a moment',\n { variant: 'info', persist: false },\n )\n }\n if (!checkEntitlement(org as never, 'aiAssist')) {\n return void enqueueSnackbar(assistNotOnPlanText(), {\n variant: 'warning',\n persist: false,\n })\n }\n setInstruction('')\n setTargetProp('children')\n setNode(target)\n },\n [org, orgReady, aiPermissions, enqueueSnackbar],\n )\n\n // Keep the target valid for the selected element.\n const effectiveTarget = textTargets.some((item) => item.prop === targetProp)\n ? targetProp\n : (textTargets[0]?.prop ?? 'children')\n\n const handleConfirm = useCallback(async () => {\n if (!node || !instruction.trim() || busy) return\n setBusy(true)\n try {\n const current = (Aglyn.canvas.toJSON().nodes as Record<string, any>)[\n node.$id\n ]\n const text =\n typeof current?.props?.[effectiveTarget] === 'string'\n ? (current.props[effectiveTarget] as string)\n : ''\n const response = await authorizedFetch(user, '/api/ai/assist', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n orgId,\n hostId,\n text,\n instruction: instruction.trim(),\n ...(copyModel.model ? { model: copyModel.model } : {}),\n }),\n })\n const payload = await response.json()\n publishMeter(payload?.meter)\n // An ai-assist feature lockdown (AGL-1510/1532) reads as a pause, not\n // as \"AI request failed\" — a provider incident or a cost runaway is\n // something WE turned off, and saying so keeps the user's content out\n // of the story.\n const locked = parseLockdownRefusal(response.status, payload)\n if (locked) {\n return void enqueueSnackbar(lockdownRefusalText(locked), {\n variant: 'warning',\n persist: true,\n })\n }\n if (response.status === 501) {\n return void enqueueSnackbar(\n 'AI assist is not configured on this deployment',\n { variant: 'info', persist: false },\n )\n }\n if (!response.ok || !payload?.text) {\n return void enqueueSnackbar(payload?.error ?? 'AI request failed', {\n variant: 'error',\n allowDuplicate: true,\n })\n }\n Aglyn.canvas.updateNodeProps(node, {\n ...current?.props,\n [effectiveTarget]: payload.text,\n // Rich-text elements render `html` over `children`; drop it so the\n // rewrite is what shows (the user can re-format inline afterwards).\n ...(effectiveTarget === 'children' ? { html: undefined } : {}),\n })\n setNode(null)\n enqueueSnackbar('Text rewritten — undo restores the original', {\n variant: 'success',\n persist: false,\n })\n } catch (error) {\n console.error(error)\n enqueueSnackbar('An error has occurred', {\n variant: 'error',\n allowDuplicate: true,\n })\n } finally {\n setBusy(false)\n }\n }, [\n node,\n instruction,\n busy,\n user,\n effectiveTarget,\n orgId,\n hostId,\n copyModel.model,\n publishMeter,\n enqueueSnackbar,\n ])\n\n const handleGenerateSection = useCallback(() => {\n // The permission first (AGL-2927) — a section is a generation, so this\n // door sells under `ai.generate`; see `handleRewrite`.\n if (!aiPermissions?.loaded) {\n return void enqueueSnackbar(PERMISSIONS_PENDING, {\n variant: 'info',\n persist: false,\n })\n }\n if (!aiPermissions.generate) {\n return void enqueueSnackbar(AI_GENERATE_REFUSED, {\n variant: 'warning',\n persist: false,\n })\n }\n // AGL-1380: same gate as `handleRewrite`.\n if (!orgReady) {\n return void enqueueSnackbar('Checking your plan — try again in a moment', {\n variant: 'info',\n persist: false,\n })\n }\n if (!checkEntitlement(org as never, 'aiAssist')) {\n return void enqueueSnackbar(assistNotOnPlanText(), {\n variant: 'warning',\n persist: false,\n })\n }\n setSectionPrompt('')\n setSectionOpen(true)\n }, [org, orgReady, aiPermissions, enqueueSnackbar])\n\n const handleSectionConfirm = useCallback(async () => {\n if (!sectionPrompt.trim() || busy) return\n setBusy(true)\n try {\n const response = await authorizedFetch(user, '/api/ai/assist', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n orgId,\n hostId,\n mode: 'section',\n instruction: sectionPrompt.trim(),\n ...(sectionModel.model ? { model: sectionModel.model } : {}),\n }),\n })\n const payload = await response.json()\n publishMeter(payload?.meter)\n // Same pause notice on the section-generation door (AGL-1532).\n const locked = parseLockdownRefusal(response.status, payload)\n if (locked) {\n return void enqueueSnackbar(lockdownRefusalText(locked), {\n variant: 'warning',\n persist: true,\n })\n }\n if (response.status === 501) {\n return void enqueueSnackbar(\n 'AI assist is not configured on this deployment',\n { variant: 'info', persist: false },\n )\n }\n if (!response.ok || !payload?.section?.rootId) {\n return void enqueueSnackbar(payload?.error ?? 'AI request failed', {\n variant: 'error',\n allowDuplicate: true,\n })\n }\n const nested = portableDefinitionToNested(\n payload.section.rootId,\n payload.section.nodes,\n )\n if (!nested) {\n return void enqueueSnackbar('AI returned an empty section', {\n variant: 'error',\n allowDuplicate: true,\n })\n }\n // Graft through the preset path: ids regenerate, history is saved,\n // and the subtree lands at the end of the canvas root.\n const stamped = (function stamp(node: any): any {\n const schema = Aglyn.components.getSchema(node.componentId)\n return {\n ...node,\n ...(schema?.pluginId ? { pluginId: schema.pluginId } : {}),\n nodes: (node.nodes ?? []).map(stamp),\n }\n })(nested)\n Aglyn.canvas.addNodeFromPreset(\n { type: Aglyn.NodeType.PRESET, data: stamped } as any,\n Aglyn.canvas.rootNode as any,\n )\n setSectionOpen(false)\n enqueueSnackbar('Section added — undo removes it', {\n variant: 'success',\n persist: false,\n })\n } catch (error) {\n console.error(error)\n enqueueSnackbar('An error has occurred', {\n variant: 'error',\n allowDuplicate: true,\n })\n } finally {\n setBusy(false)\n }\n }, [\n sectionPrompt,\n busy,\n user,\n orgId,\n hostId,\n sectionModel.model,\n publishMeter,\n enqueueSnackbar,\n ])\n\n // A REFUSED key publishes no callback (AGL-2927): the besigner controls\n // render only when the callback exists, so the refusal removes\n // the button rather than dimming it. A PENDING answer keeps both\n // callbacks, and each holds with a notice when pressed — a control that\n // vanishes and reappears while the read lands is worse than one that is\n // briefly inert (the `useHostRole` argument, applied here).\n const refusedUse = aiPermissions?.loaded === true && !aiPermissions.use\n const refusedGenerate =\n aiPermissions?.loaded === true && !aiPermissions.generate\n const contextValue = useMemo(\n () => ({\n ...(refusedUse ? {} : { onRewrite: handleRewrite }),\n ...(refusedGenerate ? {} : { onGenerateSection: handleGenerateSection }),\n }),\n [handleRewrite, handleGenerateSection, refusedUse, refusedGenerate],\n )\n\n return (\n <AiAssistActionsContext.Provider value={contextValue}>\n {children}\n <Dialog\n open={Boolean(node)}\n onClose={() => (busy ? null : setNode(null))}\n maxWidth=\"xs\"\n fullWidth\n >\n <DialogTitle>{'Rewrite with AI'}</DialogTitle>\n <DialogContent\n sx={{ display: 'flex', flexDirection: 'column', gap: 2, pt: 1 }}\n >\n <Typography variant=\"body2\" color=\"text.secondary\">\n {'Describe how the text should change — tone, length, message.'}\n </Typography>\n {textTargets.length > 1 ? (\n <TextField\n select\n label=\"Field\"\n value={effectiveTarget}\n onChange={(event) => setTargetProp(event.target.value)}\n size=\"small\"\n disabled={busy}\n >\n {textTargets.map((item) => (\n <MenuItem key={item.prop} value={item.prop}>\n {item.label}\n </MenuItem>\n ))}\n </TextField>\n ) : null}\n <TextField\n label=\"Instruction\"\n placeholder=\"e.g. Make it punchier and half as long\"\n value={instruction}\n onChange={(event) => setInstruction(event.target.value)}\n size=\"small\"\n autoFocus\n multiline\n minRows={2}\n disabled={busy}\n onKeyDown={(event) => {\n if (event.key === 'Enter' && (event.metaKey || event.ctrlKey)) {\n event.preventDefault()\n handleConfirm()\n }\n }}\n />\n <AiModelSelector choice={copyModel} disabled={busy} />\n <AiUsageStrip orgId={orgId} />\n </DialogContent>\n <DialogActions>\n <Button disabled={busy} onClick={() => setNode(null)}>\n {'Cancel'}\n </Button>\n <Button\n variant=\"contained\"\n color=\"primary\"\n disabled={!instruction.trim() || busy}\n startIcon={busy ? <CircularProgress size={16} /> : undefined}\n onClick={handleConfirm}\n >\n {busy ? 'Rewriting…' : 'Rewrite'}\n </Button>\n </DialogActions>\n </Dialog>\n <Dialog\n open={sectionOpen}\n onClose={() => (busy ? null : setSectionOpen(false))}\n maxWidth=\"xs\"\n fullWidth\n >\n <DialogTitle>{'Generate a section with AI'}</DialogTitle>\n <DialogContent\n sx={{ display: 'flex', flexDirection: 'column', gap: 2, pt: 1 }}\n >\n <Typography variant=\"body2\" color=\"text.secondary\">\n {'Describe the section — e.g. \"hero with headline, subtext, ' +\n 'and a call-to-action button\" or \"three-column feature grid\".'}\n </Typography>\n <TextField\n label=\"Section\"\n value={sectionPrompt}\n onChange={(event) => setSectionPrompt(event.target.value)}\n size=\"small\"\n autoFocus\n multiline\n minRows={2}\n disabled={busy}\n onKeyDown={(event) => {\n if (event.key === 'Enter' && (event.metaKey || event.ctrlKey)) {\n event.preventDefault()\n handleSectionConfirm()\n }\n }}\n />\n <AiModelSelector choice={sectionModel} disabled={busy} />\n <AiUsageStrip orgId={orgId} />\n </DialogContent>\n <DialogActions>\n <Button disabled={busy} onClick={() => setSectionOpen(false)}>\n {'Cancel'}\n </Button>\n <Button\n variant=\"contained\"\n color=\"primary\"\n disabled={!sectionPrompt.trim() || busy}\n startIcon={busy ? <CircularProgress size={16} /> : undefined}\n onClick={handleSectionConfirm}\n >\n {busy ? 'Generating…' : 'Generate'}\n </Button>\n </DialogActions>\n </Dialog>\n </AiAssistActionsContext.Provider>\n )\n}\nAiAssistProvider.displayName = 'AiAssistProvider'\n\nexport default AiAssistProvider\n"],"names":["Aglyn","checkEntitlement","lockdownRefusalText","parseLockdownRefusal","portableDefinitionToNested","AiAssistActionsContext","assistNotOnPlanText","useSnackbar","Button","CircularProgress","Dialog","DialogActions","DialogContent","DialogTitle","MenuItem","TextField","Typography","useCallback","useMemo","useState","useUser","authorizedFetch","AiModelSelector","AiUsageStrip","useAiModelChoice","usePublishAiUsageMeter","PERMISSIONS_PENDING","AI_USE_REFUSED","AI_GENERATE_REFUSED","AiAssistProvider","props","textTargets","org","orgReady","orgId","hostId","aiPermissions","children","enqueueSnackbar","data","user","node","setNode","instruction","setInstruction","targetProp","setTargetProp","busy","setBusy","sectionOpen","setSectionOpen","sectionPrompt","setSectionPrompt","copyModel","surface","kind","sectionModel","publishMeter","schema","componentSchema","textEditable","flags","FEATURE_FLAG","DISABLED","ENABLED","attributes","filter","field","component","FieldComponentType","TEXT_FIELD","TEXTAREA","map","prop","String","name","label","handleRewrite","target","loaded","variant","persist","use","effectiveTarget","some","item","handleConfirm","trim","current","canvas","toJSON","nodes","$id","text","response","method","headers","body","JSON","stringify","model","payload","json","meter","locked","status","ok","error","allowDuplicate","updateNodeProps","html","undefined","console","handleGenerateSection","generate","handleSectionConfirm","mode","section","rootId","nested","stamped","stamp","components","getSchema","componentId","pluginId","addNodeFromPreset","type","NodeType","PRESET","rootNode","refusedUse","refusedGenerate","contextValue","onRewrite","onGenerateSection","Provider","value","open","Boolean","onClose","maxWidth","fullWidth","sx","display","flexDirection","gap","pt","color","length","select","onChange","event","size","disabled","placeholder","autoFocus","multiline","minRows","onKeyDown","key","metaKey","ctrlKey","preventDefault","choice","onClick","startIcon","displayName"],"mappings":"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"}
1
+ {"version":3,"sources":["../../../../../../../libs/plugins/ai/src/lib/components/ai-assist-provider.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 {\n canvas,\n checkEntitlement,\n components,\n FEATURE_FLAG,\n FieldComponentType,\n lockdownRefusalText,\n NodeType,\n parseLockdownRefusal,\n type NodeSchema,\n} from '@aglyn/aglyn'\nimport { portableDefinitionToNested } from '@aglyn/aglyn/app-utils/node-definition-sanitizer'\nimport { AiAssistActionsContext } from './ai-assist-actions-context'\nimport { assistNotOnPlanText } from '../usage/assist-credits'\nimport { useSnackbar } from '@aglyn/shared-ui-snackstack'\nimport {\n Button,\n CircularProgress,\n Dialog,\n DialogActions,\n DialogContent,\n DialogTitle,\n MenuItem,\n TextField,\n Typography,\n} from '@mui/material'\nimport { useCallback, useMemo, useState } from 'react'\nimport { useUser } from '@aglyn/tenant-feature-instance'\nimport { authorizedFetch } from '@aglyn/shared-util-http/authorized-token'\nimport { AiModelSelector } from './ai-model-selector.component'\nimport { AiUsageStrip } from './ai-usage-strip.component'\nimport { useAiModelChoice } from './use-ai-model-choice'\nimport { usePublishAiUsageMeter } from './use-ai-usage-meter'\n\n\nexport interface AiAssistProviderProps {\n /** Org billing doc for the entitlement gate (mounted by the shell). */\n org?: unknown\n /**\n * True once `org` is a trustworthy answer (AGL-1380). The shell mounts\n * this provider above the whole console route tree, so it cannot hold its\n * render until the billing doc settles the way the plugin-page route does\n * — and an undefined `org` is not \"unknown\" to `checkEntitlement`, it is\n * the free tier. Without this flag the gates below told a Pro org that AI\n * assist is not on its plan for as long as the read was in flight.\n */\n orgReady?: boolean\n /**\n * The org every assist call is metered against (AGL-2073). The route no\n * longer resolves it from the signed-in user — a user with one paid org was\n * getting assist on all of their free ones, and their spend was landing on\n * whichever org the server happened to resolve.\n */\n orgId?: string\n /**\n * The site the canvas belongs to (AGL-2927), sent with every assist call\n * so the door can decide a site collaborator's permission on THAT site.\n * Null off a host route, where there is no canvas to assist on.\n */\n hostId?: string | null\n /**\n * The reader's AI verdict, resolved by the shell (AGL-2927). The gates\n * below HOLD until `loaded` — a door opened on a pending answer would\n * spend the workspace's credits on a permission nobody has confirmed —\n * and a refused key removes its callback from the context, so the\n * designer draws no control for it. Omitted, the answer is pending.\n */\n aiPermissions?: { loaded: boolean; use: boolean; generate: boolean }\n children?: JSX.Children\n}\n\nconst PERMISSIONS_PENDING = 'Checking your permissions — try again in a moment'\nconst AI_USE_REFUSED =\n 'Your role does not include AI assistance — ask an organization admin'\nconst AI_GENERATE_REFUSED =\n 'Your role does not include AI generation — ask an organization admin'\n\n/**\n * Console-side AI copy assist (AGL-89): provides the designer's \"Rewrite\n * with AI\" callback, hosts the instruction dialog, and calls the assist API\n * (which 501-degrades when no AI provider is configured). The commit\n * spreads the node's current props — `updateNodeProps` REPLACES the props\n * object — and clears any stale rich-text `html` so the new text renders.\n */\nexport function AiAssistProvider(props: AiAssistProviderProps) {\n const org = props.org\n const orgReady = props.orgReady\n const orgId = props.orgId\n const hostId = props.hostId ?? null\n const aiPermissions = props.aiPermissions\n const { children } = props\n const { enqueueSnackbar } = useSnackbar()\n const { data: user } = useUser()\n const [node, setNode] = useState<NodeSchema<any> | null>(null)\n const [instruction, setInstruction] = useState('')\n // Rewrite target (AGL-130): 'children' for text-editable elements, or\n // any text attribute the element's schema declares (alt text, labels…).\n const [targetProp, setTargetProp] = useState('children')\n const [busy, setBusy] = useState(false)\n // Generate section (AGL-169).\n const [sectionOpen, setSectionOpen] = useState(false)\n const [sectionPrompt, setSectionPrompt] = useState('')\n // The model switch and the usage strip in both dialogs (AGL-2942). Each\n // dialog remembers its own pick; one envelope store serves both strips\n // and the assistant panel's.\n const copyModel = useAiModelChoice({ orgId, hostId, surface: 'copy', kind: 'copy.element' })\n const sectionModel = useAiModelChoice({\n orgId,\n hostId,\n surface: 'section',\n kind: 'copy.section',\n })\n const publishMeter = usePublishAiUsageMeter(orgId)\n\n const textTargets = useMemo(() => {\n const schema = node?.componentSchema\n const textEditable =\n ((schema?.flags?.textEditable ?? FEATURE_FLAG.DISABLED) &\n FEATURE_FLAG.ENABLED) !==\n 0\n const attributes = (schema?.attributes ?? [])\n .filter(\n (field: any) =>\n field.component === FieldComponentType.TEXT_FIELD ||\n field.component === FieldComponentType.TEXTAREA,\n )\n .map((field: any) => ({\n prop: String(field.name),\n label: String(field.label ?? field.name),\n }))\n return textEditable\n ? [{ prop: 'children', label: 'Element text' }, ...attributes]\n : attributes\n }, [node])\n\n const handleRewrite = useCallback(\n (target: NodeSchema<any>) => {\n // The permission first (AGL-2927): it is a fact about the reader, and\n // pending asserts nothing here either. The refusal is unreachable\n // through the designer — a refused key publishes no callback — and\n // stands for any other caller of the context.\n if (!aiPermissions?.loaded) {\n return void enqueueSnackbar(PERMISSIONS_PENDING, {\n variant: 'info',\n persist: false,\n })\n }\n if (!aiPermissions.use) {\n return void enqueueSnackbar(AI_USE_REFUSED, {\n variant: 'warning',\n persist: false,\n })\n }\n // AGL-1380: pending asserts nothing. See `orgReady` on the props.\n if (!orgReady) {\n return void enqueueSnackbar(\n 'Checking your plan — try again in a moment',\n { variant: 'info', persist: false },\n )\n }\n if (!checkEntitlement(org as never, 'aiAssist')) {\n return void enqueueSnackbar(assistNotOnPlanText(), {\n variant: 'warning',\n persist: false,\n })\n }\n setInstruction('')\n setTargetProp('children')\n setNode(target)\n },\n [org, orgReady, aiPermissions, enqueueSnackbar],\n )\n\n // Keep the target valid for the selected element.\n const effectiveTarget = textTargets.some((item) => item.prop === targetProp)\n ? targetProp\n : (textTargets[0]?.prop ?? 'children')\n\n const handleConfirm = useCallback(async () => {\n if (!node || !instruction.trim() || busy) return\n setBusy(true)\n try {\n const current = (canvas.toJSON().nodes as Record<string, any>)[\n node.$id\n ]\n const text =\n typeof current?.props?.[effectiveTarget] === 'string'\n ? (current.props[effectiveTarget] as string)\n : ''\n const response = await authorizedFetch(user, '/api/ai/assist', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n orgId,\n hostId,\n text,\n instruction: instruction.trim(),\n ...(copyModel.model ? { model: copyModel.model } : {}),\n }),\n })\n const payload = await response.json()\n publishMeter(payload?.meter)\n // An ai-assist feature lockdown (AGL-1510/1532) reads as a pause, not\n // as \"AI request failed\" — a provider incident or a cost runaway is\n // something WE turned off, and saying so keeps the user's content out\n // of the story.\n const locked = parseLockdownRefusal(response.status, payload)\n if (locked) {\n return void enqueueSnackbar(lockdownRefusalText(locked), {\n variant: 'warning',\n persist: true,\n })\n }\n if (response.status === 501) {\n return void enqueueSnackbar(\n 'AI assist is not configured on this deployment',\n { variant: 'info', persist: false },\n )\n }\n if (!response.ok || !payload?.text) {\n return void enqueueSnackbar(payload?.error ?? 'AI request failed', {\n variant: 'error',\n allowDuplicate: true,\n })\n }\n canvas.updateNodeProps(node, {\n ...current?.props,\n [effectiveTarget]: payload.text,\n // Rich-text elements render `html` over `children`; drop it so the\n // rewrite is what shows (the user can re-format inline afterwards).\n ...(effectiveTarget === 'children' ? { html: undefined } : {}),\n })\n setNode(null)\n enqueueSnackbar('Text rewritten — undo restores the original', {\n variant: 'success',\n persist: false,\n })\n } catch (error) {\n console.error(error)\n enqueueSnackbar('An error has occurred', {\n variant: 'error',\n allowDuplicate: true,\n })\n } finally {\n setBusy(false)\n }\n }, [\n node,\n instruction,\n busy,\n user,\n effectiveTarget,\n orgId,\n hostId,\n copyModel.model,\n publishMeter,\n enqueueSnackbar,\n ])\n\n const handleGenerateSection = useCallback(() => {\n // The permission first (AGL-2927) — a section is a generation, so this\n // door sells under `ai.generate`; see `handleRewrite`.\n if (!aiPermissions?.loaded) {\n return void enqueueSnackbar(PERMISSIONS_PENDING, {\n variant: 'info',\n persist: false,\n })\n }\n if (!aiPermissions.generate) {\n return void enqueueSnackbar(AI_GENERATE_REFUSED, {\n variant: 'warning',\n persist: false,\n })\n }\n // AGL-1380: same gate as `handleRewrite`.\n if (!orgReady) {\n return void enqueueSnackbar('Checking your plan — try again in a moment', {\n variant: 'info',\n persist: false,\n })\n }\n if (!checkEntitlement(org as never, 'aiAssist')) {\n return void enqueueSnackbar(assistNotOnPlanText(), {\n variant: 'warning',\n persist: false,\n })\n }\n setSectionPrompt('')\n setSectionOpen(true)\n }, [org, orgReady, aiPermissions, enqueueSnackbar])\n\n const handleSectionConfirm = useCallback(async () => {\n if (!sectionPrompt.trim() || busy) return\n setBusy(true)\n try {\n const response = await authorizedFetch(user, '/api/ai/assist', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n orgId,\n hostId,\n mode: 'section',\n instruction: sectionPrompt.trim(),\n ...(sectionModel.model ? { model: sectionModel.model } : {}),\n }),\n })\n const payload = await response.json()\n publishMeter(payload?.meter)\n // Same pause notice on the section-generation door (AGL-1532).\n const locked = parseLockdownRefusal(response.status, payload)\n if (locked) {\n return void enqueueSnackbar(lockdownRefusalText(locked), {\n variant: 'warning',\n persist: true,\n })\n }\n if (response.status === 501) {\n return void enqueueSnackbar(\n 'AI assist is not configured on this deployment',\n { variant: 'info', persist: false },\n )\n }\n if (!response.ok || !payload?.section?.rootId) {\n return void enqueueSnackbar(payload?.error ?? 'AI request failed', {\n variant: 'error',\n allowDuplicate: true,\n })\n }\n const nested = portableDefinitionToNested(\n payload.section.rootId,\n payload.section.nodes,\n )\n if (!nested) {\n return void enqueueSnackbar('AI returned an empty section', {\n variant: 'error',\n allowDuplicate: true,\n })\n }\n // Graft through the preset path: ids regenerate, history is saved,\n // and the subtree lands at the end of the canvas root.\n const stamped = (function stamp(node: any): any {\n const schema = components.getSchema(node.componentId)\n return {\n ...node,\n ...(schema?.pluginId ? { pluginId: schema.pluginId } : {}),\n nodes: (node.nodes ?? []).map(stamp),\n }\n })(nested)\n canvas.addNodeFromPreset(\n { type: NodeType.PRESET, data: stamped } as any,\n canvas.rootNode as any,\n )\n setSectionOpen(false)\n enqueueSnackbar('Section added — undo removes it', {\n variant: 'success',\n persist: false,\n })\n } catch (error) {\n console.error(error)\n enqueueSnackbar('An error has occurred', {\n variant: 'error',\n allowDuplicate: true,\n })\n } finally {\n setBusy(false)\n }\n }, [\n sectionPrompt,\n busy,\n user,\n orgId,\n hostId,\n sectionModel.model,\n publishMeter,\n enqueueSnackbar,\n ])\n\n // A REFUSED key publishes no callback (AGL-2927): the besigner controls\n // render only when the callback exists, so the refusal removes\n // the button rather than dimming it. A PENDING answer keeps both\n // callbacks, and each holds with a notice when pressed — a control that\n // vanishes and reappears while the read lands is worse than one that is\n // briefly inert (the `useHostRole` argument, applied here).\n const refusedUse = aiPermissions?.loaded === true && !aiPermissions.use\n const refusedGenerate =\n aiPermissions?.loaded === true && !aiPermissions.generate\n const contextValue = useMemo(\n () => ({\n ...(refusedUse ? {} : { onRewrite: handleRewrite }),\n ...(refusedGenerate ? {} : { onGenerateSection: handleGenerateSection }),\n }),\n [handleRewrite, handleGenerateSection, refusedUse, refusedGenerate],\n )\n\n return (\n <AiAssistActionsContext.Provider value={contextValue}>\n {children}\n <Dialog\n open={Boolean(node)}\n onClose={() => (busy ? null : setNode(null))}\n maxWidth=\"xs\"\n fullWidth\n >\n <DialogTitle>{'Rewrite with AI'}</DialogTitle>\n <DialogContent\n sx={{ display: 'flex', flexDirection: 'column', gap: 2, pt: 1 }}\n >\n <Typography variant=\"body2\" color=\"text.secondary\">\n {'Describe how the text should change — tone, length, message.'}\n </Typography>\n {textTargets.length > 1 ? (\n <TextField\n select\n label=\"Field\"\n value={effectiveTarget}\n onChange={(event) => setTargetProp(event.target.value)}\n size=\"small\"\n disabled={busy}\n >\n {textTargets.map((item) => (\n <MenuItem key={item.prop} value={item.prop}>\n {item.label}\n </MenuItem>\n ))}\n </TextField>\n ) : null}\n <TextField\n label=\"Instruction\"\n placeholder=\"e.g. Make it punchier and half as long\"\n value={instruction}\n onChange={(event) => setInstruction(event.target.value)}\n size=\"small\"\n autoFocus\n multiline\n minRows={2}\n disabled={busy}\n onKeyDown={(event) => {\n if (event.key === 'Enter' && (event.metaKey || event.ctrlKey)) {\n event.preventDefault()\n handleConfirm()\n }\n }}\n />\n <AiModelSelector choice={copyModel} disabled={busy} />\n <AiUsageStrip orgId={orgId} />\n </DialogContent>\n <DialogActions>\n <Button disabled={busy} onClick={() => setNode(null)}>\n {'Cancel'}\n </Button>\n <Button\n variant=\"contained\"\n color=\"primary\"\n disabled={!instruction.trim() || busy}\n startIcon={busy ? <CircularProgress size={16} /> : undefined}\n onClick={handleConfirm}\n >\n {busy ? 'Rewriting…' : 'Rewrite'}\n </Button>\n </DialogActions>\n </Dialog>\n <Dialog\n open={sectionOpen}\n onClose={() => (busy ? null : setSectionOpen(false))}\n maxWidth=\"xs\"\n fullWidth\n >\n <DialogTitle>{'Generate a section with AI'}</DialogTitle>\n <DialogContent\n sx={{ display: 'flex', flexDirection: 'column', gap: 2, pt: 1 }}\n >\n <Typography variant=\"body2\" color=\"text.secondary\">\n {'Describe the section — e.g. \"hero with headline, subtext, ' +\n 'and a call-to-action button\" or \"three-column feature grid\".'}\n </Typography>\n <TextField\n label=\"Section\"\n value={sectionPrompt}\n onChange={(event) => setSectionPrompt(event.target.value)}\n size=\"small\"\n autoFocus\n multiline\n minRows={2}\n disabled={busy}\n onKeyDown={(event) => {\n if (event.key === 'Enter' && (event.metaKey || event.ctrlKey)) {\n event.preventDefault()\n handleSectionConfirm()\n }\n }}\n />\n <AiModelSelector choice={sectionModel} disabled={busy} />\n <AiUsageStrip orgId={orgId} />\n </DialogContent>\n <DialogActions>\n <Button disabled={busy} onClick={() => setSectionOpen(false)}>\n {'Cancel'}\n </Button>\n <Button\n variant=\"contained\"\n color=\"primary\"\n disabled={!sectionPrompt.trim() || busy}\n startIcon={busy ? <CircularProgress size={16} /> : undefined}\n onClick={handleSectionConfirm}\n >\n {busy ? 'Generating…' : 'Generate'}\n </Button>\n </DialogActions>\n </Dialog>\n </AiAssistActionsContext.Provider>\n )\n}\nAiAssistProvider.displayName = 'AiAssistProvider'\n\nexport default AiAssistProvider\n"],"names":["canvas","checkEntitlement","components","FEATURE_FLAG","FieldComponentType","lockdownRefusalText","NodeType","parseLockdownRefusal","portableDefinitionToNested","AiAssistActionsContext","assistNotOnPlanText","useSnackbar","Button","CircularProgress","Dialog","DialogActions","DialogContent","DialogTitle","MenuItem","TextField","Typography","useCallback","useMemo","useState","useUser","authorizedFetch","AiModelSelector","AiUsageStrip","useAiModelChoice","usePublishAiUsageMeter","PERMISSIONS_PENDING","AI_USE_REFUSED","AI_GENERATE_REFUSED","AiAssistProvider","props","textTargets","org","orgReady","orgId","hostId","aiPermissions","children","enqueueSnackbar","data","user","node","setNode","instruction","setInstruction","targetProp","setTargetProp","busy","setBusy","sectionOpen","setSectionOpen","sectionPrompt","setSectionPrompt","copyModel","surface","kind","sectionModel","publishMeter","schema","componentSchema","textEditable","flags","DISABLED","ENABLED","attributes","filter","field","component","TEXT_FIELD","TEXTAREA","map","prop","String","name","label","handleRewrite","target","loaded","variant","persist","use","effectiveTarget","some","item","handleConfirm","trim","current","toJSON","nodes","$id","text","response","method","headers","body","JSON","stringify","model","payload","json","meter","locked","status","ok","error","allowDuplicate","updateNodeProps","html","undefined","console","handleGenerateSection","generate","handleSectionConfirm","mode","section","rootId","nested","stamped","stamp","getSchema","componentId","pluginId","addNodeFromPreset","type","PRESET","rootNode","refusedUse","refusedGenerate","contextValue","onRewrite","onGenerateSection","Provider","value","open","Boolean","onClose","maxWidth","fullWidth","sx","display","flexDirection","gap","pt","color","length","select","onChange","event","size","disabled","placeholder","autoFocus","multiline","minRows","onKeyDown","key","metaKey","ctrlKey","preventDefault","choice","onClick","startIcon","displayName"],"mappings":"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"}
@@ -146,6 +146,7 @@ export function AiJobFollow({ job: initial, orgId, orgSlug, user, intro, onOpenJ
146
146
  }),
147
147
  children: [
148
148
  /*#__PURE__*/ _jsxs(Stack, {
149
+ useFlexGap: true,
149
150
  direction: "row",
150
151
  spacing: 1,
151
152
  sx: {