@aglyn/plugins-ai 1.0.0-beta.143

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (717) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +25 -0
  3. package/package.json +60 -0
  4. package/src/index.d.ts +21 -0
  5. package/src/index.js +22 -0
  6. package/src/index.js.map +1 -0
  7. package/src/lib/activity/ai-activity-actions.d.ts +106 -0
  8. package/src/lib/activity/ai-activity-actions.js +209 -0
  9. package/src/lib/activity/ai-activity-actions.js.map +1 -0
  10. package/src/lib/activity/ai-activity.d.ts +219 -0
  11. package/src/lib/activity/ai-activity.js +251 -0
  12. package/src/lib/activity/ai-activity.js.map +1 -0
  13. package/src/lib/billing/ai-overage-charge.d.ts +102 -0
  14. package/src/lib/billing/ai-overage-charge.js +258 -0
  15. package/src/lib/billing/ai-overage-charge.js.map +1 -0
  16. package/src/lib/billing/ai-overage-close.d.ts +62 -0
  17. package/src/lib/billing/ai-overage-close.js +129 -0
  18. package/src/lib/billing/ai-overage-close.js.map +1 -0
  19. package/src/lib/billing/ai-overage-cutover.d.ts +63 -0
  20. package/src/lib/billing/ai-overage-cutover.js +114 -0
  21. package/src/lib/billing/ai-overage-cutover.js.map +1 -0
  22. package/src/lib/billing/ai-overage-events.d.ts +77 -0
  23. package/src/lib/billing/ai-overage-events.js +174 -0
  24. package/src/lib/billing/ai-overage-events.js.map +1 -0
  25. package/src/lib/billing/ai-overage-gate.d.ts +147 -0
  26. package/src/lib/billing/ai-overage-gate.js +177 -0
  27. package/src/lib/billing/ai-overage-gate.js.map +1 -0
  28. package/src/lib/billing/ai-overage-ledger.d.ts +135 -0
  29. package/src/lib/billing/ai-overage-ledger.js +278 -0
  30. package/src/lib/billing/ai-overage-ledger.js.map +1 -0
  31. package/src/lib/billing/ai-overage-standing-writes.d.ts +110 -0
  32. package/src/lib/billing/ai-overage-standing-writes.js +205 -0
  33. package/src/lib/billing/ai-overage-standing-writes.js.map +1 -0
  34. package/src/lib/billing/ai-overage-standing.d.ts +168 -0
  35. package/src/lib/billing/ai-overage-standing.js +215 -0
  36. package/src/lib/billing/ai-overage-standing.js.map +1 -0
  37. package/src/lib/billing/ai-overage-trigger.d.ts +30 -0
  38. package/src/lib/billing/ai-overage-trigger.js +76 -0
  39. package/src/lib/billing/ai-overage-trigger.js.map +1 -0
  40. package/src/lib/components/ai-allotment-editor.component.d.ts +40 -0
  41. package/src/lib/components/ai-allotment-editor.component.js +213 -0
  42. package/src/lib/components/ai-allotment-editor.component.js.map +1 -0
  43. package/src/lib/components/ai-assist-actions-context.d.ts +13 -0
  44. package/src/lib/components/ai-assist-actions-context.js +21 -0
  45. package/src/lib/components/ai-assist-actions-context.js.map +1 -0
  46. package/src/lib/components/ai-assist-provider.component.d.ts +51 -0
  47. package/src/lib/components/ai-assist-provider.component.js +519 -0
  48. package/src/lib/components/ai-assist-provider.component.js.map +1 -0
  49. package/src/lib/components/ai-brief-dialog.component.d.ts +56 -0
  50. package/src/lib/components/ai-brief-dialog.component.js +319 -0
  51. package/src/lib/components/ai-brief-dialog.component.js.map +1 -0
  52. package/src/lib/components/ai-collaborator-permissions-column.component.d.ts +32 -0
  53. package/src/lib/components/ai-collaborator-permissions-column.component.js +132 -0
  54. package/src/lib/components/ai-collaborator-permissions-column.component.js.map +1 -0
  55. package/src/lib/components/ai-credits-card.component.d.ts +34 -0
  56. package/src/lib/components/ai-credits-card.component.js +131 -0
  57. package/src/lib/components/ai-credits-card.component.js.map +1 -0
  58. package/src/lib/components/ai-credits-columns.component.d.ts +56 -0
  59. package/src/lib/components/ai-credits-columns.component.js +118 -0
  60. package/src/lib/components/ai-credits-columns.component.js.map +1 -0
  61. package/src/lib/components/ai-crm-email-draft.component.d.ts +17 -0
  62. package/src/lib/components/ai-crm-email-draft.component.js +159 -0
  63. package/src/lib/components/ai-crm-email-draft.component.js.map +1 -0
  64. package/src/lib/components/ai-crm-import-mapping.component.d.ts +20 -0
  65. package/src/lib/components/ai-crm-import-mapping.component.js +167 -0
  66. package/src/lib/components/ai-crm-import-mapping.component.js.map +1 -0
  67. package/src/lib/components/ai-crm-record-card.component.d.ts +27 -0
  68. package/src/lib/components/ai-crm-record-card.component.js +263 -0
  69. package/src/lib/components/ai-crm-record-card.component.js.map +1 -0
  70. package/src/lib/components/ai-describe-automation.component.d.ts +31 -0
  71. package/src/lib/components/ai-describe-automation.component.js +226 -0
  72. package/src/lib/components/ai-describe-automation.component.js.map +1 -0
  73. package/src/lib/components/ai-describe-button.component.d.ts +39 -0
  74. package/src/lib/components/ai-describe-button.component.js +87 -0
  75. package/src/lib/components/ai-describe-button.component.js.map +1 -0
  76. package/src/lib/components/ai-describe-page.component.d.ts +26 -0
  77. package/src/lib/components/ai-describe-page.component.js +18 -0
  78. package/src/lib/components/ai-describe-page.component.js.map +1 -0
  79. package/src/lib/components/ai-experiment-cards.component.d.ts +75 -0
  80. package/src/lib/components/ai-experiment-cards.component.js +573 -0
  81. package/src/lib/components/ai-experiment-cards.component.js.map +1 -0
  82. package/src/lib/components/ai-explain-automation.component.d.ts +31 -0
  83. package/src/lib/components/ai-explain-automation.component.js +265 -0
  84. package/src/lib/components/ai-explain-automation.component.js.map +1 -0
  85. package/src/lib/components/ai-insight-dialog.component.d.ts +37 -0
  86. package/src/lib/components/ai-insight-dialog.component.js +441 -0
  87. package/src/lib/components/ai-insight-dialog.component.js.map +1 -0
  88. package/src/lib/components/ai-job-plan.component.d.ts +46 -0
  89. package/src/lib/components/ai-job-plan.component.js +192 -0
  90. package/src/lib/components/ai-job-plan.component.js.map +1 -0
  91. package/src/lib/components/ai-model-selector.component.d.ts +21 -0
  92. package/src/lib/components/ai-model-selector.component.js +109 -0
  93. package/src/lib/components/ai-model-selector.component.js.map +1 -0
  94. package/src/lib/components/ai-page-brief-dialog.component.d.ts +29 -0
  95. package/src/lib/components/ai-page-brief-dialog.component.js +27 -0
  96. package/src/lib/components/ai-page-brief-dialog.component.js.map +1 -0
  97. package/src/lib/components/ai-permissions-on-host.component.d.ts +55 -0
  98. package/src/lib/components/ai-permissions-on-host.component.js +91 -0
  99. package/src/lib/components/ai-permissions-on-host.component.js.map +1 -0
  100. package/src/lib/components/ai-product-copy-card.component.d.ts +25 -0
  101. package/src/lib/components/ai-product-copy-card.component.js +328 -0
  102. package/src/lib/components/ai-product-copy-card.component.js.map +1 -0
  103. package/src/lib/components/ai-product-import-option.component.d.ts +14 -0
  104. package/src/lib/components/ai-product-import-option.component.js +58 -0
  105. package/src/lib/components/ai-product-import-option.component.js.map +1 -0
  106. package/src/lib/components/ai-products-hub-card.component.d.ts +15 -0
  107. package/src/lib/components/ai-products-hub-card.component.js +418 -0
  108. package/src/lib/components/ai-products-hub-card.component.js.map +1 -0
  109. package/src/lib/components/ai-products-proposals.component.d.ts +19 -0
  110. package/src/lib/components/ai-products-proposals.component.js +547 -0
  111. package/src/lib/components/ai-products-proposals.component.js.map +1 -0
  112. package/src/lib/components/ai-save-as-component.component.d.ts +38 -0
  113. package/src/lib/components/ai-save-as-component.component.js +231 -0
  114. package/src/lib/components/ai-save-as-component.component.js.map +1 -0
  115. package/src/lib/components/ai-seo-audit-card.component.d.ts +9 -0
  116. package/src/lib/components/ai-seo-audit-card.component.js +620 -0
  117. package/src/lib/components/ai-seo-audit-card.component.js.map +1 -0
  118. package/src/lib/components/ai-seo-fields-card.component.d.ts +10 -0
  119. package/src/lib/components/ai-seo-fields-card.component.js +453 -0
  120. package/src/lib/components/ai-seo-fields-card.component.js.map +1 -0
  121. package/src/lib/components/ai-site-batch-card.component.d.ts +32 -0
  122. package/src/lib/components/ai-site-batch-card.component.js +531 -0
  123. package/src/lib/components/ai-site-batch-card.component.js.map +1 -0
  124. package/src/lib/components/ai-site-seo-start-card.component.d.ts +26 -0
  125. package/src/lib/components/ai-site-seo-start-card.component.js +178 -0
  126. package/src/lib/components/ai-site-seo-start-card.component.js.map +1 -0
  127. package/src/lib/components/ai-site-start-card.component.d.ts +19 -0
  128. package/src/lib/components/ai-site-start-card.component.js +348 -0
  129. package/src/lib/components/ai-site-start-card.component.js.map +1 -0
  130. package/src/lib/components/ai-template-collection-field.component.d.ts +32 -0
  131. package/src/lib/components/ai-template-collection-field.component.js +63 -0
  132. package/src/lib/components/ai-template-collection-field.component.js.map +1 -0
  133. package/src/lib/components/ai-theme-proposal-card.component.d.ts +6 -0
  134. package/src/lib/components/ai-theme-proposal-card.component.js +619 -0
  135. package/src/lib/components/ai-theme-proposal-card.component.js.map +1 -0
  136. package/src/lib/components/ai-usage-strip.component.d.ts +27 -0
  137. package/src/lib/components/ai-usage-strip.component.js +145 -0
  138. package/src/lib/components/ai-usage-strip.component.js.map +1 -0
  139. package/src/lib/components/assist-edit-canvas.d.ts +169 -0
  140. package/src/lib/components/assist-edit-canvas.js +636 -0
  141. package/src/lib/components/assist-edit-canvas.js.map +1 -0
  142. package/src/lib/components/assist-edit-card.component.d.ts +16 -0
  143. package/src/lib/components/assist-edit-card.component.js +181 -0
  144. package/src/lib/components/assist-edit-card.component.js.map +1 -0
  145. package/src/lib/components/assist-jobs-drawer.component.d.ts +72 -0
  146. package/src/lib/components/assist-jobs-drawer.component.js +626 -0
  147. package/src/lib/components/assist-jobs-drawer.component.js.map +1 -0
  148. package/src/lib/components/assist-panel.component.d.ts +136 -0
  149. package/src/lib/components/assist-panel.component.js +1099 -0
  150. package/src/lib/components/assist-panel.component.js.map +1 -0
  151. package/src/lib/components/assist-signals-page.component.d.ts +3 -0
  152. package/src/lib/components/assist-signals-page.component.js +1017 -0
  153. package/src/lib/components/assist-signals-page.component.js.map +1 -0
  154. package/src/lib/components/besigner-ai-controls.component.d.ts +29 -0
  155. package/src/lib/components/besigner-ai-controls.component.js +81 -0
  156. package/src/lib/components/besigner-ai-controls.component.js.map +1 -0
  157. package/src/lib/components/billing-ai-allotments.component.d.ts +36 -0
  158. package/src/lib/components/billing-ai-allotments.component.js +486 -0
  159. package/src/lib/components/billing-ai-allotments.component.js.map +1 -0
  160. package/src/lib/components/billing-ai-top-users.component.d.ts +44 -0
  161. package/src/lib/components/billing-ai-top-users.component.js +304 -0
  162. package/src/lib/components/billing-ai-top-users.component.js.map +1 -0
  163. package/src/lib/components/billing-assist-overage-card.component.d.ts +69 -0
  164. package/src/lib/components/billing-assist-overage-card.component.js +437 -0
  165. package/src/lib/components/billing-assist-overage-card.component.js.map +1 -0
  166. package/src/lib/components/host-ai-allotments.component.d.ts +40 -0
  167. package/src/lib/components/host-ai-allotments.component.js +239 -0
  168. package/src/lib/components/host-ai-allotments.component.js.map +1 -0
  169. package/src/lib/components/member-ai-allotment-card.component.d.ts +28 -0
  170. package/src/lib/components/member-ai-allotment-card.component.js +172 -0
  171. package/src/lib/components/member-ai-allotment-card.component.js.map +1 -0
  172. package/src/lib/components/member-ai-usage-card.component.d.ts +28 -0
  173. package/src/lib/components/member-ai-usage-card.component.js +240 -0
  174. package/src/lib/components/member-ai-usage-card.component.js.map +1 -0
  175. package/src/lib/components/staff-org-ai-card.component.d.ts +17 -0
  176. package/src/lib/components/staff-org-ai-card.component.js +739 -0
  177. package/src/lib/components/staff-org-ai-card.component.js.map +1 -0
  178. package/src/lib/components/staff-org-usage-ai-columns.component.d.ts +41 -0
  179. package/src/lib/components/staff-org-usage-ai-columns.component.js +65 -0
  180. package/src/lib/components/staff-org-usage-ai-columns.component.js.map +1 -0
  181. package/src/lib/components/staff-orgs-ai-spend-column.component.d.ts +28 -0
  182. package/src/lib/components/staff-orgs-ai-spend-column.component.js +89 -0
  183. package/src/lib/components/staff-orgs-ai-spend-column.component.js.map +1 -0
  184. package/src/lib/components/staff-user-ai-usage-card.component.d.ts +27 -0
  185. package/src/lib/components/staff-user-ai-usage-card.component.js +183 -0
  186. package/src/lib/components/staff-user-ai-usage-card.component.js.map +1 -0
  187. package/src/lib/components/use-ai-allotments.d.ts +49 -0
  188. package/src/lib/components/use-ai-allotments.js +171 -0
  189. package/src/lib/components/use-ai-allotments.js.map +1 -0
  190. package/src/lib/components/use-ai-crm-answer.d.ts +50 -0
  191. package/src/lib/components/use-ai-crm-answer.js +220 -0
  192. package/src/lib/components/use-ai-crm-answer.js.map +1 -0
  193. package/src/lib/components/use-ai-job-run.d.ts +51 -0
  194. package/src/lib/components/use-ai-job-run.js +176 -0
  195. package/src/lib/components/use-ai-job-run.js.map +1 -0
  196. package/src/lib/components/use-ai-model-choice.d.ts +47 -0
  197. package/src/lib/components/use-ai-model-choice.js +150 -0
  198. package/src/lib/components/use-ai-model-choice.js.map +1 -0
  199. package/src/lib/components/use-ai-products-jobs.d.ts +36 -0
  200. package/src/lib/components/use-ai-products-jobs.js +190 -0
  201. package/src/lib/components/use-ai-products-jobs.js.map +1 -0
  202. package/src/lib/components/use-ai-usage-meter.d.ts +11 -0
  203. package/src/lib/components/use-ai-usage-meter.js +96 -0
  204. package/src/lib/components/use-ai-usage-meter.js.map +1 -0
  205. package/src/lib/components/use-org-ai-usage.d.ts +42 -0
  206. package/src/lib/components/use-org-ai-usage.js +181 -0
  207. package/src/lib/components/use-org-ai-usage.js.map +1 -0
  208. package/src/lib/components/use-staff-orgs-ai-spend.d.ts +18 -0
  209. package/src/lib/components/use-staff-orgs-ai-spend.js +127 -0
  210. package/src/lib/components/use-staff-orgs-ai-spend.js.map +1 -0
  211. package/src/lib/constants.d.ts +24 -0
  212. package/src/lib/constants.js +23 -0
  213. package/src/lib/constants.js.map +1 -0
  214. package/src/lib/declarations.d.ts +48 -0
  215. package/src/lib/declarations.js +129 -0
  216. package/src/lib/declarations.js.map +1 -0
  217. package/src/lib/declarations.server.d.ts +35 -0
  218. package/src/lib/declarations.server.js +138 -0
  219. package/src/lib/declarations.server.js.map +1 -0
  220. package/src/lib/insights/ai-figure-readers.d.ts +90 -0
  221. package/src/lib/insights/ai-figure-readers.js +863 -0
  222. package/src/lib/insights/ai-figure-readers.js.map +1 -0
  223. package/src/lib/insights/ai-insight-digest.d.ts +165 -0
  224. package/src/lib/insights/ai-insight-digest.js +363 -0
  225. package/src/lib/insights/ai-insight-digest.js.map +1 -0
  226. package/src/lib/insights/ai-insight-readers.d.ts +71 -0
  227. package/src/lib/insights/ai-insight-readers.js +141 -0
  228. package/src/lib/insights/ai-insight-readers.js.map +1 -0
  229. package/src/lib/jobs/ai-crm-access.d.ts +61 -0
  230. package/src/lib/jobs/ai-crm-access.js +94 -0
  231. package/src/lib/jobs/ai-crm-access.js.map +1 -0
  232. package/src/lib/jobs/ai-email-bindings.d.ts +97 -0
  233. package/src/lib/jobs/ai-email-bindings.js +147 -0
  234. package/src/lib/jobs/ai-email-bindings.js.map +1 -0
  235. package/src/lib/jobs/ai-job-admission.d.ts +82 -0
  236. package/src/lib/jobs/ai-job-admission.js +45 -0
  237. package/src/lib/jobs/ai-job-admission.js.map +1 -0
  238. package/src/lib/jobs/ai-job-budget.d.ts +167 -0
  239. package/src/lib/jobs/ai-job-budget.js +161 -0
  240. package/src/lib/jobs/ai-job-budget.js.map +1 -0
  241. package/src/lib/jobs/ai-job-campaign-step.d.ts +108 -0
  242. package/src/lib/jobs/ai-job-campaign-step.js +340 -0
  243. package/src/lib/jobs/ai-job-campaign-step.js.map +1 -0
  244. package/src/lib/jobs/ai-job-component-checks.d.ts +74 -0
  245. package/src/lib/jobs/ai-job-component-checks.js +442 -0
  246. package/src/lib/jobs/ai-job-component-checks.js.map +1 -0
  247. package/src/lib/jobs/ai-job-component-step.d.ts +75 -0
  248. package/src/lib/jobs/ai-job-component-step.js +262 -0
  249. package/src/lib/jobs/ai-job-component-step.js.map +1 -0
  250. package/src/lib/jobs/ai-job-crm-step.d.ts +192 -0
  251. package/src/lib/jobs/ai-job-crm-step.js +734 -0
  252. package/src/lib/jobs/ai-job-crm-step.js.map +1 -0
  253. package/src/lib/jobs/ai-job-draft-ids.d.ts +62 -0
  254. package/src/lib/jobs/ai-job-draft-ids.js +132 -0
  255. package/src/lib/jobs/ai-job-draft-ids.js.map +1 -0
  256. package/src/lib/jobs/ai-job-drafts.d.ts +304 -0
  257. package/src/lib/jobs/ai-job-drafts.js +557 -0
  258. package/src/lib/jobs/ai-job-drafts.js.map +1 -0
  259. package/src/lib/jobs/ai-job-email-step.d.ts +195 -0
  260. package/src/lib/jobs/ai-job-email-step.js +547 -0
  261. package/src/lib/jobs/ai-job-email-step.js.map +1 -0
  262. package/src/lib/jobs/ai-job-experiment-step.d.ts +105 -0
  263. package/src/lib/jobs/ai-job-experiment-step.js +445 -0
  264. package/src/lib/jobs/ai-job-experiment-step.js.map +1 -0
  265. package/src/lib/jobs/ai-job-form-step.d.ts +250 -0
  266. package/src/lib/jobs/ai-job-form-step.js +634 -0
  267. package/src/lib/jobs/ai-job-form-step.js.map +1 -0
  268. package/src/lib/jobs/ai-job-generation.d.ts +114 -0
  269. package/src/lib/jobs/ai-job-generation.js +384 -0
  270. package/src/lib/jobs/ai-job-generation.js.map +1 -0
  271. package/src/lib/jobs/ai-job-insight-budget.d.ts +41 -0
  272. package/src/lib/jobs/ai-job-insight-budget.js +46 -0
  273. package/src/lib/jobs/ai-job-insight-budget.js.map +1 -0
  274. package/src/lib/jobs/ai-job-insight-step.d.ts +58 -0
  275. package/src/lib/jobs/ai-job-insight-step.js +350 -0
  276. package/src/lib/jobs/ai-job-insight-step.js.map +1 -0
  277. package/src/lib/jobs/ai-job-layout-step.d.ts +103 -0
  278. package/src/lib/jobs/ai-job-layout-step.js +340 -0
  279. package/src/lib/jobs/ai-job-layout-step.js.map +1 -0
  280. package/src/lib/jobs/ai-job-page-budget.d.ts +57 -0
  281. package/src/lib/jobs/ai-job-page-budget.js +60 -0
  282. package/src/lib/jobs/ai-job-page-budget.js.map +1 -0
  283. package/src/lib/jobs/ai-job-page-sections.d.ts +150 -0
  284. package/src/lib/jobs/ai-job-page-sections.js +450 -0
  285. package/src/lib/jobs/ai-job-page-sections.js.map +1 -0
  286. package/src/lib/jobs/ai-job-page-step.d.ts +198 -0
  287. package/src/lib/jobs/ai-job-page-step.js +667 -0
  288. package/src/lib/jobs/ai-job-page-step.js.map +1 -0
  289. package/src/lib/jobs/ai-job-plan-conformance.d.ts +107 -0
  290. package/src/lib/jobs/ai-job-plan-conformance.js +164 -0
  291. package/src/lib/jobs/ai-job-plan-conformance.js.map +1 -0
  292. package/src/lib/jobs/ai-job-plan-step.d.ts +196 -0
  293. package/src/lib/jobs/ai-job-plan-step.js +458 -0
  294. package/src/lib/jobs/ai-job-plan-step.js.map +1 -0
  295. package/src/lib/jobs/ai-job-plugin-drafts.d.ts +76 -0
  296. package/src/lib/jobs/ai-job-plugin-drafts.js +91 -0
  297. package/src/lib/jobs/ai-job-plugin-drafts.js.map +1 -0
  298. package/src/lib/jobs/ai-job-products-step.d.ts +106 -0
  299. package/src/lib/jobs/ai-job-products-step.js +436 -0
  300. package/src/lib/jobs/ai-job-products-step.js.map +1 -0
  301. package/src/lib/jobs/ai-job-seo-budget.d.ts +52 -0
  302. package/src/lib/jobs/ai-job-seo-budget.js +63 -0
  303. package/src/lib/jobs/ai-job-seo-budget.js.map +1 -0
  304. package/src/lib/jobs/ai-job-seo-step.d.ts +145 -0
  305. package/src/lib/jobs/ai-job-seo-step.js +809 -0
  306. package/src/lib/jobs/ai-job-seo-step.js.map +1 -0
  307. package/src/lib/jobs/ai-job-site-step.d.ts +252 -0
  308. package/src/lib/jobs/ai-job-site-step.js +538 -0
  309. package/src/lib/jobs/ai-job-site-step.js.map +1 -0
  310. package/src/lib/jobs/ai-job-template-step.d.ts +105 -0
  311. package/src/lib/jobs/ai-job-template-step.js +391 -0
  312. package/src/lib/jobs/ai-job-template-step.js.map +1 -0
  313. package/src/lib/jobs/ai-job-text-step.d.ts +125 -0
  314. package/src/lib/jobs/ai-job-text-step.js +128 -0
  315. package/src/lib/jobs/ai-job-text-step.js.map +1 -0
  316. package/src/lib/jobs/ai-job-theme-budget.d.ts +38 -0
  317. package/src/lib/jobs/ai-job-theme-budget.js +43 -0
  318. package/src/lib/jobs/ai-job-theme-budget.js.map +1 -0
  319. package/src/lib/jobs/ai-job-theme-step.d.ts +115 -0
  320. package/src/lib/jobs/ai-job-theme-step.js +337 -0
  321. package/src/lib/jobs/ai-job-theme-step.js.map +1 -0
  322. package/src/lib/jobs/ai-job-workflow-step.d.ts +139 -0
  323. package/src/lib/jobs/ai-job-workflow-step.js +530 -0
  324. package/src/lib/jobs/ai-job-workflow-step.js.map +1 -0
  325. package/src/lib/jobs/ai-jobs-beat.d.ts +78 -0
  326. package/src/lib/jobs/ai-jobs-beat.js +93 -0
  327. package/src/lib/jobs/ai-jobs-beat.js.map +1 -0
  328. package/src/lib/jobs/ai-jobs-pause.d.ts +38 -0
  329. package/src/lib/jobs/ai-jobs-pause.js +45 -0
  330. package/src/lib/jobs/ai-jobs-pause.js.map +1 -0
  331. package/src/lib/jobs/ai-jobs.d.ts +558 -0
  332. package/src/lib/jobs/ai-jobs.js +1410 -0
  333. package/src/lib/jobs/ai-jobs.js.map +1 -0
  334. package/src/lib/jobs/ai-media-asset-server.d.ts +34 -0
  335. package/src/lib/jobs/ai-media-asset-server.js +34 -0
  336. package/src/lib/jobs/ai-media-asset-server.js.map +1 -0
  337. package/src/lib/jobs/ai-media-asset.d.ts +59 -0
  338. package/src/lib/jobs/ai-media-asset.js +86 -0
  339. package/src/lib/jobs/ai-media-asset.js.map +1 -0
  340. package/src/lib/jobs/ai-product-image.d.ts +78 -0
  341. package/src/lib/jobs/ai-product-image.js +113 -0
  342. package/src/lib/jobs/ai-product-image.js.map +1 -0
  343. package/src/lib/jobs/ai-theme-brand-inputs.d.ts +125 -0
  344. package/src/lib/jobs/ai-theme-brand-inputs.js +378 -0
  345. package/src/lib/jobs/ai-theme-brand-inputs.js.map +1 -0
  346. package/src/lib/jobs/ai-theme-brand-server.d.ts +33 -0
  347. package/src/lib/jobs/ai-theme-brand-server.js +33 -0
  348. package/src/lib/jobs/ai-theme-brand-server.js.map +1 -0
  349. package/src/lib/jobs/ai-workflow-records.d.ts +84 -0
  350. package/src/lib/jobs/ai-workflow-records.js +158 -0
  351. package/src/lib/jobs/ai-workflow-records.js.map +1 -0
  352. package/src/lib/jobs/fixtures/ai-free-page-built-recording.d.ts +31 -0
  353. package/src/lib/jobs/fixtures/ai-free-page-built-recording.js +367 -0
  354. package/src/lib/jobs/fixtures/ai-free-page-built-recording.js.map +1 -0
  355. package/src/lib/jobs/fixtures/ai-free-page-recording.d.ts +69 -0
  356. package/src/lib/jobs/fixtures/ai-free-page-recording.js +442 -0
  357. package/src/lib/jobs/fixtures/ai-free-page-recording.js.map +1 -0
  358. package/src/lib/jobs/fixtures/ai-page-briefs.d.ts +146 -0
  359. package/src/lib/jobs/fixtures/ai-page-briefs.js +1850 -0
  360. package/src/lib/jobs/fixtures/ai-page-briefs.js.map +1 -0
  361. package/src/lib/model/ai-allotments.d.ts +208 -0
  362. package/src/lib/model/ai-allotments.js +269 -0
  363. package/src/lib/model/ai-allotments.js.map +1 -0
  364. package/src/lib/model/ai-automation-draft.d.ts +74 -0
  365. package/src/lib/model/ai-automation-draft.js +310 -0
  366. package/src/lib/model/ai-automation-draft.js.map +1 -0
  367. package/src/lib/model/ai-automation-outline.d.ts +50 -0
  368. package/src/lib/model/ai-automation-outline.js +262 -0
  369. package/src/lib/model/ai-automation-outline.js.map +1 -0
  370. package/src/lib/model/ai-build-plan.d.ts +197 -0
  371. package/src/lib/model/ai-build-plan.js +438 -0
  372. package/src/lib/model/ai-build-plan.js.map +1 -0
  373. package/src/lib/model/ai-crm.d.ts +237 -0
  374. package/src/lib/model/ai-crm.js +225 -0
  375. package/src/lib/model/ai-crm.js.map +1 -0
  376. package/src/lib/model/ai-experiment-proposal.d.ts +68 -0
  377. package/src/lib/model/ai-experiment-proposal.js +146 -0
  378. package/src/lib/model/ai-experiment-proposal.js.map +1 -0
  379. package/src/lib/model/ai-experiment.d.ts +309 -0
  380. package/src/lib/model/ai-experiment.js +395 -0
  381. package/src/lib/model/ai-experiment.js.map +1 -0
  382. package/src/lib/model/ai-insight.d.ts +178 -0
  383. package/src/lib/model/ai-insight.js +201 -0
  384. package/src/lib/model/ai-insight.js.map +1 -0
  385. package/src/lib/model/ai-jobs.types.d.ts +412 -0
  386. package/src/lib/model/ai-jobs.types.js +42 -0
  387. package/src/lib/model/ai-jobs.types.js.map +1 -0
  388. package/src/lib/model/ai-page-job.d.ts +92 -0
  389. package/src/lib/model/ai-page-job.js +159 -0
  390. package/src/lib/model/ai-page-job.js.map +1 -0
  391. package/src/lib/model/ai-permissions.d.ts +49 -0
  392. package/src/lib/model/ai-permissions.js +97 -0
  393. package/src/lib/model/ai-permissions.js.map +1 -0
  394. package/src/lib/model/ai-plan-capabilities.d.ts +139 -0
  395. package/src/lib/model/ai-plan-capabilities.js +149 -0
  396. package/src/lib/model/ai-plan-capabilities.js.map +1 -0
  397. package/src/lib/model/ai-products.d.ts +251 -0
  398. package/src/lib/model/ai-products.js +253 -0
  399. package/src/lib/model/ai-products.js.map +1 -0
  400. package/src/lib/model/ai-seo.d.ts +208 -0
  401. package/src/lib/model/ai-seo.js +150 -0
  402. package/src/lib/model/ai-seo.js.map +1 -0
  403. package/src/lib/model/ai-site-inventory.d.ts +164 -0
  404. package/src/lib/model/ai-site-inventory.js +145 -0
  405. package/src/lib/model/ai-site-inventory.js.map +1 -0
  406. package/src/lib/model/ai-site-job.d.ts +247 -0
  407. package/src/lib/model/ai-site-job.js +314 -0
  408. package/src/lib/model/ai-site-job.js.map +1 -0
  409. package/src/lib/model/ai-site-start-seo.d.ts +103 -0
  410. package/src/lib/model/ai-site-start-seo.js +154 -0
  411. package/src/lib/model/ai-site-start-seo.js.map +1 -0
  412. package/src/lib/model/ai-site-start.d.ts +122 -0
  413. package/src/lib/model/ai-site-start.js +159 -0
  414. package/src/lib/model/ai-site-start.js.map +1 -0
  415. package/src/lib/model/ai-site-switch.d.ts +56 -0
  416. package/src/lib/model/ai-site-switch.js +73 -0
  417. package/src/lib/model/ai-site-switch.js.map +1 -0
  418. package/src/lib/model/ai-storefront-claims.d.ts +70 -0
  419. package/src/lib/model/ai-storefront-claims.js +130 -0
  420. package/src/lib/model/ai-storefront-claims.js.map +1 -0
  421. package/src/lib/model/ai-template-subjects.d.ts +82 -0
  422. package/src/lib/model/ai-template-subjects.js +136 -0
  423. package/src/lib/model/ai-template-subjects.js.map +1 -0
  424. package/src/lib/model/ai-theme-proposal.d.ts +210 -0
  425. package/src/lib/model/ai-theme-proposal.js +506 -0
  426. package/src/lib/model/ai-theme-proposal.js.map +1 -0
  427. package/src/lib/model/ai-tokens.d.ts +96 -0
  428. package/src/lib/model/ai-tokens.js +117 -0
  429. package/src/lib/model/ai-tokens.js.map +1 -0
  430. package/src/lib/model/ai-usage-by-user.d.ts +120 -0
  431. package/src/lib/model/ai-usage-by-user.js +139 -0
  432. package/src/lib/model/ai-usage-by-user.js.map +1 -0
  433. package/src/lib/model/ai-workflow-job.d.ts +111 -0
  434. package/src/lib/model/ai-workflow-job.js +183 -0
  435. package/src/lib/model/ai-workflow-job.js.map +1 -0
  436. package/src/lib/model/assist-edit.d.ts +261 -0
  437. package/src/lib/model/assist-edit.js +175 -0
  438. package/src/lib/model/assist-edit.js.map +1 -0
  439. package/src/lib/plugin-config.d.ts +33 -0
  440. package/src/lib/plugin-config.js +118 -0
  441. package/src/lib/plugin-config.js.map +1 -0
  442. package/src/lib/plugin.d.ts +30 -0
  443. package/src/lib/plugin.js +525 -0
  444. package/src/lib/plugin.js.map +1 -0
  445. package/src/lib/providers/anthropic.d.ts +84 -0
  446. package/src/lib/providers/anthropic.js +432 -0
  447. package/src/lib/providers/anthropic.js.map +1 -0
  448. package/src/lib/providers/catalog.d.ts +197 -0
  449. package/src/lib/providers/catalog.js +312 -0
  450. package/src/lib/providers/catalog.js.map +1 -0
  451. package/src/lib/providers/contract.d.ts +464 -0
  452. package/src/lib/providers/contract.js +274 -0
  453. package/src/lib/providers/contract.js.map +1 -0
  454. package/src/lib/providers/model-choice.d.ts +119 -0
  455. package/src/lib/providers/model-choice.js +416 -0
  456. package/src/lib/providers/model-choice.js.map +1 -0
  457. package/src/lib/providers/openai-compatible.d.ts +58 -0
  458. package/src/lib/providers/openai-compatible.js +361 -0
  459. package/src/lib/providers/openai-compatible.js.map +1 -0
  460. package/src/lib/providers/registry.d.ts +49 -0
  461. package/src/lib/providers/registry.js +71 -0
  462. package/src/lib/providers/registry.js.map +1 -0
  463. package/src/lib/providers/routing.d.ts +98 -0
  464. package/src/lib/providers/routing.js +450 -0
  465. package/src/lib/providers/routing.js.map +1 -0
  466. package/src/lib/runtime/ai-abuse-guards.d.ts +113 -0
  467. package/src/lib/runtime/ai-abuse-guards.js +148 -0
  468. package/src/lib/runtime/ai-abuse-guards.js.map +1 -0
  469. package/src/lib/runtime/ai-component-bindings.d.ts +67 -0
  470. package/src/lib/runtime/ai-component-bindings.js +106 -0
  471. package/src/lib/runtime/ai-component-bindings.js.map +1 -0
  472. package/src/lib/runtime/ai-device-audit.d.ts +109 -0
  473. package/src/lib/runtime/ai-device-audit.js +97 -0
  474. package/src/lib/runtime/ai-device-audit.js.map +1 -0
  475. package/src/lib/runtime/ai-doctrine-validators.d.ts +720 -0
  476. package/src/lib/runtime/ai-doctrine-validators.js +3133 -0
  477. package/src/lib/runtime/ai-doctrine-validators.js.map +1 -0
  478. package/src/lib/runtime/ai-doctrine.d.ts +372 -0
  479. package/src/lib/runtime/ai-doctrine.js +944 -0
  480. package/src/lib/runtime/ai-doctrine.js.map +1 -0
  481. package/src/lib/runtime/ai-eval-live.d.ts +321 -0
  482. package/src/lib/runtime/ai-eval-live.js +1257 -0
  483. package/src/lib/runtime/ai-eval-live.js.map +1 -0
  484. package/src/lib/runtime/ai-eval-memory-firestore.d.ts +51 -0
  485. package/src/lib/runtime/ai-eval-memory-firestore.js +183 -0
  486. package/src/lib/runtime/ai-eval-memory-firestore.js.map +1 -0
  487. package/src/lib/runtime/ai-eval.d.ts +441 -0
  488. package/src/lib/runtime/ai-eval.js +1151 -0
  489. package/src/lib/runtime/ai-eval.js.map +1 -0
  490. package/src/lib/runtime/ai-gate.d.ts +130 -0
  491. package/src/lib/runtime/ai-gate.js +272 -0
  492. package/src/lib/runtime/ai-gate.js.map +1 -0
  493. package/src/lib/runtime/ai-generation-bounds.d.ts +24 -0
  494. package/src/lib/runtime/ai-generation-bounds.js +23 -0
  495. package/src/lib/runtime/ai-generation-bounds.js.map +1 -0
  496. package/src/lib/runtime/ai-insight-check.d.ts +76 -0
  497. package/src/lib/runtime/ai-insight-check.js +281 -0
  498. package/src/lib/runtime/ai-insight-check.js.map +1 -0
  499. package/src/lib/runtime/ai-node-tree.d.ts +181 -0
  500. package/src/lib/runtime/ai-node-tree.js +931 -0
  501. package/src/lib/runtime/ai-node-tree.js.map +1 -0
  502. package/src/lib/runtime/ai-page-links.d.ts +79 -0
  503. package/src/lib/runtime/ai-page-links.js +135 -0
  504. package/src/lib/runtime/ai-page-links.js.map +1 -0
  505. package/src/lib/runtime/ai-palette.d.ts +252 -0
  506. package/src/lib/runtime/ai-palette.generated.d.ts +34 -0
  507. package/src/lib/runtime/ai-palette.generated.js +5263 -0
  508. package/src/lib/runtime/ai-palette.generated.js.map +1 -0
  509. package/src/lib/runtime/ai-palette.js +187 -0
  510. package/src/lib/runtime/ai-palette.js.map +1 -0
  511. package/src/lib/runtime/ai-products-generation.d.ts +107 -0
  512. package/src/lib/runtime/ai-products-generation.js +250 -0
  513. package/src/lib/runtime/ai-products-generation.js.map +1 -0
  514. package/src/lib/runtime/ai-repeated-items.d.ts +95 -0
  515. package/src/lib/runtime/ai-repeated-items.js +397 -0
  516. package/src/lib/runtime/ai-repeated-items.js.map +1 -0
  517. package/src/lib/runtime/ai-runtime.d.ts +148 -0
  518. package/src/lib/runtime/ai-runtime.js +237 -0
  519. package/src/lib/runtime/ai-runtime.js.map +1 -0
  520. package/src/lib/runtime/ai-template-examples.d.ts +71 -0
  521. package/src/lib/runtime/ai-template-examples.js +135 -0
  522. package/src/lib/runtime/ai-template-examples.js.map +1 -0
  523. package/src/lib/runtime/assist-answer-cache.d.ts +80 -0
  524. package/src/lib/runtime/assist-answer-cache.js +184 -0
  525. package/src/lib/runtime/assist-answer-cache.js.map +1 -0
  526. package/src/lib/runtime/seo-audit.d.ts +93 -0
  527. package/src/lib/runtime/seo-audit.js +260 -0
  528. package/src/lib/runtime/seo-audit.js.map +1 -0
  529. package/src/lib/runtime/seo-content-fixes.d.ts +41 -0
  530. package/src/lib/runtime/seo-content-fixes.js +168 -0
  531. package/src/lib/runtime/seo-content-fixes.js.map +1 -0
  532. package/src/lib/runtime/seo-fields.d.ts +152 -0
  533. package/src/lib/runtime/seo-fields.js +215 -0
  534. package/src/lib/runtime/seo-fields.js.map +1 -0
  535. package/src/lib/runtime/seo-page-facts.d.ts +61 -0
  536. package/src/lib/runtime/seo-page-facts.js +150 -0
  537. package/src/lib/runtime/seo-page-facts.js.map +1 -0
  538. package/src/lib/runtime/site-inventory.d.ts +63 -0
  539. package/src/lib/runtime/site-inventory.js +230 -0
  540. package/src/lib/runtime/site-inventory.js.map +1 -0
  541. package/src/lib/server/ai-admin-org.d.ts +33 -0
  542. package/src/lib/server/ai-admin-org.js +381 -0
  543. package/src/lib/server/ai-admin-org.js.map +1 -0
  544. package/src/lib/server/ai-admin-orgs-spend.d.ts +40 -0
  545. package/src/lib/server/ai-admin-orgs-spend.js +129 -0
  546. package/src/lib/server/ai-admin-orgs-spend.js.map +1 -0
  547. package/src/lib/server/ai-admin-overage.d.ts +19 -0
  548. package/src/lib/server/ai-admin-overage.js +246 -0
  549. package/src/lib/server/ai-admin-overage.js.map +1 -0
  550. package/src/lib/server/ai-admin-signals.d.ts +34 -0
  551. package/src/lib/server/ai-admin-signals.js +330 -0
  552. package/src/lib/server/ai-admin-signals.js.map +1 -0
  553. package/src/lib/server/ai-admin-user.d.ts +27 -0
  554. package/src/lib/server/ai-admin-user.js +128 -0
  555. package/src/lib/server/ai-admin-user.js.map +1 -0
  556. package/src/lib/server/ai-allotments.d.ts +27 -0
  557. package/src/lib/server/ai-allotments.js +544 -0
  558. package/src/lib/server/ai-allotments.js.map +1 -0
  559. package/src/lib/server/ai-assist-prompts.d.ts +102 -0
  560. package/src/lib/server/ai-assist-prompts.js +207 -0
  561. package/src/lib/server/ai-assist-prompts.js.map +1 -0
  562. package/src/lib/server/ai-assist.d.ts +119 -0
  563. package/src/lib/server/ai-assist.js +517 -0
  564. package/src/lib/server/ai-assist.js.map +1 -0
  565. package/src/lib/server/ai-crm-answer.d.ts +30 -0
  566. package/src/lib/server/ai-crm-answer.js +98 -0
  567. package/src/lib/server/ai-crm-answer.js.map +1 -0
  568. package/src/lib/server/ai-generate-component.d.ts +111 -0
  569. package/src/lib/server/ai-generate-component.js +643 -0
  570. package/src/lib/server/ai-generate-component.js.map +1 -0
  571. package/src/lib/server/ai-host-permissions.d.ts +46 -0
  572. package/src/lib/server/ai-host-permissions.js +204 -0
  573. package/src/lib/server/ai-host-permissions.js.map +1 -0
  574. package/src/lib/server/ai-insight-answer.d.ts +30 -0
  575. package/src/lib/server/ai-insight-answer.js +83 -0
  576. package/src/lib/server/ai-insight-answer.js.map +1 -0
  577. package/src/lib/server/ai-insight-digest-route.d.ts +30 -0
  578. package/src/lib/server/ai-insight-digest-route.js +156 -0
  579. package/src/lib/server/ai-insight-digest-route.js.map +1 -0
  580. package/src/lib/server/ai-jobs-batch.d.ts +48 -0
  581. package/src/lib/server/ai-jobs-batch.js +306 -0
  582. package/src/lib/server/ai-jobs-batch.js.map +1 -0
  583. package/src/lib/server/ai-jobs-beat-route.d.ts +36 -0
  584. package/src/lib/server/ai-jobs-beat-route.js +86 -0
  585. package/src/lib/server/ai-jobs-beat-route.js.map +1 -0
  586. package/src/lib/server/ai-jobs-cancel.d.ts +30 -0
  587. package/src/lib/server/ai-jobs-cancel.js +74 -0
  588. package/src/lib/server/ai-jobs-cancel.js.map +1 -0
  589. package/src/lib/server/ai-jobs-events-route.d.ts +31 -0
  590. package/src/lib/server/ai-jobs-events-route.js +51 -0
  591. package/src/lib/server/ai-jobs-events-route.js.map +1 -0
  592. package/src/lib/server/ai-jobs-events.d.ts +55 -0
  593. package/src/lib/server/ai-jobs-events.js +144 -0
  594. package/src/lib/server/ai-jobs-events.js.map +1 -0
  595. package/src/lib/server/ai-jobs-gate.d.ts +47 -0
  596. package/src/lib/server/ai-jobs-gate.js +106 -0
  597. package/src/lib/server/ai-jobs-gate.js.map +1 -0
  598. package/src/lib/server/ai-jobs-resume.d.ts +23 -0
  599. package/src/lib/server/ai-jobs-resume.js +209 -0
  600. package/src/lib/server/ai-jobs-resume.js.map +1 -0
  601. package/src/lib/server/ai-jobs-route.d.ts +32 -0
  602. package/src/lib/server/ai-jobs-route.js +307 -0
  603. package/src/lib/server/ai-jobs-route.js.map +1 -0
  604. package/src/lib/server/ai-models.d.ts +18 -0
  605. package/src/lib/server/ai-models.js +134 -0
  606. package/src/lib/server/ai-models.js.map +1 -0
  607. package/src/lib/server/ai-seo-apply.d.ts +53 -0
  608. package/src/lib/server/ai-seo-apply.js +294 -0
  609. package/src/lib/server/ai-seo-apply.js.map +1 -0
  610. package/src/lib/server/ai-usage.d.ts +18 -0
  611. package/src/lib/server/ai-usage.js +220 -0
  612. package/src/lib/server/ai-usage.js.map +1 -0
  613. package/src/lib/server/assist-chat.d.ts +234 -0
  614. package/src/lib/server/assist-chat.js +1446 -0
  615. package/src/lib/server/assist-chat.js.map +1 -0
  616. package/src/lib/server/assist-edit-applied.d.ts +22 -0
  617. package/src/lib/server/assist-edit-applied.js +239 -0
  618. package/src/lib/server/assist-edit-applied.js.map +1 -0
  619. package/src/lib/server/assist-edit.d.ts +124 -0
  620. package/src/lib/server/assist-edit.js +1000 -0
  621. package/src/lib/server/assist-edit.js.map +1 -0
  622. package/src/lib/server/assist-feedback.d.ts +31 -0
  623. package/src/lib/server/assist-feedback.js +115 -0
  624. package/src/lib/server/assist-feedback.js.map +1 -0
  625. package/src/lib/server/assist-view-context.d.ts +343 -0
  626. package/src/lib/server/assist-view-context.js +690 -0
  627. package/src/lib/server/assist-view-context.js.map +1 -0
  628. package/src/lib/server/billing-credits.d.ts +59 -0
  629. package/src/lib/server/billing-credits.js +146 -0
  630. package/src/lib/server/billing-credits.js.map +1 -0
  631. package/src/lib/server/billing-overage.d.ts +19 -0
  632. package/src/lib/server/billing-overage.js +337 -0
  633. package/src/lib/server/billing-overage.js.map +1 -0
  634. package/src/lib/server.d.ts +32 -0
  635. package/src/lib/server.js +265 -0
  636. package/src/lib/server.js.map +1 -0
  637. package/src/lib/subprocessors.d.ts +18 -0
  638. package/src/lib/subprocessors.js +52 -0
  639. package/src/lib/subprocessors.js.map +1 -0
  640. package/src/lib/tools/ai-component-tool.d.ts +99 -0
  641. package/src/lib/tools/ai-component-tool.js +369 -0
  642. package/src/lib/tools/ai-component-tool.js.map +1 -0
  643. package/src/lib/tools/ai-crm-tool.d.ts +106 -0
  644. package/src/lib/tools/ai-crm-tool.js +488 -0
  645. package/src/lib/tools/ai-crm-tool.js.map +1 -0
  646. package/src/lib/tools/ai-duplicate-resource-tool.d.ts +71 -0
  647. package/src/lib/tools/ai-duplicate-resource-tool.js +164 -0
  648. package/src/lib/tools/ai-duplicate-resource-tool.js.map +1 -0
  649. package/src/lib/tools/ai-experiment-tool.d.ts +40 -0
  650. package/src/lib/tools/ai-experiment-tool.js +155 -0
  651. package/src/lib/tools/ai-experiment-tool.js.map +1 -0
  652. package/src/lib/tools/ai-insight-tool.d.ts +46 -0
  653. package/src/lib/tools/ai-insight-tool.js +200 -0
  654. package/src/lib/tools/ai-insight-tool.js.map +1 -0
  655. package/src/lib/tools/ai-inventory-lookup-tool.d.ts +86 -0
  656. package/src/lib/tools/ai-inventory-lookup-tool.js +164 -0
  657. package/src/lib/tools/ai-inventory-lookup-tool.js.map +1 -0
  658. package/src/lib/tools/ai-products-tool.d.ts +65 -0
  659. package/src/lib/tools/ai-products-tool.js +644 -0
  660. package/src/lib/tools/ai-products-tool.js.map +1 -0
  661. package/src/lib/tools/ai-seo-tool.d.ts +162 -0
  662. package/src/lib/tools/ai-seo-tool.js +546 -0
  663. package/src/lib/tools/ai-seo-tool.js.map +1 -0
  664. package/src/lib/tools/ai-theme-tool.d.ts +101 -0
  665. package/src/lib/tools/ai-theme-tool.js +562 -0
  666. package/src/lib/tools/ai-theme-tool.js.map +1 -0
  667. package/src/lib/tools/ai-workflow-tool.d.ts +166 -0
  668. package/src/lib/tools/ai-workflow-tool.js +860 -0
  669. package/src/lib/tools/ai-workflow-tool.js.map +1 -0
  670. package/src/lib/usage/ai-allotment-alerts.d.ts +72 -0
  671. package/src/lib/usage/ai-allotment-alerts.js +157 -0
  672. package/src/lib/usage/ai-allotment-alerts.js.map +1 -0
  673. package/src/lib/usage/ai-allotments.d.ts +125 -0
  674. package/src/lib/usage/ai-allotments.js +239 -0
  675. package/src/lib/usage/ai-allotments.js.map +1 -0
  676. package/src/lib/usage/ai-model-sample.d.ts +36 -0
  677. package/src/lib/usage/ai-model-sample.js +68 -0
  678. package/src/lib/usage/ai-model-sample.js.map +1 -0
  679. package/src/lib/usage/ai-usage-alerts.d.ts +55 -0
  680. package/src/lib/usage/ai-usage-alerts.js +114 -0
  681. package/src/lib/usage/ai-usage-alerts.js.map +1 -0
  682. package/src/lib/usage/ai-usage-by-user.d.ts +161 -0
  683. package/src/lib/usage/ai-usage-by-user.js +211 -0
  684. package/src/lib/usage/ai-usage-by-user.js.map +1 -0
  685. package/src/lib/usage/ai-usage-eraser.d.ts +29 -0
  686. package/src/lib/usage/ai-usage-eraser.js +40 -0
  687. package/src/lib/usage/ai-usage-eraser.js.map +1 -0
  688. package/src/lib/usage/ai-usage-meter.d.ts +39 -0
  689. package/src/lib/usage/ai-usage-meter.js +85 -0
  690. package/src/lib/usage/ai-usage-meter.js.map +1 -0
  691. package/src/lib/usage/ai-usage-wire.d.ts +184 -0
  692. package/src/lib/usage/ai-usage-wire.js +98 -0
  693. package/src/lib/usage/ai-usage-wire.js.map +1 -0
  694. package/src/lib/usage/assist-ceiling.d.ts +87 -0
  695. package/src/lib/usage/assist-ceiling.js +110 -0
  696. package/src/lib/usage/assist-ceiling.js.map +1 -0
  697. package/src/lib/usage/assist-free-taste.d.ts +225 -0
  698. package/src/lib/usage/assist-free-taste.js +308 -0
  699. package/src/lib/usage/assist-free-taste.js.map +1 -0
  700. package/src/lib/usage/assist-refusals.d.ts +69 -0
  701. package/src/lib/usage/assist-refusals.js +79 -0
  702. package/src/lib/usage/assist-refusals.js.map +1 -0
  703. package/src/lib/usage/assist-signal-mining.d.ts +375 -0
  704. package/src/lib/usage/assist-signal-mining.js +344 -0
  705. package/src/lib/usage/assist-signal-mining.js.map +1 -0
  706. package/src/lib/usage/assist-usage.d.ts +571 -0
  707. package/src/lib/usage/assist-usage.js +978 -0
  708. package/src/lib/usage/assist-usage.js.map +1 -0
  709. package/src/lib/usage/staff-org-ai.d.ts +242 -0
  710. package/src/lib/usage/staff-org-ai.js +173 -0
  711. package/src/lib/usage/staff-org-ai.js.map +1 -0
  712. package/src/lib/usage/staff-org-usage-ai.d.ts +83 -0
  713. package/src/lib/usage/staff-org-usage-ai.js +59 -0
  714. package/src/lib/usage/staff-org-usage-ai.js.map +1 -0
  715. package/src/lib/usage/staff-orgs-ai-spend.d.ts +83 -0
  716. package/src/lib/usage/staff-orgs-ai-spend.js +114 -0
  717. package/src/lib/usage/staff-orgs-ai-spend.js.map +1 -0
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../../../../libs/plugins/ai/src/lib/usage/assist-usage.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 * `FieldValue` comes straight from the SDK rather than through the admin\n * barrel (AGL-2073). This module serves every metered AI door — the chat\n * door, the besigner copy assistant and the generation jobs — and importing\n * the admin lib's `firebase-admin` module would drag the default-app\n * initialization (cert credential, RTDB, AppCheck) into every unit test that\n * touches a counter; `FieldValue`'s statics need no app at all.\n */\nimport { FieldValue } from 'firebase-admin/firestore'\nimport {\n ASSIST_PROVIDER_COST_FIELD,\n assistBandRefuses,\n assistCreditsFromUsd,\n assistMonthOverage,\n assistOverageCapReached,\n publicAssistCredits,\n resolveAssistBudgetUsd,\n resolveAssistOverageCapUsd,\n resolveAssistOverageRateUsdPer1k,\n type PublicAssistCredits,\n} from '@aglyn/aglyn/app-utils/assist-credits'\nimport {\n aiOverageRefusal,\n type AiOverageCapReason,\n} from '../billing/ai-overage-gate'\nimport {\n aiOverageBillsByInvoice,\n aiOverageGuardsApply,\n} from '../billing/ai-overage-cutover'\nimport {\n AI_BILLING_STANDING_DOC,\n AI_BILLING_SUBCOLLECTION,\n readAiOverageMonthLedger,\n} from '../billing/ai-overage-ledger'\nimport { readAiOverageStanding } from '../billing/ai-overage-standing'\nimport type { AiRefusedBy } from '../model/ai-allotments'\nimport {\n AI_HOST_CREDITS_FIELD,\n readAiAllotmentGate,\n type AiAllotmentGate,\n type AiAllotmentRequestSubject,\n} from './ai-allotments'\nimport { isUncappedPlanComp } from '@aglyn/aglyn/app-utils/plan-entitlements'\nimport { assistMonthlyCeilingUsd } from './assist-ceiling'\nimport { estimateAiBilledUsd, estimateAiProviderCostUsd } from '../providers/catalog'\nimport { recordAssistRefusal } from './assist-refusals'\nimport {\n announcePlatformFreeSpend,\n freeAccountReservationWrite,\n freeAccountUsageRef,\n freeAssistAccount,\n freeTasteMeterWrites,\n freeTasteReadsFrom,\n freeTasteRefusal,\n platformFreeSpendRef,\n type AssistMeteredOrg,\n type FreeAssistAccount,\n} from './assist-free-taste'\nimport { aiTokenIncrements, recordUserAiUsage } from './ai-usage-by-user'\nimport { AI_USAGE_MONTH_KINDS_FIELD, AI_USAGE_TOKENS_FIELD } from '../model/ai-tokens'\nimport {\n aiUsageKindFromRoute,\n type AiUsageKind,\n} from '../model/ai-usage-by-user'\n\n// The ceiling composition lives beside the one other reader it has, the staff\n// refusal alert, in a module that writes nothing; the reservation's importers\n// keep reaching it here.\nexport { assistMonthlyCeilingUsd } from './assist-ceiling'\n\n/**\n * Aglyn Assist metering + the data loop (AGL-1860, phase 1).\n *\n * Collections (org-scoped, ABSENT from firebase-firestore.rules on purpose —\n * default-deny, the forumThreads precedent: every read/write passes the\n * assist API route via the Admin SDK):\n *\n * orgs/{orgId}/assistUsage/{YYYY-MM} per-org monthly cost telemetry:\n * { month, messages, inputTokens, outputTokens, cacheReadTokens,\n * cacheWriteTokens, estCostUsd, byHost: { hostId: credits },\n * kinds: { kind: { requests, estCostUsd, tokens } }, updatedAt }\n * (`byHost` is each site's credits, which a site's AI allotment is\n * measured against — AGL-2942; `kinds` splits the tokens and the\n * measured spend by what each model request was for — AGL-2937)\n * orgs/{orgId}/counters/assistMessagesDaily\n * fields keyed YYYY-MM-DD → integer (the free-tier daily cap counter;\n * same field-per-period shape as the other `counters/*` docs)\n * orgs/{orgId}/assistExchanges/{id} the VERBATIM half of one exchange:\n * { uid, question, answer, hostId, createdAt, expiresAt }\n * orgs/{orgId}/assistSignals/{id} the DERIVED half, same id:\n * { route, hostId, model, tier, kind, inputTokens, outputTokens,\n * cacheReadTokens, cacheWriteTokens, estCostUsd, docsPaths,\n * stopReason, feedback: 'up'|'down'|null, createdAt }\n *\n * The Free taste (AGL-2925) adds two more, one under the workspace OWNER's\n * user document and one platform-wide, both documented and both closed to\n * clients in `assist-free-taste.ts`.\n *\n * Costs are OUR cost estimates at list rates (pricing-tunable telemetry),\n * mirrored after ORG_COGS_UNIT_RATES_USD's posture: cost visibility per org\n * from day one so the paid gate and caps can be tuned with data — the * \"must not eat margins\" constraint.\n *\n * ── Why the exchange is split in two (AGL-1972) ────────────────────────────\n *\n * One document carrying both halves forces one retention period onto two\n * kinds of data with opposite needs. The prose is what a person typed; the\n * data loop is what it cited and what it cost. Keeping them together means\n * either the prose is retained forever so the loop keeps its corpus, or the\n * loop's corpus is destroyed so the prose can expire. Neither is the answer,\n * and picking one number for both is how that false choice gets made.\n *\n * So: `assistExchanges` holds the question, the answer and the asking `uid`,\n * and carries `expiresAt` — a TTL policy reaps it after\n * ASSIST_EXCHANGE_RETENTION_DAYS. `assistSignals` holds no prose and NO uid,\n * carries no expiry, and is what the docs-gap view, the thumbs loop and the\n * cost meters actually read. The corpus the loop needs outlives the words\n * that produced it, because the corpus was never the words.\n *\n * Both subcollections sit under the org, so `recursiveDelete(orgRef)` still\n * takes them and an erasure still clears everything with no extra sweep. And\n * both are ABSENT from firebase-firestore.rules deliberately: the org block\n * matches its subcollections BY NAME and has no wildcard, so an unmatched\n * name is default-deny for every client (verified against the live ruleset —\n * the `{subcollection}/{document=**}` catch-all is under `hosts/{hostId}`,\n * not here).\n *\n * ⚠️ The TTL policy is MANUAL gcloud configuration, not repo state. It is\n * documented in `docs/FIRESTORE_MANUAL_CONFIG.md` and declared as a\n * `fieldOverrides` entry in `cloud/firebase-firestore.indexes.json` — the\n * declaration is not decoration, it is what stops the next unrelated index\n * deploy from DELETING the policy. `apps/console/specs/retention-ttl-config.spec.ts`\n * fails the build if either half goes missing.\n */\n\n/** Current billing month key, `YYYY-MM`, matching the usage rollup. */\nexport function assistUsageMonth(now = new Date()): string {\n return now.toISOString().slice(0, 7)\n}\n\n/** Current day key, `YYYY-MM-DD` (UTC — same clock as the month key). */\nexport function assistUsageDay(now = new Date()): string {\n return now.toISOString().slice(0, 10)\n}\n\n/**\n * How long the VERBATIM half of an exchange is kept — the question, the\n * answer and the asking uid (AGL-1972).\n *\n * 180 days, and the number is chosen against what actually reads this data\n * rather than against a round figure:\n *\n * - The docs-gap loop mines `docsPaths` and the thumbs rating. Both live on\n * the signal document, which has no expiry, so shortening this period\n * costs the loop nothing. That separation is what makes 180 affordable;\n * without it the honest answer would have been \"forever\".\n * - Two full quarters is long enough to read a quarter's questions LATE, and\n * long enough to diff what people asked before and after a docs rewrite —\n * the one analysis that genuinely needs the prose and not the citations.\n * - It is short enough that a workspace open for years is not an indefinite\n * archive of what its people typed into a text box.\n *\n * ⚠️ TTL deletion is best-effort within ~72h of expiry, so nothing may treat\n * an exchange's absence OR its presence as exact at the boundary. Nothing\n * does: the only reader addresses an exchange by id and tolerates a miss.\n */\nexport const ASSIST_EXCHANGE_RETENTION_DAYS = 180\n\nconst DAY_MS = 24 * 60 * 60 * 1000\n\n/**\n * When an exchange written at `now` expires. A `Date` rather than a number:\n * a TTL policy keys on a Firestore **Timestamp** and silently governs\n * nothing when the field is a number (`bookings.expiresAtMs` is the\n * documented non-target for exactly this reason). The Admin SDK converts a\n * JS `Date` to a Timestamp on write, which is how `cspViolationDaily` does\n * it and is why this module needs no firebase-admin type here.\n */\nexport function assistExchangeExpiry(now = new Date()): Date {\n return new Date(now.getTime() + ASSIST_EXCHANGE_RETENTION_DAYS * DAY_MS)\n}\n\n/**\n * Free-tier daily message cap (level-1 answers only). Env-tunable without a\n * deploy of new code paths.\n *\n * What ten messages actually cost: about **$0.28 a day** at Sonnet list\n * rates, taking the worst case the clamps allow (see\n * `ASSIST_ORG_MONTHLY_COGS_LIMIT_DEFAULT_USD` for the same arithmetic\n * carried to the monthly ceiling). A typical question costs a fraction of\n * that, because the worst case assumes a full 8,000-character history and a\n * 4,000-character question on every one of the ten.\n *\n * This docstring used to claim \"well under a cent a day\", which was the\n * pre-AGL-2441 figure and wrong by ~28x once the history clamp was measured\n * rather than assumed. It is restated here because it is the stated\n * justification for the size of this cap, and a justification that is off by\n * that much is how a cap ends up set by a number nobody re-derived.\n */\nexport function assistFreeDailyLimit(): number {\n const raw = process.env.ASSIST_FREE_DAILY_LIMIT\n // `Number('')` is 0, so an unset/empty var must fall through to the\n // default rather than silently zeroing the free tier.\n const parsed = raw ? Number(raw) : Number.NaN\n return Number.isFinite(parsed) && parsed >= 0 ? Math.floor(parsed) : 10\n}\n\n/**\n * Entitled (Pro+/aiAssist) monthly message cap — a runaway guard, not a\n * product limit: high enough that no real user hits it, low enough that a\n * scripted client cannot turn one subscription into unbounded token spend.\n */\nexport function assistEntitledMonthlyLimit(): number {\n const raw = process.env.ASSIST_ENTITLED_MONTHLY_LIMIT\n const parsed = raw ? Number(raw) : Number.NaN\n return Number.isFinite(parsed) && parsed > 0 ? Math.floor(parsed) : 1000\n}\n\nexport interface AssistTokenUsage {\n inputTokens: number\n outputTokens: number\n cacheReadTokens: number\n cacheWriteTokens: number\n}\n\n/**\n * What one exchange DRAWS FROM THE CUSTOMER, at the serving model's billed\n * rates, rounded to 6dp — the figure `assistCreditsFromUsd` turns into\n * credits and the one the band, the cap and the invoice are measured in.\n *\n * The rates are the model catalog's (AGL-2939), keyed by model rather than\n * fixed at one model's because `ASSIST_MODEL` is an env override: a\n * one-line incident swap to a dearer model would otherwise keep reporting\n * the cheaper money, and per-org cost would read as roughly right — the\n * failure mode this whole meter exists to prevent. An unknown id is priced\n * at the dearest known tier on purpose, because an estimate that errs low is\n * worse than one that errs high, and a docs-only answer is metered under a\n * zero-priced sentinel (`AI_METER_SENTINELS`) so it lands in the same rollup\n * as a served one.\n *\n * NOT A COST (AGL-3015). A model may be billed above what its provider\n * charges, so this overstates what the exchange cost us by exactly that\n * markup. `estimateAssistProviderCostUsd` is the figure a margin or a spend\n * meter takes.\n */\nexport function estimateAssistCostUsd(\n usage: AssistTokenUsage,\n model: string,\n): number {\n return estimateAiBilledUsd(usage, model)\n}\n\n/**\n * What one exchange COST US, at the serving model's provider rates, rounded\n * to 6dp — real money, recorded beside the billed figure so a margin is\n * taken against a bill we actually pay rather than against a price we\n * charge.\n *\n * At or below `estimateAssistCostUsd` for the same tokens, and equal to it\n * on every model billed at its provider's list.\n */\nexport function estimateAssistProviderCostUsd(\n usage: AssistTokenUsage,\n model: string,\n): number {\n return estimateAiProviderCostUsd(usage, model)\n}\n\nexport interface AssistQuotaVerdict {\n allowed: boolean\n /** Which limit applied: free orgs meter daily, entitled orgs monthly. */\n period: 'day' | 'month'\n used: number\n limit: number\n remaining: number\n}\n\n/**\n * A reservation taken against the cap, carrying BOTH counter keys so it can\n * be handed back against the periods it actually moved rather than against\n * \"now\". A request that reserves at 23:59:59 and fails at 00:00:01 would\n * otherwise credit the NEXT day — capacity nobody paid for, arriving by the\n * one route a cap must never have.\n */\nexport interface AssistReservation extends AssistQuotaVerdict {\n /** UTC day the daily counter was incremented for (`YYYY-MM-DD`). */\n dayKey: string\n /** Month the `assistUsage` doc was incremented for (`YYYY-MM`). */\n monthKey: string\n /**\n * Which ceiling refused, or `null` when the message was reserved. The\n * refusals need different words at the surface: a message cap resets on a\n * clock the user can be told about, a spend ceiling does not, and the\n * plan's own band (`'band'`, AGL-2653) is a line the org could have chosen\n * to buy past — so its refusal has to name the switch that made it a wall.\n * `'band'` is answered only when the figure that refused IS the band; an\n * operator's lower figure refuses as `'budget'` even on a plan with one.\n * `'cap'` (AGL-2898) is the org's own dollar ceiling on the overage it\n * buys past the band — reachable only on a plan that sells past it.\n * `'requests'`, `'refusals'`, `'account'` and `'platform'` (AGL-2925) are\n * the Free taste's own precautions, and only a Free workspace can hear\n * them. `'allotment'` (AGL-2942) is a hard allotment the person or the\n * site has spent — see `allotment` for which.\n *\n * Only on the reservation, not on `AssistQuotaVerdict` — `checkAssistQuota`\n * is a reporting read that never consults the spend ceiling, and widening\n * the shared type would let a caller believe it had.\n */\n refusedBy: AiRefusedBy\n /**\n * WHICH dollar ceiling refused, when `refusedBy` is `'cap'` (AGL-3011).\n *\n * `'customer'` is the workspace's own ceiling (AGL-2898) and keeps the\n * sentence and the 402 it has always had. The other four are Aglyn's own\n * guards on the overage it extends between invoices: no card on file,\n * accrual paused, this month's ceiling, and the unpaid balance at its\n * limit. Absent on every other refusal and on an admitted request.\n *\n * The doors need it because the four answer differently: a missing card\n * and a paused workspace are 402s a person can act on, and a ceiling or a\n * settling balance are 429s they can only wait out.\n */\n capReason?: AiOverageCapReason | null\n /**\n * The figure the `cap` refusal was measured against — the month's ceiling\n * for `'limit'`, the unpaid limit for `'settling'` — so the sentence the\n * door renders quotes the number that actually refused rather than\n * re-deriving one that could differ.\n */\n overageLimitUsd?: number | null\n /** Overage accrued and not yet paid for, at the instant of the refusal. */\n overageUnpaidUsd?: number | null\n /**\n * The allotments that applied to the person asking, measured (AGL-2942):\n * which one refused, which one binds the usage strip, the caller's own\n * credits this month, and the model allowlists. `null` when the request\n * named nobody, and when a ceiling of the workspace's own refused before\n * any allotment was read.\n */\n allotment?: AiAllotmentGate | null\n /**\n * The account the workspace's FREE spend is attributed to, or `null` for\n * a workspace that is not on the Free plan (AGL-2925).\n *\n * Carried on the reservation so the door that meters the turn can hand\n * the same attribution to `recordAssistCost` without resolving it twice:\n * the reservation decided which account's allowance this request drew\n * on, and the record must charge that account and no other.\n */\n free: FreeAssistAccount | null\n /**\n * Measured provider spend for `monthKey` in USD as read inside the\n * transaction, or `null` when the transaction did not consult it.\n *\n * Nullable rather than defaulted to 0, and the difference is the whole\n * point: an entitled reservation reads the monthly document anyway (it is\n * the gate), but a free one gates on the daily counter and only opens the\n * monthly document when a ceiling is configured — so there is a path with\n * no figure to report. Reporting `0` there would be a constant wearing a\n * measurement's name, and a caller could not tell \"this org has spent\n * nothing\" from \"nobody looked\".\n */\n costUsd: number | null\n /**\n * The ceiling this reservation was measured against, or `null` when none\n * applied — the plan's band, the operator's figure, or the lower of the\n * two. See `assistMonthlyCeilingUsd`.\n */\n costLimitUsd: number | null\n /**\n * The org's PLAN assist band in USD, or `null` when its plan sells none.\n *\n * Separate from `costLimitUsd` because they answer different questions and\n * a surface needs both. `costLimitUsd` is what refused; this is whether the\n * org has a band at all, and therefore whether it can be shown a credit\n * balance. An org with no band that met the operator's backstop must not be\n * told it used up credits it was never sold, and an org whose band was\n * undercut by an operator's figure must not be told it has credits left\n * while being refused.\n */\n budgetUsd: number | null\n}\n\n/**\n * Reserve one assist message BEFORE the model is called (AGL-2057).\n *\n * This replaces `checkAssistQuota` on the request path, and the difference is\n * the whole point. `checkAssistQuota` READ the counter and let the request\n * through; the counter only moved in `recordAssistExchange`, at stream\n * COMPLETION. Two ways out of the cap followed, both of which spend real\n * provider tokens for an org that has no invoice to put them on:\n *\n * 1. **Concurrency.** N in-flight requests each read `used < limit` before any\n * of them recorded. The per-uid rate limiter (20/min) was the only bound.\n * 2. **Abandoned streams.** Recording ran in the stream's completion handler,\n * so a client that opened a request and dropped it never counted at all.\n * Looped, that is UNBOUNDED spend on a free workspace — the cap simply\n * never advanced. This is the fail-open that costs money silently.\n *\n * So the count moves to the front, inside a transaction: read and increment\n * are one atomic step, and a refused request never reaches the provider. The\n * lesson is AGL's own — fix WHEN the quota is evaluated, not how the counting\n * is done.\n *\n * Both counters move here (the daily one AND monthly `messages`) so message\n * counting has exactly one home. `recordAssistExchange` therefore records the\n * exchange, its tokens and its cost, and counts NO messages; calling it after\n * a reservation must not double-count.\n *\n * A plan-less org resolves as free upstream, so an unknown org gets the\n * SMALLER cap. That direction is deliberate.\n *\n * ## The spend gate is the one that matters now\n *\n * The message caps above are a runaway guard. The gate that decides what a\n * paying workspace gets is the SPEND ceiling, because assist actions differ\n * in cost by up to two orders of magnitude: a question is a few thousand\n * tokens and generating a screen carries a node tree, a component catalog and\n * theme tokens in and structured markup out. Counting both as one message\n * would let ten screen builds outspend a thousand questions while both read\n * as being within allowance.\n *\n * `org` is the billing document the caller already resolved `entitled` from.\n * It is optional and defaults to no org, which resolves as free — a band of\n * none, and therefore exactly the operator-backstop behaviour that predates\n * plan bands. Passing it is what makes a plan's own band bind.\n *\n * ## Refusal is legitimate here, unlike the transactional email carve-out\n *\n * A campaign send is refusable at its band and transactional mail is not,\n * because a blocked password reset locks somebody out of their own account.\n * Nothing assist does is that. It is help, not a person's data and not their\n * access: a refused question means the answer is not given, and a refused\n * build means the screen is built by hand in a besigner that still works. So\n * assist refuses at the band with no carve-out.\n *\n * What is never refused is what costs nothing. A docs-deflected answer and a\n * cache hit spend no tokens and take NO RESERVATION AT ALL — they return\n * before this function is reached — so a workspace at its band keeps getting\n * every answer the docs index can give it. That is not a carve-out inside\n * this gate; it is the reason those paths are ahead of it.\n *\n * ## The band is sold past by default (AGL-2653)\n *\n * Refusing at the band is legitimate; it is no longer the default. A plan\n * with an `extraAssistCreditsUsdPer1k` keeps reserving past its band and\n * `report-usage` bills the excess at that rate, unless the org's own\n * `assistOverage.hardCap` asks for the wall — `assistBandRefuses` is the one\n * place that rule lives. The ceiling below is composed from that answer, and\n * `refusedBy: 'band'` is how a refusal the switch caused is told apart from\n * one the operator's figure caused.\n *\n * ## The Free taste is metered twice (AGL-2925)\n *\n * A Free workspace's band is a wall, and a wall per workspace is not a\n * bound per person. So when `org` resolves to the Free plan the SAME\n * transaction also reads the workspace owner's account document and the\n * platform's day of free spend, and refuses on the account's daily request\n * cap, its refusal pause, its monthly allowance and the platform ceiling —\n * see `assist-free-taste.ts` for each. An admitted free reservation counts\n * the request on the account beside the org's own counters, so the release\n * path hands both back together.\n *\n * ## Allotments sit inside the band (AGL-2942)\n *\n * `subject` names the person asking and the site the request named. Once\n * the workspace's own ceilings — the message cap, the band or budget, the\n * overage cap — have admitted the request, the SAME transaction reads the\n * allotments that apply to that person and site and refuses as `allotment`\n * when a hard one is spent. After the workspace's rungs, so a workspace at\n * its band hears about its band and an allotment can never admit what the\n * band refused; before the Free taste's, which are precautions about the\n * account rather than decisions a manager made. Refusing moves no counter,\n * like every refusal above it. A soft allotment at 80% or 100% admits the\n * request and is announced once the transaction has committed.\n */\nexport async function reserveAssistMessage(\n firestore: FirebaseFirestore.Firestore,\n orgId: string,\n entitled: boolean,\n now = new Date(),\n org: AssistMeteredOrg | null = null,\n subject: AiAllotmentRequestSubject | null = null,\n): Promise<AssistReservation> {\n const reservation = await reserveInTransaction(\n firestore,\n orgId,\n entitled,\n now,\n org,\n subject,\n )\n if (reservation.allotment?.alerts.length) {\n announceAllotmentAlerts(firestore, orgId, org, reservation)\n }\n return reservation\n}\n\n/**\n * A soft allotment's crossing, told through the alert pipeline — off the\n * reservation's await path and never failing it: the request was admitted,\n * and a notification is not a reason to take that back. Loaded when the\n * first crossing arrives, so the modules that write notifications and send\n * mail are not part of every metered request.\n */\nfunction announceAllotmentAlerts(\n firestore: FirebaseFirestore.Firestore,\n orgId: string,\n org: AssistMeteredOrg | null,\n reservation: AssistReservation,\n): void {\n const alerts = reservation.allotment?.alerts ?? []\n void import('./ai-allotment-alerts')\n .then(({ announceAiAllotmentAlerts }) =>\n announceAiAllotmentAlerts(firestore, {\n orgId,\n orgSlug: typeof (org as { slug?: unknown } | null)?.slug === 'string'\n ? String((org as { slug?: unknown }).slug)\n : null,\n month: reservation.monthKey,\n alerts,\n }),\n )\n .catch((error) => console.error('[ai-allotments] alert failed', orgId, error))\n}\n\n/**\n * The charge this turn may have earned (AGL-3011).\n *\n * Off the await path and never able to fail the turn: the tokens are already\n * spent, and making the answer wait on a Stripe round trip — or losing it to\n * one — would turn a billing problem into a product one. Loaded when the\n * first chargeable turn arrives, so the modules that read org billing and\n * call Stripe are not part of every metered request.\n *\n * Returns before loading anything at all while `AI_OVERAGE_INVOICED_FROM`\n * names no month, which is how this ships: AI overage bills through the\n * monthly meter exactly as it does today, and this costs one string compare.\n *\n * A turn whose process ends before this finishes is covered three ways: the\n * next turn tries again, the reconcile sweep finishes a half-made charge,\n * and the gate refuses at the unpaid limit regardless.\n */\nfunction chargeAccruedOverage(\n firestore: FirebaseFirestore.Firestore,\n orgId: string,\n month: string,\n now: Date,\n): void {\n if (!aiOverageBillsByInvoice(month)) return\n void import('../billing/ai-overage-trigger')\n .then(({ chargeAccruedAiOverage }) =>\n chargeAccruedAiOverage(firestore, orgId, month, now),\n )\n .catch((error) => console.error('[ai-overage] charge failed', orgId, error))\n}\n\nasync function reserveInTransaction(\n firestore: FirebaseFirestore.Firestore,\n orgId: string,\n entitled: boolean,\n now: Date,\n org: AssistMeteredOrg | null,\n subject: AiAllotmentRequestSubject | null,\n): Promise<AssistReservation> {\n const increment = FieldValue.increment\n const serverTimestamp = FieldValue.serverTimestamp\n const orgRef = firestore.collection('orgs').doc(orgId)\n const day = assistUsageDay(now)\n const month = assistUsageMonth(now)\n const dailyRef = orgRef.collection('counters').doc('assistMessagesDaily')\n const monthlyRef = orgRef.collection('assistUsage').doc(month)\n const limit = entitled ? assistEntitledMonthlyLimit() : assistFreeDailyLimit()\n const period: 'day' | 'month' = entitled ? 'month' : 'day'\n const gateRef = entitled ? monthlyRef : dailyRef\n const gateField = entitled ? 'messages' : day\n // The Free taste's attribution, resolved once and carried on every\n // answer below: `null` for any paid plan, and for the paths that never\n // consult it.\n const free = freeAssistAccount(org)\n const accountRef =\n free?.accountUid ? freeAccountUsageRef(firestore, free.accountUid, month) : null\n\n // The plan's band first, then whether it refuses at all, then whatever the\n // operator did about it. Resolved OUTSIDE the transaction: it is pure\n // arithmetic over a document the caller already holds, and a transaction\n // that retries must not re-derive a ceiling that could have moved between\n // attempts.\n const budgetUsd = resolveAssistBudgetUsd(org)\n const bandRefuses = assistBandRefuses(org)\n // An uncapped staff comp has no band and no backstop default (AGL-3049).\n const costLimitUsd = assistMonthlyCeilingUsd(\n budgetUsd,\n bandRefuses,\n isUncappedPlanComp(org),\n )\n // The ceiling IS the band when the band refuses and nothing lower undercut\n // it. That is the refusal the surface has to attribute to the org's own\n // switch (or to a plan that sells no overage); a lower operator figure is\n // the operator's decision and keeps the operator's word.\n const ceilingIsBand =\n bandRefuses && budgetUsd !== null && costLimitUsd === budgetUsd\n // The org's own ceiling on the overage it buys (AGL-2898). Only a band\n // that is SOLD past has an overage to cap, so a band that refuses leaves\n // no ceiling to consult: past a wall there is nothing to be over.\n const overageCapUsd = bandRefuses ? null : resolveAssistOverageCapUsd(org)\n // AGLYN'S OWN GUARDS ON THE OVERAGE IT EXTENDS (AGL-3011), resolved here\n // for the same reason the ceilings above are: pure arithmetic over a\n // document the caller already holds, and a transaction that retries must\n // not re-derive them.\n //\n // They apply only where there IS overage to guard — a band that is sold\n // past, at a rate — and only from the month the platform bills that\n // overage by invoice. Before that month nothing charges, so nothing is\n // ever paid for, so an unpaid-balance guard would refuse every workspace\n // with no invoice to pay. See `ai-overage-cutover.ts`.\n const guardsOverage =\n !bandRefuses &&\n budgetUsd !== null &&\n resolveAssistOverageRateUsdPer1k(org) !== null &&\n aiOverageGuardsApply(month)\n\n return firestore.runTransaction(async (tx) => {\n // Every read before any write — Firestore requires that ordering, and it\n // is also what makes check-and-increment a single atomic step.\n const snapshot = await tx.get(gateRef)\n // The spend ceiling reads the SAME monthly document the entitled gate\n // already read, so an entitled reservation costs no extra read at all\n // and a free one costs a second read only when a ceiling is configured.\n const monthlySnapshot = entitled\n ? snapshot\n : costLimitUsd === null\n ? null\n : await tx.get(monthlyRef)\n // The taste's two extra reads, only for a Free workspace: the owner's\n // account month (when the org names an owner) and the platform's day.\n // Inside the transaction with everything else, so the rungs they feed\n // are decided against the same snapshot the counters move under.\n // The workspace's overage standing (AGL-3011): one document, read only\n // where the guards apply, beside the reads the gate already makes. The\n // allotment gate reads a plugin document in this transaction the same\n // way, and for the same reason — a guard decided against a snapshot the\n // transaction did not take is a guard a concurrent burst walks past.\n const standingSnapshot = guardsOverage\n ? await tx.get(\n orgRef.collection(AI_BILLING_SUBCOLLECTION).doc(AI_BILLING_STANDING_DOC),\n )\n : null\n const accountSnapshot = accountRef ? await tx.get(accountRef) : null\n const platformSnapshot = free\n ? await tx.get(platformFreeSpendRef(firestore, day))\n : null\n const used = Number(snapshot.get(gateField) ?? 0)\n const costUsd = monthlySnapshot\n ? Number(monthlySnapshot.get('estCostUsd') ?? 0)\n : null\n if (!(used < limit)) {\n recordAssistRefusal(firestore, orgId, month, 'messages')\n return {\n allowed: false,\n refusedBy: 'messages' as const,\n period,\n dayKey: day,\n monthKey: month,\n used,\n limit,\n remaining: 0,\n costUsd,\n costLimitUsd,\n budgetUsd,\n free,\n }\n }\n // The dollar ceiling, checked AFTER the message cap so the cheaper and\n // more explicable refusal wins when both apply. Refusing here leaves both\n // counters untouched, exactly like the message refusal above: the point\n // of a spend ceiling is that the org above it spends nothing more.\n if (costLimitUsd !== null && costUsd !== null && !(costUsd < costLimitUsd)) {\n recordAssistRefusal(firestore, orgId, month, ceilingIsBand ? 'band' : 'budget')\n return {\n allowed: false,\n refusedBy: ceilingIsBand ? ('band' as const) : ('budget' as const),\n period,\n dayKey: day,\n monthKey: month,\n used,\n limit,\n remaining: Math.max(0, limit - used),\n costUsd,\n costLimitUsd,\n budgetUsd,\n free,\n }\n }\n // The org's ceiling on its OVERAGE (AGL-2898), checked after the band\n // because it only exists on a band that is sold past. Same shape as the\n // refusals above — inside the transaction, against the spend the\n // transaction read, moving no counter — so a burst of concurrent\n // requests at the ceiling cannot each read \"under\" and all proceed.\n // `assistOverageCapReached` prices the month's overage the way the\n // invoice will, so the figure that stops here is the figure that would\n // have been billed.\n if (\n overageCapUsd !== null &&\n costUsd !== null &&\n assistOverageCapReached(org, costUsd)\n ) {\n recordAssistRefusal(firestore, orgId, month, 'cap')\n return {\n allowed: false,\n refusedBy: 'cap' as const,\n // Whose ceiling, for the doors (AGL-3011). This one is the\n // workspace's own, and it keeps the sentence and the 402 it has had\n // since AGL-2898 — the four below are Aglyn's and have their own.\n capReason: 'customer' as const,\n period,\n dayKey: day,\n monthKey: month,\n used,\n limit,\n remaining: Math.max(0, limit - used),\n costUsd,\n costLimitUsd,\n budgetUsd,\n free,\n }\n }\n // AGLYN'S OWN OVERAGE GUARDS (AGL-3011), after the workspace's own\n // ceiling so a workspace that set a limit is told about ITS limit.\n //\n // Four refusals, all `refusedBy: 'cap'` with a `capReason`: no card on\n // file, accrual paused, this month's ceiling reached, and the unpaid\n // balance at its limit. The last is the one that makes the bound a\n // bound — it compares what the month accrued against what it PAID, so\n // overage stops at the unpaid limit whether or not any charge ever ran.\n //\n // Inside the transaction, against the figures the transaction read,\n // moving no counter: a burst of concurrent requests at the limit cannot\n // each read \"under\" and all proceed.\n const overageGuard =\n guardsOverage && costUsd !== null && budgetUsd !== null && costUsd >= budgetUsd\n ? aiOverageRefusal({\n // Priced the way the invoice prices it, so the figure that\n // stops here is the figure that would have been charged.\n overageUsd: assistMonthOverage(org, costUsd).overageMonthlyUsd,\n paidUsd: readAiOverageMonthLedger(\n monthlySnapshot?.data() ?? null,\n ).paidUsd,\n standing: readAiOverageStanding(\n standingSnapshot?.exists ? (standingSnapshot.data() ?? null) : null,\n ),\n now,\n })\n : null\n if (overageGuard) {\n recordAssistRefusal(firestore, orgId, month, 'cap')\n return {\n allowed: false,\n refusedBy: 'cap' as const,\n capReason: overageGuard.capReason,\n overageLimitUsd: overageGuard.limitUsd,\n overageUnpaidUsd: overageGuard.unpaidUsd,\n period,\n dayKey: day,\n monthKey: month,\n used,\n limit,\n remaining: Math.max(0, limit - used),\n costUsd,\n costLimitUsd,\n budgetUsd,\n free,\n }\n }\n // The allotments that apply to the person asking (AGL-2942): read only\n // now that the workspace's own ceilings admitted the request, so an\n // allotment is decided inside the band and a refusal at the band costs\n // no allotment read. Reads, still — every write waits below.\n const allotment = subject\n ? await readAiAllotmentGate(\n (ref) => tx.get(ref),\n orgRef,\n subject,\n month,\n monthlySnapshot,\n )\n : null\n if (allotment?.refusal) {\n recordAssistRefusal(firestore, orgId, month, 'allotment')\n return {\n allowed: false,\n refusedBy: 'allotment' as const,\n period,\n dayKey: day,\n monthKey: month,\n used,\n limit,\n remaining: Math.max(0, limit - used),\n costUsd,\n costLimitUsd,\n budgetUsd,\n free,\n allotment,\n }\n }\n // The Free taste's own rungs (AGL-2925), AFTER the workspace's, so a\n // workspace at its own band is told about its own band. Same shape:\n // decided inside the transaction, against what it read, moving nothing.\n const tasteRefusal = free\n ? freeTasteRefusal(freeTasteReadsFrom(accountSnapshot, platformSnapshot, day))\n : null\n if (tasteRefusal) {\n recordAssistRefusal(firestore, orgId, month, tasteRefusal)\n return {\n allowed: false,\n refusedBy: tasteRefusal,\n period,\n dayKey: day,\n monthKey: month,\n used,\n limit,\n remaining: Math.max(0, limit - used),\n costUsd,\n costLimitUsd,\n budgetUsd,\n free,\n allotment,\n }\n }\n // `set(…, { merge: true })` and never `update()`: the counter document\n // does not exist before an org's first message, and `update()` throws\n // NOT_FOUND on a missing doc where a merging set conjures it.\n tx.set(dailyRef, { [day]: increment(1) }, { merge: true })\n tx.set(\n monthlyRef,\n { month, messages: increment(1), updatedAt: serverTimestamp() },\n { merge: true },\n )\n // The account's request, counted in the same commit as the org's\n // message — one atomic step, or the daily request cap has the same\n // read-then-write hole the message cap was moved here to close.\n if (accountRef) {\n tx.set(accountRef, freeAccountReservationWrite(month, day), { merge: true })\n }\n return {\n allowed: true,\n refusedBy: null,\n period,\n dayKey: day,\n monthKey: month,\n used: used + 1,\n limit,\n remaining: Math.max(0, limit - (used + 1)),\n costUsd,\n costLimitUsd,\n budgetUsd,\n free,\n allotment,\n }\n })\n}\n\n/** A reservation with every dollar of provider spend removed. */\nexport interface PublicAssistQuota {\n allowed: boolean\n period: 'day' | 'month'\n used: number\n limit: number\n remaining: number\n refusedBy: AiRefusedBy\n /**\n * The credit standing, or `null` when the org's plan sells no assist band.\n *\n * Null rather than a converted backstop, because a Free workspace refused\n * at the operator's ceiling has no credit balance to report and telling it\n * \"0 of 40,000 credits left\" names a band it was never sold.\n */\n credits: PublicAssistCredits | null\n}\n\n/**\n * The reservation as a CUSTOMER may see it.\n *\n * `AssistReservation` carries `costUsd`, `costLimitUsd` and `budgetUsd`, and\n * all three are our provider bill at the serving model's list rates. Handing\n * the reservation itself to a browser publishes our model costs, and they\n * would move under customers on every model swap. Assist is surfaced in\n * CREDITS, whose meaning is fixed, and this is the one function that crosses\n * that boundary — every route returning quota to a client returns this.\n *\n * `limit` and `remaining` stay MESSAGES, unchanged: the free tier's daily\n * message cap is a real, separately-worded limit that the panel already\n * renders, and folding it into credits would make \"10 messages a day\"\n * unsayable.\n *\n * The credit view reads against the LOWER of the plan band and the effective\n * ceiling. The band, because it is the quantity the org was sold and the line\n * `report-usage` bills past — an org buying overage (AGL-2653) has no ceiling\n * at all, and reading against `null` would blank its standing at \"used 900 of\n * nothing\". The ceiling, because an org whose band was undercut by an\n * operator's figure must not be told it has credits left while being refused.\n * `remaining` clamps at zero, so a workspace past its band reads as spent\n * rather than as owed.\n */\nexport function publicAssistQuota(\n reservation: AssistReservation,\n): PublicAssistQuota {\n const { budgetUsd, costLimitUsd, costUsd } = reservation\n const ceilingUsd =\n budgetUsd === null\n ? null\n : costLimitUsd === null\n ? budgetUsd\n : Math.min(budgetUsd, costLimitUsd)\n return {\n allowed: reservation.allowed,\n period: reservation.period,\n used: reservation.used,\n limit: reservation.limit,\n remaining: reservation.remaining,\n refusedBy: reservation.refusedBy,\n credits: ceilingUsd === null ? null : publicAssistCredits(costUsd, ceilingUsd),\n }\n}\n\n/**\n * Hand a reservation back when the provider was never reached (AGL-2057): an\n * upstream 502 spent no tokens, so it must not spend one of a free\n * workspace's ten messages a day either.\n *\n * Released against the keys the RESERVATION recorded — see\n * `AssistReservation`. Each counter is read first so neither can be driven\n * below zero, even if the same reservation were released twice: a negative\n * counter is extra capacity, and the release path must not become the\n * laundering route the reservation was added to close.\n */\nexport async function releaseAssistMessage(\n firestore: FirebaseFirestore.Firestore,\n orgId: string,\n reservation: Pick<AssistReservation, 'allowed' | 'dayKey' | 'monthKey'> &\n Partial<Pick<AssistReservation, 'free'>>,\n): Promise<void> {\n if (!reservation.allowed) return\n const increment = FieldValue.increment\n const orgRef = firestore.collection('orgs').doc(orgId)\n const dailyRef = orgRef.collection('counters').doc('assistMessagesDaily')\n const monthlyRef = orgRef.collection('assistUsage').doc(reservation.monthKey)\n // The account's request goes back with the org's message (AGL-2925) —\n // against the same keys, read first for the same reason.\n const accountRef = reservation.free?.accountUid\n ? freeAccountUsageRef(firestore, reservation.free.accountUid, reservation.monthKey)\n : null\n await firestore.runTransaction(async (tx) => {\n const dailySnapshot = await tx.get(dailyRef)\n const monthlySnapshot = await tx.get(monthlyRef)\n const accountSnapshot = accountRef ? await tx.get(accountRef) : null\n if (Number(dailySnapshot.get(reservation.dayKey) ?? 0) > 0) {\n tx.set(dailyRef, { [reservation.dayKey]: increment(-1) }, { merge: true })\n }\n if (Number(monthlySnapshot.get('messages') ?? 0) > 0) {\n tx.set(monthlyRef, { messages: increment(-1) }, { merge: true })\n }\n if (accountRef && accountSnapshot) {\n const days = (accountSnapshot.get('days') ?? {}) as Record<\n string,\n { requests?: unknown } | undefined\n >\n const today = Number(days[reservation.dayKey]?.requests ?? 0)\n const month = Number(accountSnapshot.get('requests') ?? 0)\n if (today > 0 || month > 0) {\n tx.set(\n accountRef,\n {\n ...(month > 0 ? { requests: increment(-1) } : {}),\n ...(today > 0\n ? { days: { [reservation.dayKey]: { requests: increment(-1) } } }\n : {}),\n },\n { merge: true },\n )\n }\n }\n })\n}\n\n/**\n * READ-ONLY view of where an org stands against its cap.\n *\n * ⚠️ NOT the enforcement path any more (AGL-2057) — `reserveAssistMessage` is.\n * A read that is followed by a separate write is exactly the shape that let\n * concurrent requests and abandoned streams past the cap; this function is\n * kept for reporting and for tests that want the standing without consuming a\n * message. **Anything that decides whether to call the model must reserve.**\n *\n * Free orgs meter per UTC day; entitled orgs carry the monthly runaway guard.\n */\nexport async function checkAssistQuota(\n firestore: FirebaseFirestore.Firestore,\n orgId: string,\n entitled: boolean,\n now = new Date(),\n): Promise<AssistQuotaVerdict> {\n if (entitled) {\n const limit = assistEntitledMonthlyLimit()\n const month = assistUsageMonth(now)\n const snapshot = await firestore\n .collection('orgs')\n .doc(orgId)\n .collection('assistUsage')\n .doc(month)\n .get()\n const used = Number(snapshot.get('messages') ?? 0)\n return {\n allowed: used < limit,\n period: 'month',\n used,\n limit,\n remaining: Math.max(0, limit - used),\n }\n }\n const limit = assistFreeDailyLimit()\n const day = assistUsageDay(now)\n const snapshot = await firestore\n .collection('orgs')\n .doc(orgId)\n .collection('counters')\n .doc('assistMessagesDaily')\n .get()\n const used = Number(snapshot.get(day) ?? 0)\n return {\n allowed: used < limit,\n period: 'day',\n used,\n limit,\n remaining: Math.max(0, limit - used),\n }\n}\n\n/**\n * The DERIVED half of one assist turn: what it cost, what it cited, how it\n * stopped. No prose and no uid, by construction — see the module header.\n *\n * Split out of `AssistExchangeRecord` (AGL-2073) because the besigner copy\n * assistant at `/api/ai/assist` needs the meters WITHOUT the verbatim half.\n * What a customer types into that surface is their own site copy and blog\n * bodies, and retaining it for 180 days is a data flow the published privacy\n * disclosure does not describe. The margin question — what did this org's\n * assist usage cost us — is answered entirely by this record.\n */\nexport interface AssistSignalRecord {\n /** Console route the user asked from, e.g. `/org/acme/hosts`. */\n route: string\n hostId: string | null\n model: string\n /** Capability tier served: 'free' (level 1) or 'entitled' (level 1–2). */\n tier: 'free' | 'entitled'\n usage: AssistTokenUsage\n /** Docs paths cited in grounding, for the docs-gap mining view. */\n docsPaths: string[]\n /**\n * The model's own `stop_reason` (`end_turn` | `refusal` | `max_tokens` |\n * …), or null when the stream ended without one. Stored because a\n * refusal and a truncation both look like a short answer in the data —\n * and a rising refusal rate is a prompt problem, while a rising\n * max_tokens rate is a ceiling problem. They need different fixes.\n */\n stopReason: string | null\n /**\n * True when the answer came from the docs index with NO model call\n * (AGL-2486).\n *\n * Optional only so the two existing callers need not be edited in the same\n * breath; it is written as an explicit boolean either way, never left\n * undefined on the document. An absent field would make \"this turn used no\n * model\" and \"this turn predates the flag\" the same value, and the whole\n * point of the field is that an operator can tell how much of the month was\n * free.\n */\n deflected?: boolean\n /**\n * The Free taste's attribution (AGL-2925), copied from the reservation\n * that admitted this turn: `null` or absent for a paid workspace, and for\n * a turn that took no reservation. Present, the turn's cost also lands on\n * the platform's day of free spend and — unless the model refused — on\n * the owner's account allowance.\n */\n free?: FreeAssistAccount | null\n /**\n * Who asked, for the per-user rollup (AGL-2928) and NOTHING else: the\n * signal document never carries it, for the reason the module header\n * gives. Optional because a meter that cannot say who asked still owes\n * the org its cost; such a request attributes to nobody.\n */\n uid?: string | null\n /**\n * What the request was for, as the per-user rollup buckets it. A job\n * step names its job's kind; a meter without one is read off `route`.\n */\n kind?: AiUsageKind\n /**\n * How many canvas edits the answer proposed (AGL-2906), on a turn that\n * proposed any. A count and nothing of the edits: the applied-edit door\n * reads it back as the evidence that this turn issued a proposal, and a\n * turn that proposed none carries no field at all.\n */\n editOps?: number\n}\n\n/** A signal PLUS the verbatim half — the question, the answer, the asker. */\nexport interface AssistExchangeRecord extends AssistSignalRecord {\n uid: string\n question: string\n answer: string\n}\n\n/**\n * The signal document and the monthly cost rollup — the two writes every\n * assist turn owes regardless of whether its prose is kept. Shared by\n * `recordAssistExchange` and `recordAssistCost` so the meter has exactly one\n * writer and the two entrypoints can never drift into reporting different\n * money for the same tokens.\n */\nfunction writeSignalAndRollup(\n firestore: FirebaseFirestore.Firestore,\n batch: FirebaseFirestore.WriteBatch,\n orgRef: FirebaseFirestore.DocumentReference,\n signalRef: FirebaseFirestore.DocumentReference,\n record: AssistSignalRecord,\n now: Date,\n /** What the request was for, as the caller's own rollup names it. */\n kind: AiUsageKind,\n): void {\n const increment = FieldValue.increment\n const serverTimestamp = FieldValue.serverTimestamp\n const estCostUsd = estimateAssistCostUsd(record.usage, record.model)\n // What the same tokens COST US (AGL-3015). Recorded beside the billed\n // figure rather than derived from it later: a month is a sum over models\n // and a markup lives on the model, so once the exchanges are added up the\n // mix is gone and the two can no longer be told apart.\n const providerCostUsd = estimateAssistProviderCostUsd(record.usage, record.model)\n const deflected = record.deflected === true\n const free = record.free ?? null\n // On the Free taste a `refusal` stop draws no credits (AGL-2925): the\n // org's band and the account's allowance stay where they were, and the\n // cost goes to the platform's day instead, where it is still our money.\n // Everywhere else the tokens are metered as they always were.\n const refusedFree = free !== null && record.stopReason === 'refusal'\n // The site's credits for its allotment (AGL-2942), rounded as the person's\n // own `byHost` rounds them, so a site's month equals the sum of its\n // people's months on it. Not zeroed for a declined Free turn, for the same\n // reason the person's month is not: the site did spend it.\n const hostId = String(record.hostId ?? '').trim()\n const hostCredits = hostId ? assistCreditsFromUsd(estCostUsd) : 0\n // The analytic half. No prose and NO uid — deliberately, because a signal\n // row that names the asker is just the exchange with the words removed,\n // and would re-create as an access-request obligation exactly what the\n // expiry was meant to retire. What survives answers \"which docs gaps, at\n // what cost, rated how\", which is the whole of the data loop.\n batch.set(signalRef, {\n route: record.route,\n hostId: record.hostId,\n model: record.model,\n tier: record.tier,\n kind,\n inputTokens: record.usage.inputTokens,\n outputTokens: record.usage.outputTokens,\n cacheReadTokens: record.usage.cacheReadTokens,\n cacheWriteTokens: record.usage.cacheWriteTokens,\n estCostUsd,\n [ASSIST_PROVIDER_COST_FIELD]: providerCostUsd,\n docsPaths: record.docsPaths,\n stopReason: record.stopReason,\n deflected,\n feedback: null,\n ...(record.editOps && record.editOps > 0\n ? { editOps: Math.floor(record.editOps) }\n : {}),\n createdAt: serverTimestamp(),\n })\n // NO message counting here (AGL-2057). Both message counters are moved by\n // `reserveAssistMessage`, BEFORE the provider is called — which is what\n // makes the cap a cap. Counting again here would double every message, and\n // more importantly would restore the belief that this is where the cap\n // advances: it is not, and an exchange that never reaches this function\n // (an abandoned stream) has already been counted.\n batch.set(\n orgRef.collection('assistUsage').doc(assistUsageMonth(now)),\n {\n month: assistUsageMonth(now),\n // The free half of the month, counted where the paid half already is\n // (AGL-2486). `messages` counts what the RESERVATION moved — model\n // turns — and a deflected turn takes no reservation because it spends\n // nothing, so without this counter the questions Assist answered for\n // free are invisible and the deflection rate can only be guessed at.\n // Total questions asked is `messages + deflected`; neither field alone\n // is that number, and reading `messages` as it would understate usage\n // by exactly the amount this work was done to create.\n deflected: increment(deflected ? 1 : 0),\n inputTokens: increment(record.usage.inputTokens),\n outputTokens: increment(record.usage.outputTokens),\n cacheReadTokens: increment(record.usage.cacheReadTokens),\n cacheWriteTokens: increment(record.usage.cacheWriteTokens),\n estCostUsd: increment(refusedFree ? 0 : estCostUsd),\n // Our bill for the same turns, credited and refused alike on the same\n // rule as `estCostUsd` above, so the month's two dollar figures always\n // describe the same set of exchanges and a margin taken across them is\n // a margin over one period.\n [ASSIST_PROVIDER_COST_FIELD]: increment(refusedFree ? 0 : providerCostUsd),\n // The refused half of a Free month, kept beside the credited half so\n // the rollup still says what the month cost us in total. Its own field\n // name (AGL-2986): `refusals` on this document is the gate's map of\n // refusal counts by reason (`recordAssistRefusal`), and an increment\n // over a map replaces the map with the operand.\n refusedTurns: increment(refusedFree ? 1 : 0),\n refusedCostUsd: increment(refusedFree ? estCostUsd : 0),\n // What each model request was for, with its tokens (AGL-2937): cost\n // per generation, tokens per kind and the cache hit rate are read off\n // this map. A docs answer bought nothing and is left out. Both dollar\n // figures are kept — what the kind drew and what it cost us — because\n // the staff card reading this map is asking the second question and\n // the credit meter beside it is asking the first.\n // A declined Free turn is counted in both.\n ...(deflected\n ? {}\n : {\n [AI_USAGE_MONTH_KINDS_FIELD]: {\n [kind]: {\n requests: increment(1),\n estCostUsd: increment(estCostUsd),\n [ASSIST_PROVIDER_COST_FIELD]: increment(providerCostUsd),\n [AI_USAGE_TOKENS_FIELD]: aiTokenIncrements(record.usage),\n },\n },\n }),\n ...(hostCredits > 0\n ? { [AI_HOST_CREDITS_FIELD]: { [hostId]: increment(hostCredits) } }\n : {}),\n updatedAt: serverTimestamp(),\n },\n { merge: true },\n )\n if (free) {\n const day = assistUsageDay(now)\n const writes = freeTasteMeterWrites({\n estCostUsd,\n refused: refusedFree,\n day,\n month: assistUsageMonth(now),\n })\n batch.set(platformFreeSpendRef(firestore, day), writes.platform, { merge: true })\n if (free.accountUid) {\n batch.set(\n freeAccountUsageRef(firestore, free.accountUid, assistUsageMonth(now)),\n writes.account,\n { merge: true },\n )\n }\n }\n}\n\n/**\n * After a Free turn's batch commits: the ceiling's announcements, which\n * need the figure the batch just moved and must never fail the turn.\n */\nasync function announceFreeTurn(\n firestore: FirebaseFirestore.Firestore,\n record: AssistSignalRecord,\n now: Date,\n): Promise<void> {\n if (!record.free) return\n await announcePlatformFreeSpend(firestore, assistUsageDay(now)).catch((error) =>\n console.error('[ai-free-spend] announcement failed', error),\n )\n}\n\n/**\n * Meter one assist turn that keeps NO verbatim record (AGL-2073) — the\n * besigner copy assistant at `/api/ai/assist`.\n *\n * Writes the signal and folds tokens/cost into the monthly rollup, and writes\n * nothing to `assistExchanges`. Same reason the console route splits the two:\n * the loop's corpus was never the words. Here there is no loop to feed and no\n * thumbs to collect, so the words are simply not taken.\n *\n * Like `recordAssistExchange` it counts NO message — the reservation did that\n * before the tokens were spent. Callers should not let a metering failure fail\n * the request: the tokens are already spent either way, and refusing the\n * answer the customer paid for would make an accounting problem a product one.\n */\nexport async function recordAssistCost(\n firestore: FirebaseFirestore.Firestore,\n orgId: string,\n record: AssistSignalRecord,\n now = new Date(),\n): Promise<string> {\n const orgRef = firestore.collection('orgs').doc(orgId)\n const signalRef = orgRef.collection('assistSignals').doc()\n const batch = firestore.batch()\n const kind = record.kind ?? aiUsageKindFromRoute(record.route)\n writeSignalAndRollup(firestore, batch, orgRef, signalRef, record, now, kind)\n // The person's month, on the SAME batch as the org's (AGL-2928), so the\n // two rollups commit together or not at all.\n recordUserAiUsage(batch, orgRef, {\n uid: record.uid,\n month: assistUsageMonth(now),\n estCostUsd: estimateAssistCostUsd(record.usage, record.model),\n hostId: record.hostId,\n kind,\n usage: record.usage,\n })\n await batch.commit()\n chargeAccruedOverage(firestore, orgId, assistUsageMonth(now), now)\n await announceFreeTurn(firestore, record, now)\n return signalRef.id\n}\n\n/**\n * The data loop + meters, one batch: writes the two halves of the exchange\n * and folds tokens/cost into the monthly usage doc. It does NOT count the\n * message — `reserveAssistMessage` already did, before the tokens were spent.\n * Returns the shared id (the feedback route addresses it later). Callers\n * `await` this — an exchange that fails to record should surface in logs,\n * but the batch is one round trip so it does not add meaningful latency.\n *\n * The two halves share one id ON PURPOSE. It is what lets the feedback route\n * keep its single-id signature, and it is what makes an exchange and its\n * signal joinable for as long as both exist — without storing a second\n * pointer that could rot.\n */\nexport async function recordAssistExchange(\n firestore: FirebaseFirestore.Firestore,\n orgId: string,\n record: AssistExchangeRecord,\n now = new Date(),\n): Promise<string> {\n const serverTimestamp = FieldValue.serverTimestamp\n const orgRef = firestore.collection('orgs').doc(orgId)\n const exchangeRef = orgRef.collection('assistExchanges').doc()\n const signalRef = orgRef.collection('assistSignals').doc(exchangeRef.id)\n\n const batch = firestore.batch()\n // The personal half. Everything a person typed, everything we said back,\n // and who asked — and nothing else. Expires.\n batch.set(exchangeRef, {\n uid: record.uid,\n question: record.question,\n answer: record.answer,\n hostId: record.hostId,\n createdAt: serverTimestamp(),\n expiresAt: assistExchangeExpiry(now),\n })\n // A chat turn is an `assist` request whatever console route it was asked\n // from — on the signal, the org's month and the asker's month alike.\n const kind = record.kind ?? 'assist'\n // The analytic half plus the meters — the same writer `recordAssistCost`\n // uses, so the two assist entrypoints can never report different money for\n // the same tokens.\n writeSignalAndRollup(firestore, batch, orgRef, signalRef, record, now, kind)\n // And the asker's month, on the same batch (AGL-2928).\n recordUserAiUsage(batch, orgRef, {\n uid: record.uid,\n month: assistUsageMonth(now),\n estCostUsd: estimateAssistCostUsd(record.usage, record.model),\n hostId: record.hostId,\n kind,\n usage: record.usage,\n })\n await batch.commit()\n chargeAccruedOverage(firestore, orgId, assistUsageMonth(now), now)\n await announceFreeTurn(firestore, record, now)\n return exchangeRef.id\n}\n\n/**\n * Record explicit thumbs feedback on an exchange. Only the exchange's own\n * org path is addressable, and only the two literal values are accepted —\n * the route validates membership before calling this.\n *\n * The rating lands on the SIGNAL document, not the exchange (AGL-1972). A\n * thumbs-down is the single most valuable row in the data loop and it is not\n * personal content, so it must not be reaped along with the prose that\n * earned it. Existence is checked on the signal too: it is the document\n * being written, and after the exchange expires it is the only one left.\n */\nexport async function recordAssistFeedback(\n firestore: FirebaseFirestore.Firestore,\n orgId: string,\n exchangeId: string,\n feedback: 'up' | 'down',\n): Promise<boolean> {\n const ref = firestore\n .collection('orgs')\n .doc(orgId)\n .collection('assistSignals')\n .doc(exchangeId)\n const snapshot = await ref.get()\n if (!snapshot.exists) return false\n await ref.update({ feedback })\n return true\n}\n"],"names":["FieldValue","ASSIST_PROVIDER_COST_FIELD","assistBandRefuses","assistCreditsFromUsd","assistMonthOverage","assistOverageCapReached","publicAssistCredits","resolveAssistBudgetUsd","resolveAssistOverageCapUsd","resolveAssistOverageRateUsdPer1k","aiOverageRefusal","aiOverageBillsByInvoice","aiOverageGuardsApply","AI_BILLING_STANDING_DOC","AI_BILLING_SUBCOLLECTION","readAiOverageMonthLedger","readAiOverageStanding","AI_HOST_CREDITS_FIELD","readAiAllotmentGate","isUncappedPlanComp","assistMonthlyCeilingUsd","estimateAiBilledUsd","estimateAiProviderCostUsd","recordAssistRefusal","announcePlatformFreeSpend","freeAccountReservationWrite","freeAccountUsageRef","freeAssistAccount","freeTasteMeterWrites","freeTasteReadsFrom","freeTasteRefusal","platformFreeSpendRef","aiTokenIncrements","recordUserAiUsage","AI_USAGE_MONTH_KINDS_FIELD","AI_USAGE_TOKENS_FIELD","aiUsageKindFromRoute","assistUsageMonth","now","Date","toISOString","slice","assistUsageDay","ASSIST_EXCHANGE_RETENTION_DAYS","DAY_MS","assistExchangeExpiry","getTime","assistFreeDailyLimit","raw","process","env","ASSIST_FREE_DAILY_LIMIT","parsed","Number","NaN","isFinite","Math","floor","assistEntitledMonthlyLimit","ASSIST_ENTITLED_MONTHLY_LIMIT","estimateAssistCostUsd","usage","model","estimateAssistProviderCostUsd","reserveAssistMessage","firestore","orgId","entitled","org","subject","reservation","reserveInTransaction","allotment","alerts","length","announceAllotmentAlerts","then","announceAiAllotmentAlerts","orgSlug","slug","String","month","monthKey","catch","error","console","chargeAccruedOverage","chargeAccruedAiOverage","increment","serverTimestamp","orgRef","collection","doc","day","dailyRef","monthlyRef","limit","period","gateRef","gateField","free","accountRef","accountUid","budgetUsd","bandRefuses","costLimitUsd","ceilingIsBand","overageCapUsd","guardsOverage","runTransaction","tx","snapshot","monthlySnapshot","standingSnapshot","get","accountSnapshot","platformSnapshot","used","costUsd","allowed","refusedBy","dayKey","remaining","max","capReason","overageGuard","overageUsd","overageMonthlyUsd","paidUsd","data","standing","exists","overageLimitUsd","limitUsd","overageUnpaidUsd","unpaidUsd","ref","refusal","tasteRefusal","set","merge","messages","updatedAt","publicAssistQuota","ceilingUsd","min","credits","releaseAssistMessage","dailySnapshot","days","today","requests","checkAssistQuota","writeSignalAndRollup","batch","signalRef","record","kind","estCostUsd","providerCostUsd","deflected","refusedFree","stopReason","hostId","trim","hostCredits","route","tier","inputTokens","outputTokens","cacheReadTokens","cacheWriteTokens","docsPaths","feedback","editOps","createdAt","refusedTurns","refusedCostUsd","writes","refused","platform","account","announceFreeTurn","recordAssistCost","uid","commit","id","recordAssistExchange","exchangeRef","question","answer","expiresAt","recordAssistFeedback","exchangeId","update"],"mappings":";AAAA;;;;;;;;;;;;;;;CAeC,GAED;;;;;;;CAOC,GACD,SAASA,UAAU,QAAQ,2BAA0B;AACrD,SACEC,0BAA0B,EAC1BC,iBAAiB,EACjBC,oBAAoB,EACpBC,kBAAkB,EAClBC,uBAAuB,EACvBC,mBAAmB,EACnBC,sBAAsB,EACtBC,0BAA0B,EAC1BC,gCAAgC,QAE3B,wCAAuC;AAC9C,SACEC,gBAAgB,QAEX,gCAA4B;AACnC,SACEC,uBAAuB,EACvBC,oBAAoB,QACf,mCAA+B;AACtC,SACEC,uBAAuB,EACvBC,wBAAwB,EACxBC,wBAAwB,QACnB,kCAA8B;AACrC,SAASC,qBAAqB,QAAQ,oCAAgC;AAEtE,SACEC,qBAAqB,EACrBC,mBAAmB,QAGd,qBAAiB;AACxB,SAASC,kBAAkB,QAAQ,2CAA0C;AAC7E,SAASC,uBAAuB,QAAQ,sBAAkB;AAC1D,SAASC,mBAAmB,EAAEC,yBAAyB,QAAQ,0BAAsB;AACrF,SAASC,mBAAmB,QAAQ,uBAAmB;AACvD,SACEC,yBAAyB,EACzBC,2BAA2B,EAC3BC,mBAAmB,EACnBC,iBAAiB,EACjBC,oBAAoB,EACpBC,kBAAkB,EAClBC,gBAAgB,EAChBC,oBAAoB,QAGf,yBAAqB;AAC5B,SAASC,iBAAiB,EAAEC,iBAAiB,QAAQ,wBAAoB;AACzE,SAASC,0BAA0B,EAAEC,qBAAqB,QAAQ,wBAAoB;AACtF,SACEC,oBAAoB,QAEf,+BAA2B;AAElC,8EAA8E;AAC9E,8EAA8E;AAC9E,yBAAyB;AACzB,SAAShB,uBAAuB,QAAQ,sBAAkB;AAE1D;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA8DC,GAED,qEAAqE,GACrE,OAAO,SAASiB,iBAAiBC,MAAM,IAAIC,MAAM;IAC/C,OAAOD,IAAIE,WAAW,GAAGC,KAAK,CAAC,GAAG;AACpC;AAEA,uEAAuE,GACvE,OAAO,SAASC,eAAeJ,MAAM,IAAIC,MAAM;IAC7C,OAAOD,IAAIE,WAAW,GAAGC,KAAK,CAAC,GAAG;AACpC;AAEA;;;;;;;;;;;;;;;;;;;;CAoBC,GACD,OAAO,MAAME,iCAAiC,IAAG;AAEjD,MAAMC,SAAS,KAAK,KAAK,KAAK;AAE9B;;;;;;;CAOC,GACD,OAAO,SAASC,qBAAqBP,MAAM,IAAIC,MAAM;IACnD,OAAO,IAAIA,KAAKD,IAAIQ,OAAO,KAAKH,iCAAiCC;AACnE;AAEA;;;;;;;;;;;;;;;;CAgBC,GACD,OAAO,SAASG;IACd,MAAMC,MAAMC,QAAQC,GAAG,CAACC,uBAAuB;IAC/C,oEAAoE;IACpE,sDAAsD;IACtD,MAAMC,SAASJ,MAAMK,OAAOL,OAAOK,OAAOC,GAAG;IAC7C,OAAOD,OAAOE,QAAQ,CAACH,WAAWA,UAAU,IAAII,KAAKC,KAAK,CAACL,UAAU;AACvE;AAEA;;;;CAIC,GACD,OAAO,SAASM;IACd,MAAMV,MAAMC,QAAQC,GAAG,CAACS,6BAA6B;IACrD,MAAMP,SAASJ,MAAMK,OAAOL,OAAOK,OAAOC,GAAG;IAC7C,OAAOD,OAAOE,QAAQ,CAACH,WAAWA,SAAS,IAAII,KAAKC,KAAK,CAACL,UAAU;AACtE;AASA;;;;;;;;;;;;;;;;;;;CAmBC,GACD,OAAO,SAASQ,sBACdC,KAAuB,EACvBC,KAAa;IAEb,OAAOzC,oBAAoBwC,OAAOC;AACpC;AAEA;;;;;;;;CAQC,GACD,OAAO,SAASC,8BACdF,KAAuB,EACvBC,KAAa;IAEb,OAAOxC,0BAA0BuC,OAAOC;AAC1C;AAqHA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA4FC,GACD,OAAO,eAAeE,qBACpBC,SAAsC,EACtCC,KAAa,EACbC,QAAiB,EACjB7B,MAAM,IAAIC,MAAM,EAChB6B,MAA+B,IAAI,EACnCC,UAA4C,IAAI;QAU5CC;IARJ,MAAMA,cAAc,MAAMC,qBACxBN,WACAC,OACAC,UACA7B,KACA8B,KACAC;IAEF,KAAIC,yBAAAA,YAAYE,SAAS,qBAArBF,uBAAuBG,MAAM,CAACC,MAAM,EAAE;QACxCC,wBAAwBV,WAAWC,OAAOE,KAAKE;IACjD;IACA,OAAOA;AACT;AAEA;;;;;;CAMC,GACD,SAASK,wBACPV,SAAsC,EACtCC,KAAa,EACbE,GAA4B,EAC5BE,WAA8B;;QAEfA;IAAf,MAAMG,kBAASH,yBAAAA,YAAYE,SAAS,qBAArBF,uBAAuBG,MAAM,mBAAI,EAAE;IAClD,KAAK,MAAM,CAAC,4BACTG,IAAI,CAAC,CAAC,EAAEC,yBAAyB,EAAE,GAClCA,0BAA0BZ,WAAW;YACnCC;YACAY,SAAS,QAAQV,uBAAD,AAACA,IAAmCW,IAAI,MAAK,WACzDC,OAAO,AAACZ,IAA2BW,IAAI,IACvC;YACJE,OAAOX,YAAYY,QAAQ;YAC3BT;QACF,IAEDU,KAAK,CAAC,CAACC,QAAUC,QAAQD,KAAK,CAAC,gCAAgClB,OAAOkB;AAC3E;AAEA;;;;;;;;;;;;;;;;CAgBC,GACD,SAASE,qBACPrB,SAAsC,EACtCC,KAAa,EACbe,KAAa,EACb3C,GAAS;IAET,IAAI,CAAC3B,wBAAwBsE,QAAQ;IACrC,KAAK,MAAM,CAAC,oCACTL,IAAI,CAAC,CAAC,EAAEW,sBAAsB,EAAE,GAC/BA,uBAAuBtB,WAAWC,OAAOe,OAAO3C,MAEjD6C,KAAK,CAAC,CAACC,QAAUC,QAAQD,KAAK,CAAC,8BAA8BlB,OAAOkB;AACzE;AAEA,eAAeb,qBACbN,SAAsC,EACtCC,KAAa,EACbC,QAAiB,EACjB7B,GAAS,EACT8B,GAA4B,EAC5BC,OAAyC;IAEzC,MAAMmB,YAAYxF,WAAWwF,SAAS;IACtC,MAAMC,kBAAkBzF,WAAWyF,eAAe;IAClD,MAAMC,SAASzB,UAAU0B,UAAU,CAAC,QAAQC,GAAG,CAAC1B;IAChD,MAAM2B,MAAMnD,eAAeJ;IAC3B,MAAM2C,QAAQ5C,iBAAiBC;IAC/B,MAAMwD,WAAWJ,OAAOC,UAAU,CAAC,YAAYC,GAAG,CAAC;IACnD,MAAMG,aAAaL,OAAOC,UAAU,CAAC,eAAeC,GAAG,CAACX;IACxD,MAAMe,QAAQ7B,WAAWT,+BAA+BX;IACxD,MAAMkD,SAA0B9B,WAAW,UAAU;IACrD,MAAM+B,UAAU/B,WAAW4B,aAAaD;IACxC,MAAMK,YAAYhC,WAAW,aAAa0B;IAC1C,mEAAmE;IACnE,uEAAuE;IACvE,cAAc;IACd,MAAMO,OAAOzE,kBAAkByC;IAC/B,MAAMiC,aACJD,CAAAA,wBAAAA,KAAME,UAAU,IAAG5E,oBAAoBuC,WAAWmC,KAAKE,UAAU,EAAErB,SAAS;IAE9E,2EAA2E;IAC3E,sEAAsE;IACtE,yEAAyE;IACzE,0EAA0E;IAC1E,YAAY;IACZ,MAAMsB,YAAYhG,uBAAuB6D;IACzC,MAAMoC,cAActG,kBAAkBkE;IACtC,yEAAyE;IACzE,MAAMqC,eAAerF,wBACnBmF,WACAC,aACArF,mBAAmBiD;IAErB,2EAA2E;IAC3E,wEAAwE;IACxE,0EAA0E;IAC1E,yDAAyD;IACzD,MAAMsC,gBACJF,eAAeD,cAAc,QAAQE,iBAAiBF;IACxD,uEAAuE;IACvE,yEAAyE;IACzE,kEAAkE;IAClE,MAAMI,gBAAgBH,cAAc,OAAOhG,2BAA2B4D;IACtE,yEAAyE;IACzE,qEAAqE;IACrE,yEAAyE;IACzE,sBAAsB;IACtB,EAAE;IACF,wEAAwE;IACxE,oEAAoE;IACpE,uEAAuE;IACvE,yEAAyE;IACzE,uDAAuD;IACvD,MAAMwC,gBACJ,CAACJ,eACDD,cAAc,QACd9F,iCAAiC2D,SAAS,QAC1CxD,qBAAqBqE;IAEvB,OAAOhB,UAAU4C,cAAc,CAAC,OAAOC;YA8BjBC,eAETC,4BA+F2BC;QA9HtC,yEAAyE;QACzE,+DAA+D;QAC/D,MAAMF,WAAW,MAAMD,GAAGI,GAAG,CAAChB;QAC9B,sEAAsE;QACtE,sEAAsE;QACtE,wEAAwE;QACxE,MAAMc,kBAAkB7C,WACpB4C,WACAN,iBAAiB,OACf,OACA,MAAMK,GAAGI,GAAG,CAACnB;QACnB,sEAAsE;QACtE,sEAAsE;QACtE,sEAAsE;QACtE,iEAAiE;QACjE,uEAAuE;QACvE,uEAAuE;QACvE,sEAAsE;QACtE,wEAAwE;QACxE,qEAAqE;QACrE,MAAMkB,mBAAmBL,gBACrB,MAAME,GAAGI,GAAG,CACVxB,OAAOC,UAAU,CAAC7E,0BAA0B8E,GAAG,CAAC/E,4BAElD;QACJ,MAAMsG,kBAAkBd,aAAa,MAAMS,GAAGI,GAAG,CAACb,cAAc;QAChE,MAAMe,mBAAmBhB,OACrB,MAAMU,GAAGI,GAAG,CAACnF,qBAAqBkC,WAAW4B,QAC7C;QACJ,MAAMwB,OAAOhE,QAAO0D,gBAAAA,SAASG,GAAG,CAACf,sBAAbY,gBAA2B;QAC/C,MAAMO,UAAUN,kBACZ3D,QAAO2D,uBAAAA,gBAAgBE,GAAG,CAAC,yBAApBF,uBAAqC,KAC5C;QACJ,IAAI,CAAEK,CAAAA,OAAOrB,KAAI,GAAI;YACnBzE,oBAAoB0C,WAAWC,OAAOe,OAAO;YAC7C,OAAO;gBACLsC,SAAS;gBACTC,WAAW;gBACXvB;gBACAwB,QAAQ5B;gBACRX,UAAUD;gBACVoC;gBACArB;gBACA0B,WAAW;gBACXJ;gBACAb;gBACAF;gBACAH;YACF;QACF;QACA,uEAAuE;QACvE,0EAA0E;QAC1E,wEAAwE;QACxE,mEAAmE;QACnE,IAAIK,iBAAiB,QAAQa,YAAY,QAAQ,CAAEA,CAAAA,UAAUb,YAAW,GAAI;YAC1ElF,oBAAoB0C,WAAWC,OAAOe,OAAOyB,gBAAgB,SAAS;YACtE,OAAO;gBACLa,SAAS;gBACTC,WAAWd,gBAAiB,SAAoB;gBAChDT;gBACAwB,QAAQ5B;gBACRX,UAAUD;gBACVoC;gBACArB;gBACA0B,WAAWlE,KAAKmE,GAAG,CAAC,GAAG3B,QAAQqB;gBAC/BC;gBACAb;gBACAF;gBACAH;YACF;QACF;QACA,sEAAsE;QACtE,wEAAwE;QACxE,iEAAiE;QACjE,iEAAiE;QACjE,oEAAoE;QACpE,mEAAmE;QACnE,uEAAuE;QACvE,oBAAoB;QACpB,IACEO,kBAAkB,QAClBW,YAAY,QACZjH,wBAAwB+D,KAAKkD,UAC7B;YACA/F,oBAAoB0C,WAAWC,OAAOe,OAAO;YAC7C,OAAO;gBACLsC,SAAS;gBACTC,WAAW;gBACX,2DAA2D;gBAC3D,oEAAoE;gBACpE,kEAAkE;gBAClEI,WAAW;gBACX3B;gBACAwB,QAAQ5B;gBACRX,UAAUD;gBACVoC;gBACArB;gBACA0B,WAAWlE,KAAKmE,GAAG,CAAC,GAAG3B,QAAQqB;gBAC/BC;gBACAb;gBACAF;gBACAH;YACF;QACF;QACA,mEAAmE;QACnE,mEAAmE;QACnE,EAAE;QACF,uEAAuE;QACvE,qEAAqE;QACrE,mEAAmE;QACnE,sEAAsE;QACtE,wEAAwE;QACxE,EAAE;QACF,oEAAoE;QACpE,wEAAwE;QACxE,qCAAqC;QACrC,MAAMyB,eACJjB,iBAAiBU,YAAY,QAAQf,cAAc,QAAQe,WAAWf,YAClE7F,iBAAiB;YACf,2DAA2D;YAC3D,yDAAyD;YACzDoH,YAAY1H,mBAAmBgE,KAAKkD,SAASS,iBAAiB;YAC9DC,SAASjH,iCACPiG,mCAAAA,gBAAiBiB,IAAI,qBAAM,MAC3BD,OAAO;YACTE,UAAUlH,sBACRiG,CAAAA,oCAAAA,iBAAkBkB,MAAM,KAAIlB,yBAAAA,iBAAiBgB,IAAI,cAArBhB,yBAA2B,OAAQ;YAEjE3E;QACF,KACA;QACN,IAAIuF,cAAc;YAChBtG,oBAAoB0C,WAAWC,OAAOe,OAAO;YAC7C,OAAO;gBACLsC,SAAS;gBACTC,WAAW;gBACXI,WAAWC,aAAaD,SAAS;gBACjCQ,iBAAiBP,aAAaQ,QAAQ;gBACtCC,kBAAkBT,aAAaU,SAAS;gBACxCtC;gBACAwB,QAAQ5B;gBACRX,UAAUD;gBACVoC;gBACArB;gBACA0B,WAAWlE,KAAKmE,GAAG,CAAC,GAAG3B,QAAQqB;gBAC/BC;gBACAb;gBACAF;gBACAH;YACF;QACF;QACA,uEAAuE;QACvE,oEAAoE;QACpE,uEAAuE;QACvE,6DAA6D;QAC7D,MAAM5B,YAAYH,UACd,MAAMnD,oBACJ,CAACsH,MAAQ1B,GAAGI,GAAG,CAACsB,MAChB9C,QACArB,SACAY,OACA+B,mBAEF;QACJ,IAAIxC,6BAAAA,UAAWiE,OAAO,EAAE;YACtBlH,oBAAoB0C,WAAWC,OAAOe,OAAO;YAC7C,OAAO;gBACLsC,SAAS;gBACTC,WAAW;gBACXvB;gBACAwB,QAAQ5B;gBACRX,UAAUD;gBACVoC;gBACArB;gBACA0B,WAAWlE,KAAKmE,GAAG,CAAC,GAAG3B,QAAQqB;gBAC/BC;gBACAb;gBACAF;gBACAH;gBACA5B;YACF;QACF;QACA,qEAAqE;QACrE,oEAAoE;QACpE,wEAAwE;QACxE,MAAMkE,eAAetC,OACjBtE,iBAAiBD,mBAAmBsF,iBAAiBC,kBAAkBvB,QACvE;QACJ,IAAI6C,cAAc;YAChBnH,oBAAoB0C,WAAWC,OAAOe,OAAOyD;YAC7C,OAAO;gBACLnB,SAAS;gBACTC,WAAWkB;gBACXzC;gBACAwB,QAAQ5B;gBACRX,UAAUD;gBACVoC;gBACArB;gBACA0B,WAAWlE,KAAKmE,GAAG,CAAC,GAAG3B,QAAQqB;gBAC/BC;gBACAb;gBACAF;gBACAH;gBACA5B;YACF;QACF;QACA,uEAAuE;QACvE,sEAAsE;QACtE,8DAA8D;QAC9DsC,GAAG6B,GAAG,CAAC7C,UAAU;YAAE,CAACD,IAAI,EAAEL,UAAU;QAAG,GAAG;YAAEoD,OAAO;QAAK;QACxD9B,GAAG6B,GAAG,CACJ5C,YACA;YAAEd;YAAO4D,UAAUrD,UAAU;YAAIsD,WAAWrD;QAAkB,GAC9D;YAAEmD,OAAO;QAAK;QAEhB,iEAAiE;QACjE,mEAAmE;QACnE,gEAAgE;QAChE,IAAIvC,YAAY;YACdS,GAAG6B,GAAG,CAACtC,YAAY5E,4BAA4BwD,OAAOY,MAAM;gBAAE+C,OAAO;YAAK;QAC5E;QACA,OAAO;YACLrB,SAAS;YACTC,WAAW;YACXvB;YACAwB,QAAQ5B;YACRX,UAAUD;YACVoC,MAAMA,OAAO;YACbrB;YACA0B,WAAWlE,KAAKmE,GAAG,CAAC,GAAG3B,QAASqB,CAAAA,OAAO,CAAA;YACvCC;YACAb;YACAF;YACAH;YACA5B;QACF;IACF;AACF;AAoBA;;;;;;;;;;;;;;;;;;;;;;;CAuBC,GACD,OAAO,SAASuE,kBACdzE,WAA8B;IAE9B,MAAM,EAAEiC,SAAS,EAAEE,YAAY,EAAEa,OAAO,EAAE,GAAGhD;IAC7C,MAAM0E,aACJzC,cAAc,OACV,OACAE,iBAAiB,OACfF,YACA/C,KAAKyF,GAAG,CAAC1C,WAAWE;IAC5B,OAAO;QACLc,SAASjD,YAAYiD,OAAO;QAC5BtB,QAAQ3B,YAAY2B,MAAM;QAC1BoB,MAAM/C,YAAY+C,IAAI;QACtBrB,OAAO1B,YAAY0B,KAAK;QACxB0B,WAAWpD,YAAYoD,SAAS;QAChCF,WAAWlD,YAAYkD,SAAS;QAChC0B,SAASF,eAAe,OAAO,OAAO1I,oBAAoBgH,SAAS0B;IACrE;AACF;AAEA;;;;;;;;;;CAUC,GACD,OAAO,eAAeG,qBACpBlF,SAAsC,EACtCC,KAAa,EACbI,WAC0C;QASvBA;IAPnB,IAAI,CAACA,YAAYiD,OAAO,EAAE;IAC1B,MAAM/B,YAAYxF,WAAWwF,SAAS;IACtC,MAAME,SAASzB,UAAU0B,UAAU,CAAC,QAAQC,GAAG,CAAC1B;IAChD,MAAM4B,WAAWJ,OAAOC,UAAU,CAAC,YAAYC,GAAG,CAAC;IACnD,MAAMG,aAAaL,OAAOC,UAAU,CAAC,eAAeC,GAAG,CAACtB,YAAYY,QAAQ;IAC5E,sEAAsE;IACtE,yDAAyD;IACzD,MAAMmB,aAAa/B,EAAAA,oBAAAA,YAAY8B,IAAI,qBAAhB9B,kBAAkBgC,UAAU,IAC3C5E,oBAAoBuC,WAAWK,YAAY8B,IAAI,CAACE,UAAU,EAAEhC,YAAYY,QAAQ,IAChF;IACJ,MAAMjB,UAAU4C,cAAc,CAAC,OAAOC;YAIzBsC,oBAGApC;QANX,MAAMoC,gBAAgB,MAAMtC,GAAGI,GAAG,CAACpB;QACnC,MAAMkB,kBAAkB,MAAMF,GAAGI,GAAG,CAACnB;QACrC,MAAMoB,kBAAkBd,aAAa,MAAMS,GAAGI,GAAG,CAACb,cAAc;QAChE,IAAIhD,QAAO+F,qBAAAA,cAAclC,GAAG,CAAC5C,YAAYmD,MAAM,aAApC2B,qBAAyC,KAAK,GAAG;YAC1DtC,GAAG6B,GAAG,CAAC7C,UAAU;gBAAE,CAACxB,YAAYmD,MAAM,CAAC,EAAEjC,UAAU,CAAC;YAAG,GAAG;gBAAEoD,OAAO;YAAK;QAC1E;QACA,IAAIvF,QAAO2D,uBAAAA,gBAAgBE,GAAG,CAAC,uBAApBF,uBAAmC,KAAK,GAAG;YACpDF,GAAG6B,GAAG,CAAC5C,YAAY;gBAAE8C,UAAUrD,UAAU,CAAC;YAAG,GAAG;gBAAEoD,OAAO;YAAK;QAChE;QACA,IAAIvC,cAAcc,iBAAiB;gBACnBA,4BAKOA;gBADAkC;YAJrB,MAAMA,QAAQlC,uBAAAA,gBAAgBD,GAAG,CAAC,mBAApBC,uBAA+B,CAAC;YAI9C,MAAMmC,QAAQjG,gBAAOgG,2BAAAA,IAAI,CAAC/E,YAAYmD,MAAM,CAAC,qBAAxB4B,yBAA0BE,QAAQ,mBAAI;YAC3D,MAAMtE,QAAQ5B,QAAO8D,wBAAAA,gBAAgBD,GAAG,CAAC,uBAApBC,wBAAmC;YACxD,IAAImC,QAAQ,KAAKrE,QAAQ,GAAG;gBAC1B6B,GAAG6B,GAAG,CACJtC,YACA,aACMpB,QAAQ,IAAI;oBAAEsE,UAAU/D,UAAU,CAAC;gBAAG,IAAI,CAAC,GAC3C8D,QAAQ,IACR;oBAAED,MAAM;wBAAE,CAAC/E,YAAYmD,MAAM,CAAC,EAAE;4BAAE8B,UAAU/D,UAAU,CAAC;wBAAG;oBAAE;gBAAE,IAC9D,CAAC,IAEP;oBAAEoD,OAAO;gBAAK;YAElB;QACF;IACF;AACF;AAEA;;;;;;;;;;CAUC,GACD,OAAO,eAAeY,iBACpBvF,SAAsC,EACtCC,KAAa,EACbC,QAAiB,EACjB7B,MAAM,IAAIC,MAAM;QA4BIwE;IA1BpB,IAAI5C,UAAU;YASQ4C;QARpB,MAAMf,QAAQtC;QACd,MAAMuB,QAAQ5C,iBAAiBC;QAC/B,MAAMyE,WAAW,MAAM9C,UACpB0B,UAAU,CAAC,QACXC,GAAG,CAAC1B,OACJyB,UAAU,CAAC,eACXC,GAAG,CAACX,OACJiC,GAAG;QACN,MAAMG,OAAOhE,QAAO0D,iBAAAA,SAASG,GAAG,CAAC,uBAAbH,iBAA4B;QAChD,OAAO;YACLQ,SAASF,OAAOrB;YAChBC,QAAQ;YACRoB;YACArB;YACA0B,WAAWlE,KAAKmE,GAAG,CAAC,GAAG3B,QAAQqB;QACjC;IACF;IACA,MAAMrB,QAAQjD;IACd,MAAM8C,MAAMnD,eAAeJ;IAC3B,MAAMyE,WAAW,MAAM9C,UACpB0B,UAAU,CAAC,QACXC,GAAG,CAAC1B,OACJyB,UAAU,CAAC,YACXC,GAAG,CAAC,uBACJsB,GAAG;IACN,MAAMG,OAAOhE,QAAO0D,gBAAAA,SAASG,GAAG,CAACrB,gBAAbkB,gBAAqB;IACzC,OAAO;QACLQ,SAASF,OAAOrB;QAChBC,QAAQ;QACRoB;QACArB;QACA0B,WAAWlE,KAAKmE,GAAG,CAAC,GAAG3B,QAAQqB;IACjC;AACF;AA+EA;;;;;;CAMC,GACD,SAASoC,qBACPxF,SAAsC,EACtCyF,KAAmC,EACnChE,MAA2C,EAC3CiE,SAA8C,EAC9CC,MAA0B,EAC1BtH,GAAS,EACT,mEAAmE,GACnEuH,IAAiB;QAWJD,cAUSA;IAnBtB,MAAMpE,YAAYxF,WAAWwF,SAAS;IACtC,MAAMC,kBAAkBzF,WAAWyF,eAAe;IAClD,MAAMqE,aAAalG,sBAAsBgG,OAAO/F,KAAK,EAAE+F,OAAO9F,KAAK;IACnE,sEAAsE;IACtE,yEAAyE;IACzE,0EAA0E;IAC1E,uDAAuD;IACvD,MAAMiG,kBAAkBhG,8BAA8B6F,OAAO/F,KAAK,EAAE+F,OAAO9F,KAAK;IAChF,MAAMkG,YAAYJ,OAAOI,SAAS,KAAK;IACvC,MAAM5D,QAAOwD,eAAAA,OAAOxD,IAAI,YAAXwD,eAAe;IAC5B,sEAAsE;IACtE,uEAAuE;IACvE,wEAAwE;IACxE,8DAA8D;IAC9D,MAAMK,cAAc7D,SAAS,QAAQwD,OAAOM,UAAU,KAAK;IAC3D,2EAA2E;IAC3E,oEAAoE;IACpE,2EAA2E;IAC3E,2DAA2D;IAC3D,MAAMC,SAASnF,QAAO4E,iBAAAA,OAAOO,MAAM,YAAbP,iBAAiB,IAAIQ,IAAI;IAC/C,MAAMC,cAAcF,SAAShK,qBAAqB2J,cAAc;IAChE,0EAA0E;IAC1E,wEAAwE;IACxE,uEAAuE;IACvE,yEAAyE;IACzE,8DAA8D;IAC9DJ,MAAMf,GAAG,CAACgB,WAAW;QACnBW,OAAOV,OAAOU,KAAK;QACnBH,QAAQP,OAAOO,MAAM;QACrBrG,OAAO8F,OAAO9F,KAAK;QACnByG,MAAMX,OAAOW,IAAI;QACjBV;QACAW,aAAaZ,OAAO/F,KAAK,CAAC2G,WAAW;QACrCC,cAAcb,OAAO/F,KAAK,CAAC4G,YAAY;QACvCC,iBAAiBd,OAAO/F,KAAK,CAAC6G,eAAe;QAC7CC,kBAAkBf,OAAO/F,KAAK,CAAC8G,gBAAgB;QAC/Cb;QACA,CAAC7J,2BAA2B,EAAE8J;QAC9Ba,WAAWhB,OAAOgB,SAAS;QAC3BV,YAAYN,OAAOM,UAAU;QAC7BF;QACAa,UAAU;OACNjB,OAAOkB,OAAO,IAAIlB,OAAOkB,OAAO,GAAG,IACnC;QAAEA,SAAStH,KAAKC,KAAK,CAACmG,OAAOkB,OAAO;IAAE,IACtC,CAAC;QACLC,WAAWtF;;IAEb,0EAA0E;IAC1E,wEAAwE;IACxE,2EAA2E;IAC3E,uEAAuE;IACvE,wEAAwE;IACxE,kDAAkD;IAClDiE,MAAMf,GAAG,CACPjD,OAAOC,UAAU,CAAC,eAAeC,GAAG,CAACvD,iBAAiBC,OACtD;QACE2C,OAAO5C,iBAAiBC;QACxB,qEAAqE;QACrE,mEAAmE;QACnE,sEAAsE;QACtE,qEAAqE;QACrE,qEAAqE;QACrE,uEAAuE;QACvE,sEAAsE;QACtE,sDAAsD;QACtD0H,WAAWxE,UAAUwE,YAAY,IAAI;QACrCQ,aAAahF,UAAUoE,OAAO/F,KAAK,CAAC2G,WAAW;QAC/CC,cAAcjF,UAAUoE,OAAO/F,KAAK,CAAC4G,YAAY;QACjDC,iBAAiBlF,UAAUoE,OAAO/F,KAAK,CAAC6G,eAAe;QACvDC,kBAAkBnF,UAAUoE,OAAO/F,KAAK,CAAC8G,gBAAgB;QACzDb,YAAYtE,UAAUyE,cAAc,IAAIH;QACxC,sEAAsE;QACtE,uEAAuE;QACvE,uEAAuE;QACvE,4BAA4B;QAC5B,CAAC7J,2BAA2B,EAAEuF,UAAUyE,cAAc,IAAIF;QAC1D,qEAAqE;QACrE,uEAAuE;QACvE,oEAAoE;QACpE,qEAAqE;QACrE,gDAAgD;QAChDiB,cAAcxF,UAAUyE,cAAc,IAAI;QAC1CgB,gBAAgBzF,UAAUyE,cAAcH,aAAa;OAQjDE,YACA,CAAC,IACD;QACE,CAAC9H,2BAA2B,EAAE;YAC5B,CAAC2H,KAAK,EAAE;gBACNN,UAAU/D,UAAU;gBACpBsE,YAAYtE,UAAUsE;gBACtB,CAAC7J,2BAA2B,EAAEuF,UAAUuE;gBACxC,CAAC5H,sBAAsB,EAAEH,kBAAkB4H,OAAO/F,KAAK;YACzD;QACF;IACF,GACAwG,cAAc,IACd;QAAE,CAACpJ,sBAAsB,EAAE;YAAE,CAACkJ,OAAO,EAAE3E,UAAU6E;QAAa;IAAE,IAChE,CAAC;QACLvB,WAAWrD;QAEb;QAAEmD,OAAO;IAAK;IAEhB,IAAIxC,MAAM;QACR,MAAMP,MAAMnD,eAAeJ;QAC3B,MAAM4I,SAAStJ,qBAAqB;YAClCkI;YACAqB,SAASlB;YACTpE;YACAZ,OAAO5C,iBAAiBC;QAC1B;QACAoH,MAAMf,GAAG,CAAC5G,qBAAqBkC,WAAW4B,MAAMqF,OAAOE,QAAQ,EAAE;YAAExC,OAAO;QAAK;QAC/E,IAAIxC,KAAKE,UAAU,EAAE;YACnBoD,MAAMf,GAAG,CACPjH,oBAAoBuC,WAAWmC,KAAKE,UAAU,EAAEjE,iBAAiBC,OACjE4I,OAAOG,OAAO,EACd;gBAAEzC,OAAO;YAAK;QAElB;IACF;AACF;AAEA;;;CAGC,GACD,eAAe0C,iBACbrH,SAAsC,EACtC2F,MAA0B,EAC1BtH,GAAS;IAET,IAAI,CAACsH,OAAOxD,IAAI,EAAE;IAClB,MAAM5E,0BAA0ByC,WAAWvB,eAAeJ,MAAM6C,KAAK,CAAC,CAACC,QACrEC,QAAQD,KAAK,CAAC,uCAAuCA;AAEzD;AAEA;;;;;;;;;;;;;CAaC,GACD,OAAO,eAAemG,iBACpBtH,SAAsC,EACtCC,KAAa,EACb0F,MAA0B,EAC1BtH,MAAM,IAAIC,MAAM;QAKHqH;IAHb,MAAMlE,SAASzB,UAAU0B,UAAU,CAAC,QAAQC,GAAG,CAAC1B;IAChD,MAAMyF,YAAYjE,OAAOC,UAAU,CAAC,iBAAiBC,GAAG;IACxD,MAAM8D,QAAQzF,UAAUyF,KAAK;IAC7B,MAAMG,QAAOD,eAAAA,OAAOC,IAAI,YAAXD,eAAexH,qBAAqBwH,OAAOU,KAAK;IAC7Db,qBAAqBxF,WAAWyF,OAAOhE,QAAQiE,WAAWC,QAAQtH,KAAKuH;IACvE,wEAAwE;IACxE,6CAA6C;IAC7C5H,kBAAkByH,OAAOhE,QAAQ;QAC/B8F,KAAK5B,OAAO4B,GAAG;QACfvG,OAAO5C,iBAAiBC;QACxBwH,YAAYlG,sBAAsBgG,OAAO/F,KAAK,EAAE+F,OAAO9F,KAAK;QAC5DqG,QAAQP,OAAOO,MAAM;QACrBN;QACAhG,OAAO+F,OAAO/F,KAAK;IACrB;IACA,MAAM6F,MAAM+B,MAAM;IAClBnG,qBAAqBrB,WAAWC,OAAO7B,iBAAiBC,MAAMA;IAC9D,MAAMgJ,iBAAiBrH,WAAW2F,QAAQtH;IAC1C,OAAOqH,UAAU+B,EAAE;AACrB;AAEA;;;;;;;;;;;;CAYC,GACD,OAAO,eAAeC,qBACpB1H,SAAsC,EACtCC,KAAa,EACb0F,MAA4B,EAC5BtH,MAAM,IAAIC,MAAM;QAoBHqH;IAlBb,MAAMnE,kBAAkBzF,WAAWyF,eAAe;IAClD,MAAMC,SAASzB,UAAU0B,UAAU,CAAC,QAAQC,GAAG,CAAC1B;IAChD,MAAM0H,cAAclG,OAAOC,UAAU,CAAC,mBAAmBC,GAAG;IAC5D,MAAM+D,YAAYjE,OAAOC,UAAU,CAAC,iBAAiBC,GAAG,CAACgG,YAAYF,EAAE;IAEvE,MAAMhC,QAAQzF,UAAUyF,KAAK;IAC7B,yEAAyE;IACzE,6CAA6C;IAC7CA,MAAMf,GAAG,CAACiD,aAAa;QACrBJ,KAAK5B,OAAO4B,GAAG;QACfK,UAAUjC,OAAOiC,QAAQ;QACzBC,QAAQlC,OAAOkC,MAAM;QACrB3B,QAAQP,OAAOO,MAAM;QACrBY,WAAWtF;QACXsG,WAAWlJ,qBAAqBP;IAClC;IACA,yEAAyE;IACzE,qEAAqE;IACrE,MAAMuH,QAAOD,eAAAA,OAAOC,IAAI,YAAXD,eAAe;IAC5B,yEAAyE;IACzE,2EAA2E;IAC3E,mBAAmB;IACnBH,qBAAqBxF,WAAWyF,OAAOhE,QAAQiE,WAAWC,QAAQtH,KAAKuH;IACvE,uDAAuD;IACvD5H,kBAAkByH,OAAOhE,QAAQ;QAC/B8F,KAAK5B,OAAO4B,GAAG;QACfvG,OAAO5C,iBAAiBC;QACxBwH,YAAYlG,sBAAsBgG,OAAO/F,KAAK,EAAE+F,OAAO9F,KAAK;QAC5DqG,QAAQP,OAAOO,MAAM;QACrBN;QACAhG,OAAO+F,OAAO/F,KAAK;IACrB;IACA,MAAM6F,MAAM+B,MAAM;IAClBnG,qBAAqBrB,WAAWC,OAAO7B,iBAAiBC,MAAMA;IAC9D,MAAMgJ,iBAAiBrH,WAAW2F,QAAQtH;IAC1C,OAAOsJ,YAAYF,EAAE;AACvB;AAEA;;;;;;;;;;CAUC,GACD,OAAO,eAAeM,qBACpB/H,SAAsC,EACtCC,KAAa,EACb+H,UAAkB,EAClBpB,QAAuB;IAEvB,MAAMrC,MAAMvE,UACT0B,UAAU,CAAC,QACXC,GAAG,CAAC1B,OACJyB,UAAU,CAAC,iBACXC,GAAG,CAACqG;IACP,MAAMlF,WAAW,MAAMyB,IAAItB,GAAG;IAC9B,IAAI,CAACH,SAASoB,MAAM,EAAE,OAAO;IAC7B,MAAMK,IAAI0D,MAAM,CAAC;QAAErB;IAAS;IAC5B,OAAO;AACT"}
@@ -0,0 +1,242 @@
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 { AiJobStatus } from '../model/ai-jobs.types';
18
+ import type { AglynOrgBilling } from '@aglyn/aglyn/foundation';
19
+ import { type DiscountMarginRating } from '@aglyn/aglyn/app-utils/plan-entitlements';
20
+ import type { AssistRefusalCounts } from './assist-refusals';
21
+ import { type AiKindMonth, type AiTokenTotals } from '../model/ai-tokens';
22
+ /**
23
+ * THE STAFF AI CARD'S FIGURES (AGL-2930), composed from the same helpers the
24
+ * meter, the invoice and the customer's own billing page read.
25
+ *
26
+ * Nothing here runs a query and nothing here holds a rate of its own. The
27
+ * pool is `resolveAssistCreditBudget`, the overage is `assistMonthOverage`,
28
+ * the ceiling is `assistOverageCapReached` — the ONE derivation each of those
29
+ * already is — so the card cannot show a staff member a different band,
30
+ * rate or ceiling from the one the gate refused a customer at.
31
+ */
32
+ /** The four ways the reservation refuses, plus their sum. */
33
+ export type StaffOrgAiRefusals = AssistRefusalCounts;
34
+ export interface StaffOrgAiAddon {
35
+ /** Bought and on a subscription still paying for it — `hasAiAddon`. */
36
+ on: boolean;
37
+ /** The add-on's list price on this plan, or null where the plan sells none. */
38
+ priceUsd: number | null;
39
+ /** ISO instant the subscription item was created, when Stripe could say. */
40
+ since: string | null;
41
+ /**
42
+ * Where `since` came from, so an absent date is legible: `stripe` answered,
43
+ * the org has no Stripe subscription to ask, or Stripe could not be asked
44
+ * (no key on this deployment, or the lookup failed).
45
+ */
46
+ sinceSource: 'stripe' | 'no-subscription' | 'unavailable';
47
+ }
48
+ export interface StaffOrgAiPool {
49
+ /** The plan's own band, from the catalogue row. */
50
+ planCredits: number;
51
+ /** A staff override of the band, or null when none is written. */
52
+ overrideCredits: number | null;
53
+ /** The add-on's band, 0 without the add-on. */
54
+ addonCredits: number;
55
+ /** The whole pool as the meter resolves it, or null where no band applies. */
56
+ totalCredits: number | null;
57
+ /**
58
+ * Whether an uncapped staff comp is why no band applies (AGL-3049) — a
59
+ * boolean, so "no band because uncapped" crosses JSON as itself rather
60
+ * than as the `null` an `Infinity` would become. Absent from a route older
61
+ * than the flag.
62
+ */
63
+ uncapped?: boolean;
64
+ /** Credits drawn this month, rounded up from the measured spend. */
65
+ usedCredits: number;
66
+ /**
67
+ * What the month DREW, at the catalog's billed rates — the dollars
68
+ * `usedCredits` is rounded up from, and the figure the overage line is
69
+ * priced off. Not a cost (AGL-3015).
70
+ */
71
+ billedUsd: number;
72
+ /**
73
+ * What the month COST US, at the provider's own rates: the one figure a
74
+ * margin or a spend alert may be taken against.
75
+ */
76
+ providerUsd: number;
77
+ /** Left in the pool, clamped at zero, or null where no band applies. */
78
+ remainingCredits: number | null;
79
+ /** Where `usedCredits` lands at month end at the pace so far. */
80
+ projectedCredits: number;
81
+ /** `projectedCredits` back in dollars — billed, as the credits were. */
82
+ projectedUsd: number;
83
+ /** Model turns and docs-deflected turns, off the month document. */
84
+ messages: number;
85
+ deflected: number;
86
+ }
87
+ export interface StaffOrgAiOverage {
88
+ overageCredits: number;
89
+ rateUsdPer1k: number | null;
90
+ accruedUsd: number;
91
+ /** Whether credits past the band are sold at all on this org. */
92
+ sellsOverage: boolean;
93
+ /** The org's own band switch — `assistOverage.hardCap`. */
94
+ hardCap: boolean;
95
+ /** The org's own dollar ceiling on overage — `assistOverage.capUsd`. */
96
+ capUsd: number | null;
97
+ capReached: boolean;
98
+ /** Whether the band is a wall for any reason (the switch, or no rate). */
99
+ bandRefuses: boolean;
100
+ }
101
+ export interface StaffOrgAiMargin {
102
+ /** The add-on's list price when it is on, else 0. */
103
+ addonRevenueUsd: number;
104
+ /**
105
+ * The dollar value of the plan's own band — what the plan price sets aside
106
+ * for assist. Each plan band is sized against the billed rate (a thousand
107
+ * credits are a dollar), so this is the share of the subscription that was
108
+ * sold as AI, and it belongs on the REVENUE side beside the add-on's price.
109
+ */
110
+ planAssistShareUsd: number;
111
+ /** Overage priced at the plan's rate, which the invoice will bill. */
112
+ overageRevenueUsd: number;
113
+ /** The three above, summed. */
114
+ revenueUsd: number;
115
+ /** What the month cost us: measured provider spend, never what it drew. */
116
+ spendUsd: number;
117
+ /**
118
+ * Spend past what the add-on and the plan's assist share bring in — the
119
+ * condition the card renders red. Overage revenue is left OUT of the
120
+ * comparison on purpose: it is billed at a margin, so an org deep in
121
+ * overage is not the one losing money.
122
+ */
123
+ underwater: boolean;
124
+ /** The staff review threshold and the multiple of it the spend has reached. */
125
+ thresholdUsd: number;
126
+ multiple: number;
127
+ /** The whole-org contribution margin, when a usage rollup exists. */
128
+ contribution: {
129
+ month: string | null;
130
+ marginPct: number | null;
131
+ rating: DiscountMarginRating | null;
132
+ };
133
+ }
134
+ /** The job model's own status set: the card renders every one by name. */
135
+ export type StaffOrgAiJobStatus = AiJobStatus;
136
+ export interface StaffOrgAiJob {
137
+ id: string;
138
+ kind: string;
139
+ status: StaffOrgAiJobStatus | string;
140
+ creditsReserved: number;
141
+ creditsSpent: number;
142
+ createdAt: string | null;
143
+ createdBy: string | null;
144
+ }
145
+ export interface StaffOrgAiJobs {
146
+ counts: Record<StaffOrgAiJobStatus, number>;
147
+ recent: StaffOrgAiJob[];
148
+ /** True when the scan stopped at its ceiling — the counts are a floor. */
149
+ truncated: boolean;
150
+ }
151
+ /** One row of the per-user rollup (AGL-2928), as the staff card lists it. */
152
+ export interface StaffOrgAiUser {
153
+ uid: string;
154
+ /** The roster's name for them — display name, else email, else the uid. */
155
+ name: string;
156
+ credits: number;
157
+ /** The measured provider spend behind `credits`; staff may see dollars. */
158
+ estCostUsd: number;
159
+ /** Of the org's measured spend for the month, in `[0, 1]`. */
160
+ share: number;
161
+ requests: number;
162
+ refusals: number;
163
+ byKind: Record<string, number>;
164
+ byHost: Record<string, number>;
165
+ }
166
+ /** One kind of model request this month, as the card lists it (AGL-2937). */
167
+ export interface StaffOrgAiKindTokens extends AiKindMonth {
168
+ /**
169
+ * What one request of this kind COST US on average; `null` with none. The
170
+ * provider figure, not what the kind drew — the reader is sizing a step
171
+ * against a bill, and a marked-up model would otherwise make the step look
172
+ * dearer to run than it is (AGL-3015).
173
+ */
174
+ costPerRequestUsd: number | null;
175
+ /** The share of this kind's prompt tokens the cache served — `aiCacheHitRate`. */
176
+ cacheHitRate: number | null;
177
+ }
178
+ /** The month's tokens (AGL-2937): its totals, its cache hit rate, and each kind. */
179
+ export interface StaffOrgAiTokens {
180
+ /** The month document's own four totals. */
181
+ total: AiTokenTotals;
182
+ cacheHitRate: number | null;
183
+ /** Dearest first; empty for a month written before kinds were kept. */
184
+ kinds: StaffOrgAiKindTokens[];
185
+ }
186
+ export interface StaffOrgAiResponse {
187
+ month: string;
188
+ addon: StaffOrgAiAddon;
189
+ pool: StaffOrgAiPool;
190
+ overage: StaffOrgAiOverage;
191
+ refusals: StaffOrgAiRefusals;
192
+ /** Null when the jobs read failed — distinct from an org with no jobs. */
193
+ jobs: StaffOrgAiJobs | null;
194
+ /** The dearest people this month; empty when nobody's month is written. */
195
+ users: StaffOrgAiUser[];
196
+ margin: StaffOrgAiMargin;
197
+ /** Tokens by kind (AGL-2937); absent from a route older than the card. */
198
+ tokens?: StaffOrgAiTokens;
199
+ }
200
+ /** The UTC day-of-month and month length `projectMonthEnd` scales by. */
201
+ export declare function monthProgress(now: Date): {
202
+ elapsed: number;
203
+ length: number;
204
+ };
205
+ /**
206
+ * Where a month-to-date figure lands at month end at the pace so far.
207
+ *
208
+ * Linear, on whole UTC days, and deliberately no cleverer: the reader is
209
+ * asking "will this org clear its band" and a straight line answers that
210
+ * within the margin the question needs. Day one projects the first day's
211
+ * spend across the month, which over-reads a burst — the direction a
212
+ * monitoring figure should err in.
213
+ */
214
+ export declare function projectMonthEnd(usedSoFar: number, now: Date): number;
215
+ export declare function composeStaffOrgAiPool(org: Partial<AglynOrgBilling> | null | undefined, monthDoc: Record<string, unknown> | null | undefined, now: Date): StaffOrgAiPool;
216
+ /**
217
+ * The month's tokens as the card reads them: the totals the month document
218
+ * has always kept, and its `kinds` map (`model/ai-tokens.ts`) with the cost
219
+ * per request and the cache hit rate worked out per kind.
220
+ */
221
+ export declare function composeStaffOrgAiTokens(monthDoc: Record<string, unknown> | null | undefined): StaffOrgAiTokens;
222
+ /**
223
+ * Takes the BILLED figure, never the provider one (AGL-3015): every line
224
+ * here is what the customer owes — credits past the band, the rate they sell
225
+ * at, the dollars accrued, whether the org's own cap is reached — and an
226
+ * invoice priced off our cost would bill a different month than the meter
227
+ * the customer reads.
228
+ */
229
+ export declare function composeStaffOrgAiOverage(org: Partial<AglynOrgBilling> | null | undefined, billedUsd: number): StaffOrgAiOverage;
230
+ export declare function composeStaffOrgAiAddon(org: Partial<AglynOrgBilling> | null | undefined, since: Pick<StaffOrgAiAddon, 'since' | 'sinceSource'>): StaffOrgAiAddon;
231
+ export declare function composeStaffOrgAiMargin(input: {
232
+ org: Partial<AglynOrgBilling> | null | undefined;
233
+ pool: StaffOrgAiPool;
234
+ overage: StaffOrgAiOverage;
235
+ addon: StaffOrgAiAddon;
236
+ thresholdUsd: number;
237
+ multiple: number;
238
+ contribution: StaffOrgAiMargin['contribution'];
239
+ }): StaffOrgAiMargin;
240
+ export declare const STAFF_ORG_AI_JOB_STATUSES: readonly StaffOrgAiJobStatus[];
241
+ /** Zero-filled counts, so the card renders every status by name. */
242
+ export declare function emptyJobCounts(): Record<StaffOrgAiJobStatus, number>;
@@ -0,0 +1,173 @@
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
+ */ // Imported from BOTH graphs — the staff card (client) and the App Route that
17
+ // serves it — so it may import neither entry barrel, for the reason
18
+ // `margin-utilization.ts` states at its own head.
19
+ import { _ as _extends } from "@swc/helpers/_/_extends";
20
+ import { ASSIST_PROVIDER_COST_FIELD, assistBandRefuses, assistCreditsFromUsd, assistProviderCostUsd, assistMonthOverage, assistOverageCapReached, assistUsdFromCredits, resolveAssistCreditBudget, resolveAssistHardCap, resolveAssistOverageCapUsd } from "@aglyn/aglyn/app-utils/assist-credits";
21
+ import { AI_ADDON_CREDITS_PER_MONTH, hasAiAddon, isUncappedPlanComp, PLAN_ENTITLEMENTS, resolveEffectivePlan, resolvePlanPricing } from "@aglyn/aglyn/app-utils/plan-entitlements";
22
+ import { AI_USAGE_MONTH_KINDS_FIELD, aiCacheHitRate, readAiKindMonths } from "../model/ai-tokens.js";
23
+ const finite = (value)=>{
24
+ const parsed = Number(value != null ? value : 0);
25
+ return Number.isFinite(parsed) && parsed > 0 ? parsed : 0;
26
+ };
27
+ /** The UTC day-of-month and month length `projectMonthEnd` scales by. */ export function monthProgress(now) {
28
+ const year = now.getUTCFullYear();
29
+ const month = now.getUTCMonth();
30
+ return {
31
+ elapsed: now.getUTCDate(),
32
+ length: new Date(Date.UTC(year, month + 1, 0)).getUTCDate()
33
+ };
34
+ }
35
+ /**
36
+ * Where a month-to-date figure lands at month end at the pace so far.
37
+ *
38
+ * Linear, on whole UTC days, and deliberately no cleverer: the reader is
39
+ * asking "will this org clear its band" and a straight line answers that
40
+ * within the margin the question needs. Day one projects the first day's
41
+ * spend across the month, which over-reads a burst — the direction a
42
+ * monitoring figure should err in.
43
+ */ export function projectMonthEnd(usedSoFar, now) {
44
+ const { elapsed, length } = monthProgress(now);
45
+ if (!(usedSoFar > 0) || elapsed <= 0) return 0;
46
+ return Math.ceil(usedSoFar / elapsed * length);
47
+ }
48
+ /** The staff override of the assist band, or null when none is written. */ function assistBandOverride(org) {
49
+ var _org_entitlements;
50
+ const raw = org == null ? void 0 : (_org_entitlements = org.entitlements) == null ? void 0 : _org_entitlements['assistCreditsPerMonth'];
51
+ if (typeof raw !== 'number' || !Number.isFinite(raw) || raw < 0) return null;
52
+ return Math.floor(raw);
53
+ }
54
+ export function composeStaffOrgAiPool(org, monthDoc, now) {
55
+ var _PLAN_ENTITLEMENTS_plan;
56
+ const plan = resolveEffectivePlan(org);
57
+ const addon = hasAiAddon(org);
58
+ // Two questions, two figures (AGL-3015). What the workspace DREW is the
59
+ // billed figure, because that is what its credits came out of and what its
60
+ // band is measured in. What the month COST US is the provider figure, and
61
+ // it is the only one a margin below may be taken against.
62
+ const billedUsd = finite(monthDoc == null ? void 0 : monthDoc['estCostUsd']);
63
+ const providerUsd = assistProviderCostUsd(billedUsd, monthDoc == null ? void 0 : monthDoc[ASSIST_PROVIDER_COST_FIELD]);
64
+ const usedCredits = assistCreditsFromUsd(billedUsd);
65
+ const totalCredits = resolveAssistCreditBudget(org);
66
+ const projectedCredits = projectMonthEnd(usedCredits, now);
67
+ return {
68
+ planCredits: finite((_PLAN_ENTITLEMENTS_plan = PLAN_ENTITLEMENTS[plan]) == null ? void 0 : _PLAN_ENTITLEMENTS_plan.assistCreditsPerMonth),
69
+ overrideCredits: assistBandOverride(org),
70
+ addonCredits: addon ? AI_ADDON_CREDITS_PER_MONTH[plan] : 0,
71
+ totalCredits,
72
+ uncapped: isUncappedPlanComp(org),
73
+ usedCredits,
74
+ billedUsd,
75
+ providerUsd,
76
+ remainingCredits: totalCredits === null ? null : Math.max(0, totalCredits - usedCredits),
77
+ projectedCredits,
78
+ projectedUsd: assistUsdFromCredits(projectedCredits),
79
+ messages: Math.floor(finite(monthDoc == null ? void 0 : monthDoc['messages'])),
80
+ deflected: Math.floor(finite(monthDoc == null ? void 0 : monthDoc['deflected']))
81
+ };
82
+ }
83
+ /**
84
+ * The month's tokens as the card reads them: the totals the month document
85
+ * has always kept, and its `kinds` map (`model/ai-tokens.ts`) with the cost
86
+ * per request and the cache hit rate worked out per kind.
87
+ */ export function composeStaffOrgAiTokens(monthDoc) {
88
+ const total = {
89
+ input: Math.floor(finite(monthDoc == null ? void 0 : monthDoc['inputTokens'])),
90
+ cached: Math.floor(finite(monthDoc == null ? void 0 : monthDoc['cacheReadTokens'])),
91
+ cacheWrite: Math.floor(finite(monthDoc == null ? void 0 : monthDoc['cacheWriteTokens'])),
92
+ output: Math.floor(finite(monthDoc == null ? void 0 : monthDoc['outputTokens']))
93
+ };
94
+ return {
95
+ total,
96
+ cacheHitRate: aiCacheHitRate(total),
97
+ kinds: readAiKindMonths(monthDoc == null ? void 0 : monthDoc[AI_USAGE_MONTH_KINDS_FIELD]).map((row)=>_extends({}, row, {
98
+ costPerRequestUsd: row.requests > 0 ? Math.round(row.providerCostUsd / row.requests * 1000000) / 1000000 : null,
99
+ cacheHitRate: aiCacheHitRate(row.tokens)
100
+ }))
101
+ };
102
+ }
103
+ /**
104
+ * Takes the BILLED figure, never the provider one (AGL-3015): every line
105
+ * here is what the customer owes — credits past the band, the rate they sell
106
+ * at, the dollars accrued, whether the org's own cap is reached — and an
107
+ * invoice priced off our cost would bill a different month than the meter
108
+ * the customer reads.
109
+ */ export function composeStaffOrgAiOverage(org, billedUsd) {
110
+ const overage = assistMonthOverage(org, billedUsd);
111
+ return {
112
+ overageCredits: overage.overageCredits,
113
+ rateUsdPer1k: overage.overageRateUsd,
114
+ accruedUsd: overage.overageMonthlyUsd,
115
+ sellsOverage: overage.bandCredits !== null && overage.overageRateUsd !== null,
116
+ hardCap: resolveAssistHardCap(org),
117
+ capUsd: resolveAssistOverageCapUsd(org),
118
+ capReached: assistOverageCapReached(org, billedUsd),
119
+ bandRefuses: assistBandRefuses(org)
120
+ };
121
+ }
122
+ export function composeStaffOrgAiAddon(org, since) {
123
+ var _resolvePlanPricing_aiAddonMonthlyUsd;
124
+ return _extends({
125
+ on: hasAiAddon(org),
126
+ // What this workspace would be charged — none for a staff comp, which
127
+ // has no subscription to carry the item (AGL-3034).
128
+ priceUsd: (_resolvePlanPricing_aiAddonMonthlyUsd = resolvePlanPricing(org).aiAddonMonthlyUsd) != null ? _resolvePlanPricing_aiAddonMonthlyUsd : null
129
+ }, since);
130
+ }
131
+ export function composeStaffOrgAiMargin(input) {
132
+ var _pool_overrideCredits;
133
+ const { pool, overage, addon } = input;
134
+ const addonRevenueUsd = addon.on ? finite(addon.priceUsd) : 0;
135
+ // The band the PLAN sells — the override, when one is written, is what the
136
+ // customer was actually given, so it is the figure the price is carrying.
137
+ const planAssistShareUsd = assistUsdFromCredits((_pool_overrideCredits = pool.overrideCredits) != null ? _pool_overrideCredits : pool.planCredits);
138
+ const overageRevenueUsd = overage.accruedUsd;
139
+ // THE ONE PLACE THE TWO RATES MEET (AGL-3015). Revenue is what the
140
+ // customer pays — an add-on price, a band sized in credits, overage at the
141
+ // retail rate — and spend is what the provider charges us. Taking both
142
+ // sides off one figure was what made a fully-drawn band read as exactly
143
+ // break-even no matter what the tokens actually cost.
144
+ const revenueUsd = Math.round((addonRevenueUsd + planAssistShareUsd + overageRevenueUsd) * 100) / 100;
145
+ return {
146
+ addonRevenueUsd,
147
+ planAssistShareUsd,
148
+ overageRevenueUsd,
149
+ revenueUsd,
150
+ spendUsd: pool.providerUsd,
151
+ underwater: pool.providerUsd > addonRevenueUsd + planAssistShareUsd,
152
+ thresholdUsd: input.thresholdUsd,
153
+ multiple: input.multiple,
154
+ contribution: input.contribution
155
+ };
156
+ }
157
+ export const STAFF_ORG_AI_JOB_STATUSES = [
158
+ 'queued',
159
+ 'running',
160
+ 'needs_input',
161
+ 'needs_review',
162
+ 'done',
163
+ 'failed',
164
+ 'canceled'
165
+ ];
166
+ /** Zero-filled counts, so the card renders every status by name. */ export function emptyJobCounts() {
167
+ return Object.fromEntries(STAFF_ORG_AI_JOB_STATUSES.map((status)=>[
168
+ status,
169
+ 0
170
+ ]));
171
+ }
172
+
173
+ //# sourceMappingURL=staff-org-ai.js.map