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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (305) hide show
  1. package/package.json +17 -17
  2. package/src/lib/activity/ai-activity-actions.js +8 -4
  3. package/src/lib/activity/ai-activity-actions.js.map +1 -1
  4. package/src/lib/components/ai-assist-provider-on-host.component.d.ts +66 -0
  5. package/src/lib/components/ai-assist-provider-on-host.component.js +78 -0
  6. package/src/lib/components/ai-assist-provider-on-host.component.js.map +1 -0
  7. package/src/lib/components/ai-assist-provider.component.js +9 -10
  8. package/src/lib/components/ai-assist-provider.component.js.map +1 -1
  9. package/src/lib/components/ai-job-follow.component.js +1 -0
  10. package/src/lib/components/ai-job-follow.component.js.map +1 -1
  11. package/src/lib/components/ai-job-links.js +13 -0
  12. package/src/lib/components/ai-job-links.js.map +1 -1
  13. package/src/lib/components/ai-job-plan.component.js +3 -1
  14. package/src/lib/components/ai-job-plan.component.js.map +1 -1
  15. package/src/lib/components/ai-jobs-list-page.component.js +1 -0
  16. package/src/lib/components/ai-jobs-list-page.component.js.map +1 -1
  17. package/src/lib/components/ai-media-create.component.d.ts +20 -7
  18. package/src/lib/components/ai-media-create.component.js +107 -55
  19. package/src/lib/components/ai-media-create.component.js.map +1 -1
  20. package/src/lib/components/ai-permissions-on-host.component.d.ts +3 -46
  21. package/src/lib/components/ai-permissions-on-host.component.js +5 -53
  22. package/src/lib/components/ai-permissions-on-host.component.js.map +1 -1
  23. package/src/lib/components/ai-seo-fields-card.component.js +1 -0
  24. package/src/lib/components/ai-seo-fields-card.component.js.map +1 -1
  25. package/src/lib/components/ai-site-build-page.component.js +20 -8
  26. package/src/lib/components/ai-site-build-page.component.js.map +1 -1
  27. package/src/lib/components/ai-site-memory-card.component.d.ts +32 -0
  28. package/src/lib/components/ai-site-memory-card.component.js +187 -0
  29. package/src/lib/components/ai-site-memory-card.component.js.map +1 -0
  30. package/src/lib/components/ai-site-start-card.component.js +80 -77
  31. package/src/lib/components/ai-site-start-card.component.js.map +1 -1
  32. package/src/lib/components/ai-theme-proposal-card.component.js +4 -0
  33. package/src/lib/components/ai-theme-proposal-card.component.js.map +1 -1
  34. package/src/lib/components/ai-usage-strip.component.js +1 -0
  35. package/src/lib/components/ai-usage-strip.component.js.map +1 -1
  36. package/src/lib/components/assist-panel.component.d.ts +10 -0
  37. package/src/lib/components/assist-panel.component.js +119 -9
  38. package/src/lib/components/assist-panel.component.js.map +1 -1
  39. package/src/lib/components/assist-signals-page.component.js +2 -0
  40. package/src/lib/components/assist-signals-page.component.js.map +1 -1
  41. package/src/lib/components/billing-ai-allotments.component.js +3 -0
  42. package/src/lib/components/billing-ai-allotments.component.js.map +1 -1
  43. package/src/lib/components/billing-ai-top-users.component.js +1 -0
  44. package/src/lib/components/billing-ai-top-users.component.js.map +1 -1
  45. package/src/lib/components/billing-assist-overage-card.component.js +2 -0
  46. package/src/lib/components/billing-assist-overage-card.component.js.map +1 -1
  47. package/src/lib/components/member-ai-usage-card.component.js +10 -0
  48. package/src/lib/components/member-ai-usage-card.component.js.map +1 -1
  49. package/src/lib/components/staff-org-ai-card.component.js +1 -0
  50. package/src/lib/components/staff-org-ai-card.component.js.map +1 -1
  51. package/src/lib/components/staff-org-ai-conversations.component.d.ts +23 -0
  52. package/src/lib/components/staff-org-ai-conversations.component.js +346 -0
  53. package/src/lib/components/staff-org-ai-conversations.component.js.map +1 -0
  54. package/src/lib/jobs/ai-build-capabilities.d.ts +13 -1
  55. package/src/lib/jobs/ai-build-capabilities.js +101 -7
  56. package/src/lib/jobs/ai-build-capabilities.js.map +1 -1
  57. package/src/lib/jobs/ai-build-unit-outcome.js +4 -2
  58. package/src/lib/jobs/ai-build-unit-outcome.js.map +1 -1
  59. package/src/lib/jobs/ai-business-profile-prefill.d.ts +29 -0
  60. package/src/lib/jobs/ai-business-profile-prefill.js +85 -0
  61. package/src/lib/jobs/ai-business-profile-prefill.js.map +1 -0
  62. package/src/lib/jobs/ai-job-auto-confirm.d.ts +8 -0
  63. package/src/lib/jobs/ai-job-auto-confirm.js +30 -6
  64. package/src/lib/jobs/ai-job-auto-confirm.js.map +1 -1
  65. package/src/lib/jobs/ai-job-build-step.js +14 -1
  66. package/src/lib/jobs/ai-job-build-step.js.map +1 -1
  67. package/src/lib/jobs/ai-job-edit-step.d.ts +225 -0
  68. package/src/lib/jobs/ai-job-edit-step.js +631 -0
  69. package/src/lib/jobs/ai-job-edit-step.js.map +1 -0
  70. package/src/lib/jobs/ai-job-generation.d.ts +8 -0
  71. package/src/lib/jobs/ai-job-generation.js +13 -2
  72. package/src/lib/jobs/ai-job-generation.js.map +1 -1
  73. package/src/lib/jobs/ai-job-insight-step.js +29 -5
  74. package/src/lib/jobs/ai-job-insight-step.js.map +1 -1
  75. package/src/lib/jobs/ai-job-layout-language.d.ts +78 -0
  76. package/src/lib/jobs/ai-job-layout-language.js +200 -0
  77. package/src/lib/jobs/ai-job-layout-language.js.map +1 -0
  78. package/src/lib/jobs/ai-job-layout-site-pages.d.ts +13 -2
  79. package/src/lib/jobs/ai-job-layout-site-pages.js +18 -2
  80. package/src/lib/jobs/ai-job-layout-site-pages.js.map +1 -1
  81. package/src/lib/jobs/ai-job-layout-step.d.ts +5 -0
  82. package/src/lib/jobs/ai-job-layout-step.js +107 -6
  83. package/src/lib/jobs/ai-job-layout-step.js.map +1 -1
  84. package/src/lib/jobs/ai-job-logic-step.d.ts +20 -0
  85. package/src/lib/jobs/ai-job-logic-step.js +87 -6
  86. package/src/lib/jobs/ai-job-logic-step.js.map +1 -1
  87. package/src/lib/jobs/ai-job-page-language.d.ts +194 -0
  88. package/src/lib/jobs/ai-job-page-language.js +418 -0
  89. package/src/lib/jobs/ai-job-page-language.js.map +1 -0
  90. package/src/lib/jobs/ai-job-page-sections.d.ts +37 -1
  91. package/src/lib/jobs/ai-job-page-sections.js +93 -11
  92. package/src/lib/jobs/ai-job-page-sections.js.map +1 -1
  93. package/src/lib/jobs/ai-job-page-step.d.ts +4 -4
  94. package/src/lib/jobs/ai-job-page-step.js +115 -14
  95. package/src/lib/jobs/ai-job-page-step.js.map +1 -1
  96. package/src/lib/jobs/ai-job-plan-step.d.ts +20 -6
  97. package/src/lib/jobs/ai-job-plan-step.js +62 -22
  98. package/src/lib/jobs/ai-job-plan-step.js.map +1 -1
  99. package/src/lib/jobs/ai-job-site-content.d.ts +163 -0
  100. package/src/lib/jobs/ai-job-site-content.js +443 -0
  101. package/src/lib/jobs/ai-job-site-content.js.map +1 -0
  102. package/src/lib/jobs/ai-job-site-look.d.ts +112 -0
  103. package/src/lib/jobs/ai-job-site-look.js +322 -0
  104. package/src/lib/jobs/ai-job-site-look.js.map +1 -0
  105. package/src/lib/jobs/ai-job-site-step.d.ts +30 -5
  106. package/src/lib/jobs/ai-job-site-step.js +183 -27
  107. package/src/lib/jobs/ai-job-site-step.js.map +1 -1
  108. package/src/lib/jobs/ai-job-workflow-step.js +2 -2
  109. package/src/lib/jobs/ai-job-workflow-step.js.map +1 -1
  110. package/src/lib/jobs/ai-jobs-notify.d.ts +6 -1
  111. package/src/lib/jobs/ai-jobs-notify.js +15 -3
  112. package/src/lib/jobs/ai-jobs-notify.js.map +1 -1
  113. package/src/lib/jobs/ai-jobs.d.ts +1 -1
  114. package/src/lib/jobs/ai-jobs.js +17 -8
  115. package/src/lib/jobs/ai-jobs.js.map +1 -1
  116. package/src/lib/jobs/ai-layout-full-height.d.ts +40 -0
  117. package/src/lib/jobs/ai-layout-full-height.js +82 -0
  118. package/src/lib/jobs/ai-layout-full-height.js.map +1 -0
  119. package/src/lib/jobs/ai-layout-site-facts.d.ts +54 -0
  120. package/src/lib/jobs/ai-layout-site-facts.js +153 -0
  121. package/src/lib/jobs/ai-layout-site-facts.js.map +1 -0
  122. package/src/lib/layout-language/ai-layout-compiler.d.ts +154 -0
  123. package/src/lib/layout-language/ai-layout-compiler.js +1235 -0
  124. package/src/lib/layout-language/ai-layout-compiler.js.map +1 -0
  125. package/src/lib/layout-language/ai-layout-copy.d.ts +73 -0
  126. package/src/lib/layout-language/ai-layout-copy.js +137 -0
  127. package/src/lib/layout-language/ai-layout-copy.js.map +1 -0
  128. package/src/lib/layout-language/ai-layout-frame.d.ts +52 -0
  129. package/src/lib/layout-language/ai-layout-frame.js +458 -0
  130. package/src/lib/layout-language/ai-layout-frame.js.map +1 -0
  131. package/src/lib/layout-language/ai-layout-gaps.d.ts +63 -0
  132. package/src/lib/layout-language/ai-layout-gaps.js +345 -0
  133. package/src/lib/layout-language/ai-layout-gaps.js.map +1 -0
  134. package/src/lib/layout-language/ai-layout-language.d.ts +168 -0
  135. package/src/lib/layout-language/ai-layout-language.js +529 -0
  136. package/src/lib/layout-language/ai-layout-language.js.map +1 -0
  137. package/src/lib/layout-language/ai-layout-links.d.ts +80 -0
  138. package/src/lib/layout-language/ai-layout-links.js +109 -0
  139. package/src/lib/layout-language/ai-layout-links.js.map +1 -0
  140. package/src/lib/layout-language/ai-layout-pictures.d.ts +144 -0
  141. package/src/lib/layout-language/ai-layout-pictures.js +214 -0
  142. package/src/lib/layout-language/ai-layout-pictures.js.map +1 -0
  143. package/src/lib/layout-language/ai-layout-store.d.ts +41 -0
  144. package/src/lib/layout-language/ai-layout-store.js +75 -0
  145. package/src/lib/layout-language/ai-layout-store.js.map +1 -0
  146. package/src/lib/layout-language/ai-layout-tree.d.ts +59 -0
  147. package/src/lib/layout-language/ai-layout-tree.js +84 -0
  148. package/src/lib/layout-language/ai-layout-tree.js.map +1 -0
  149. package/src/lib/lazy-widget.d.ts +45 -0
  150. package/src/lib/lazy-widget.js +53 -0
  151. package/src/lib/lazy-widget.js.map +1 -0
  152. package/src/lib/model/ai-build-job.js +2 -1
  153. package/src/lib/model/ai-build-job.js.map +1 -1
  154. package/src/lib/model/ai-build-progress.d.ts +20 -3
  155. package/src/lib/model/ai-build-progress.js +52 -7
  156. package/src/lib/model/ai-build-progress.js.map +1 -1
  157. package/src/lib/model/ai-edit-job.d.ts +109 -0
  158. package/src/lib/model/ai-edit-job.js +157 -0
  159. package/src/lib/model/ai-edit-job.js.map +1 -0
  160. package/src/lib/model/ai-host-publish-context.d.ts +51 -0
  161. package/src/lib/model/ai-host-publish-context.js +104 -0
  162. package/src/lib/model/ai-host-publish-context.js.map +1 -0
  163. package/src/lib/model/ai-job-activity.d.ts +22 -0
  164. package/src/lib/model/ai-job-activity.js +23 -1
  165. package/src/lib/model/ai-job-activity.js.map +1 -1
  166. package/src/lib/model/ai-job-failure-copy.d.ts +38 -1
  167. package/src/lib/model/ai-job-failure-copy.js +56 -1
  168. package/src/lib/model/ai-job-failure-copy.js.map +1 -1
  169. package/src/lib/model/ai-job-notice.d.ts +3 -1
  170. package/src/lib/model/ai-job-notice.js +31 -9
  171. package/src/lib/model/ai-job-notice.js.map +1 -1
  172. package/src/lib/model/ai-jobs.types.d.ts +22 -1
  173. package/src/lib/model/ai-jobs.types.js.map +1 -1
  174. package/src/lib/model/ai-logic-job.d.ts +18 -1
  175. package/src/lib/model/ai-logic-job.js +24 -3
  176. package/src/lib/model/ai-logic-job.js.map +1 -1
  177. package/src/lib/model/ai-media-credits.d.ts +8 -4
  178. package/src/lib/model/ai-media-credits.js +11 -4
  179. package/src/lib/model/ai-media-credits.js.map +1 -1
  180. package/src/lib/model/ai-media-kinds.d.ts +68 -0
  181. package/src/lib/model/ai-media-kinds.js +98 -0
  182. package/src/lib/model/ai-media-kinds.js.map +1 -0
  183. package/src/lib/model/ai-site-build-progress.d.ts +9 -1
  184. package/src/lib/model/ai-site-build-progress.js +54 -14
  185. package/src/lib/model/ai-site-build-progress.js.map +1 -1
  186. package/src/lib/model/ai-site-context.d.ts +111 -0
  187. package/src/lib/model/ai-site-context.js +222 -0
  188. package/src/lib/model/ai-site-context.js.map +1 -0
  189. package/src/lib/model/ai-site-job.d.ts +18 -2
  190. package/src/lib/model/ai-site-job.js +21 -5
  191. package/src/lib/model/ai-site-job.js.map +1 -1
  192. package/src/lib/model/ai-site-kinds.d.ts +164 -0
  193. package/src/lib/model/ai-site-kinds.js +1942 -0
  194. package/src/lib/model/ai-site-kinds.js.map +1 -0
  195. package/src/lib/model/ai-site-look.d.ts +150 -0
  196. package/src/lib/model/ai-site-look.js +1236 -0
  197. package/src/lib/model/ai-site-look.js.map +1 -0
  198. package/src/lib/model/ai-site-memory.d.ts +80 -0
  199. package/src/lib/model/ai-site-memory.js +171 -0
  200. package/src/lib/model/ai-site-memory.js.map +1 -0
  201. package/src/lib/model/ai-site-start-seo.d.ts +1 -1
  202. package/src/lib/model/ai-site-start.d.ts +15 -3
  203. package/src/lib/model/ai-site-start.js +21 -4
  204. package/src/lib/model/ai-site-start.js.map +1 -1
  205. package/src/lib/model/assist-follow-up.d.ts +92 -0
  206. package/src/lib/model/assist-follow-up.js +128 -0
  207. package/src/lib/model/assist-follow-up.js.map +1 -0
  208. package/src/lib/plugin-config.js +2 -0
  209. package/src/lib/plugin-config.js.map +1 -1
  210. package/src/lib/plugin.js +99 -48
  211. package/src/lib/plugin.js.map +1 -1
  212. package/src/lib/providers/anthropic.d.ts +9 -1
  213. package/src/lib/providers/anthropic.js +143 -9
  214. package/src/lib/providers/anthropic.js.map +1 -1
  215. package/src/lib/providers/catalog.d.ts +38 -8
  216. package/src/lib/providers/catalog.js +106 -14
  217. package/src/lib/providers/catalog.js.map +1 -1
  218. package/src/lib/providers/contract.d.ts +29 -0
  219. package/src/lib/providers/contract.js.map +1 -1
  220. package/src/lib/providers/image-contract.d.ts +22 -1
  221. package/src/lib/providers/image-contract.js +40 -1
  222. package/src/lib/providers/image-contract.js.map +1 -1
  223. package/src/lib/providers/image-endpoints.d.ts +24 -0
  224. package/src/lib/providers/image-endpoints.js +28 -0
  225. package/src/lib/providers/image-endpoints.js.map +1 -0
  226. package/src/lib/providers/model-choice.js +23 -2
  227. package/src/lib/providers/model-choice.js.map +1 -1
  228. package/src/lib/providers/routing.js +18 -0
  229. package/src/lib/providers/routing.js.map +1 -1
  230. package/src/lib/providers/vertex-image-endpoint.d.ts +48 -0
  231. package/src/lib/providers/vertex-image-endpoint.js +80 -0
  232. package/src/lib/providers/vertex-image-endpoint.js.map +1 -0
  233. package/src/lib/providers/vertex-image.d.ts +13 -27
  234. package/src/lib/providers/vertex-image.js +15 -42
  235. package/src/lib/providers/vertex-image.js.map +1 -1
  236. package/src/lib/runtime/ai-blog-post-generation.d.ts +62 -0
  237. package/src/lib/runtime/ai-blog-post-generation.js +89 -0
  238. package/src/lib/runtime/ai-blog-post-generation.js.map +1 -0
  239. package/src/lib/runtime/ai-dev-env.d.ts +53 -0
  240. package/src/lib/runtime/ai-dev-env.js +72 -0
  241. package/src/lib/runtime/ai-dev-env.js.map +1 -0
  242. package/src/lib/runtime/ai-dev-replay.d.ts +116 -0
  243. package/src/lib/runtime/ai-dev-replay.js +313 -0
  244. package/src/lib/runtime/ai-dev-replay.js.map +1 -0
  245. package/src/lib/runtime/ai-doctrine-validators.d.ts +82 -0
  246. package/src/lib/runtime/ai-doctrine-validators.js +436 -4
  247. package/src/lib/runtime/ai-doctrine-validators.js.map +1 -1
  248. package/src/lib/runtime/ai-doctrine.js +16 -3
  249. package/src/lib/runtime/ai-doctrine.js.map +1 -1
  250. package/src/lib/runtime/ai-eval-live.js +4 -0
  251. package/src/lib/runtime/ai-eval-live.js.map +1 -1
  252. package/src/lib/runtime/ai-eval.d.ts +13 -1
  253. package/src/lib/runtime/ai-eval.js +84 -1
  254. package/src/lib/runtime/ai-eval.js.map +1 -1
  255. package/src/lib/runtime/ai-icon-library.d.ts +257 -0
  256. package/src/lib/runtime/ai-icon-library.js +254 -0
  257. package/src/lib/runtime/ai-icon-library.js.map +1 -0
  258. package/src/lib/runtime/ai-live-batch.d.ts +45 -0
  259. package/src/lib/runtime/ai-live-batch.js +89 -0
  260. package/src/lib/runtime/ai-live-batch.js.map +1 -0
  261. package/src/lib/runtime/ai-node-tree.d.ts +9 -0
  262. package/src/lib/runtime/ai-node-tree.js +30 -4
  263. package/src/lib/runtime/ai-node-tree.js.map +1 -1
  264. package/src/lib/runtime/ai-palette.d.ts +6 -0
  265. package/src/lib/runtime/ai-palette.generated.js +70 -0
  266. package/src/lib/runtime/ai-palette.generated.js.map +1 -1
  267. package/src/lib/runtime/ai-palette.js.map +1 -1
  268. package/src/lib/runtime/ai-runtime.js +46 -2
  269. package/src/lib/runtime/ai-runtime.js.map +1 -1
  270. package/src/lib/runtime/site-context.d.ts +58 -0
  271. package/src/lib/runtime/site-context.js +127 -0
  272. package/src/lib/runtime/site-context.js.map +1 -0
  273. package/src/lib/server/ai-admin-conversations.d.ts +22 -0
  274. package/src/lib/server/ai-admin-conversations.js +197 -0
  275. package/src/lib/server/ai-admin-conversations.js.map +1 -0
  276. package/src/lib/server/ai-media-image.d.ts +5 -5
  277. package/src/lib/server/ai-media-image.js +25 -11
  278. package/src/lib/server/ai-media-image.js.map +1 -1
  279. package/src/lib/server/ai-media-raster-prompt.d.ts +34 -0
  280. package/src/lib/server/ai-media-raster-prompt.js +53 -0
  281. package/src/lib/server/ai-media-raster-prompt.js.map +1 -0
  282. package/src/lib/server/assist-chat.d.ts +11 -0
  283. package/src/lib/server/assist-chat.js +57 -18
  284. package/src/lib/server/assist-chat.js.map +1 -1
  285. package/src/lib/server/assist-edit-applied.js +16 -3
  286. package/src/lib/server/assist-edit-applied.js.map +1 -1
  287. package/src/lib/server/assist-view-context.d.ts +19 -1
  288. package/src/lib/server/assist-view-context.js +38 -1
  289. package/src/lib/server/assist-view-context.js.map +1 -1
  290. package/src/lib/server.js +10 -0
  291. package/src/lib/server.js.map +1 -1
  292. package/src/lib/subprocessors.js +17 -1
  293. package/src/lib/subprocessors.js.map +1 -1
  294. package/src/lib/tools/ai-blog-post-tool.d.ts +60 -0
  295. package/src/lib/tools/ai-blog-post-tool.js +175 -0
  296. package/src/lib/tools/ai-blog-post-tool.js.map +1 -0
  297. package/src/lib/tools/ai-workflow-tool.d.ts +6 -2
  298. package/src/lib/tools/ai-workflow-tool.js +16 -14
  299. package/src/lib/tools/ai-workflow-tool.js.map +1 -1
  300. package/src/lib/usage/assist-usage.d.ts +3 -0
  301. package/src/lib/usage/assist-usage.js +4 -2
  302. package/src/lib/usage/assist-usage.js.map +1 -1
  303. package/src/lib/usage/staff-org-ai-conversations.d.ts +103 -0
  304. package/src/lib/usage/staff-org-ai-conversations.js +152 -0
  305. package/src/lib/usage/staff-org-ai-conversations.js.map +1 -0
@@ -14,7 +14,7 @@
14
14
  * See the License for the specific language governing permissions and
15
15
  * limitations under the License.
16
16
  */
17
- import type { AiJobItemLedger, AiJobSummary } from './ai-jobs.types';
17
+ import { type AiJobItemLedger, type AiJobSummary } from './ai-jobs.types';
18
18
  /**
19
19
  * What a `build` job shows of each item (AGL-3616), wherever it is shown —
20
20
  * the AI jobs drawer, the job's own page, the chat card: the item, where it
@@ -31,6 +31,8 @@ export interface AiBuildItemRow {
31
31
  state: AiBuildItemRowState;
32
32
  /** What the person should know: the failure, the note, what was given back. */
33
33
  detail: string | null;
34
+ /** When the active item started, for the elapsed time beside it; absent on every other row. */
35
+ startedAt?: string | null;
34
36
  }
35
37
  /** What an operation is called at the start of a row: its own noun, or the op spelled as words. */
36
38
  export declare function aiBuildOpNoun(op: string): string;
@@ -42,8 +44,23 @@ export declare function aiBuildOpNoun(op: string): string;
42
44
  * did not fail.
43
45
  */
44
46
  export declare function aiBuildItemRefundCopy(row: Pick<AiJobItemLedger, 'status' | 'failure' | 'creditsRefunded' | 'creditsSpent'>): string | null;
45
- /** One row an item, in the order the build planned them. */
46
- export declare function aiBuildItemRows(job: Pick<AiJobSummary, 'items'>): AiBuildItemRow[];
47
+ /**
48
+ * The item the build is on (AGL-3596): the one its ledger marks running, else
49
+ * — while the job moves — the first still pending, which is the one its runner
50
+ * builds next. The runner settles an item in the write that records its pass,
51
+ * so the item it is writing reads `pending` until it is done; read as such,
52
+ * every row waited and the build looked stalled. `null` when the job is not
53
+ * moving or nothing is left.
54
+ */
55
+ export declare function aiBuildActiveSlot(job: Pick<AiJobSummary, 'items'> & Partial<Pick<AiJobSummary, 'status'>>): string | null;
56
+ /**
57
+ * When the active item started: when the last item before it settled, which
58
+ * the ledger records, else when the build step started — the first item's
59
+ * start, and the best a ledger written before settling was recorded has.
60
+ */
61
+ export declare function aiBuildActiveStartedAt(job: Pick<AiJobSummary, 'items'> & Partial<Pick<AiJobSummary, 'steps'>>): string | null;
62
+ /** One row an item, in the order the build planned them; the item it is on is the active one. */
63
+ export declare function aiBuildItemRows(job: Pick<AiJobSummary, 'items'> & Partial<Pick<AiJobSummary, 'status' | 'steps'>>): AiBuildItemRow[];
47
64
  /** How a build came out, in one line: "4 of 5 built; 1 failed." `null` while it runs. */
48
65
  export declare function aiBuildOutcomeLine(job: Pick<AiJobSummary, 'items' | 'status'>): string | null;
49
66
  /** Whether a finished build — or a site that built part of itself — has failed items to try again. */
@@ -1,3 +1,4 @@
1
+ import { _ as _extends } from "@swc/helpers/_/_extends";
1
2
  /**
2
3
  * @license
3
4
  * Copyright 2026 Aglyn LLC
@@ -13,7 +14,9 @@
13
14
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
15
  * See the License for the specific language governing permissions and
15
16
  * limitations under the License.
16
- */ const OP_NOUNS = {
17
+ */ import { aiCustomerSafeItem } from "./ai-job-failure-copy.js";
18
+ import { AI_JOB_PLAN_STEP } from "./ai-jobs.types.js";
19
+ const OP_NOUNS = {
17
20
  page: 'Page',
18
21
  layout: 'Layout',
19
22
  form: 'Form',
@@ -21,7 +24,10 @@
21
24
  email: 'Email design',
22
25
  template: 'Page template',
23
26
  campaign: 'Email campaign',
24
- workflow: 'Automation'
27
+ workflow: 'Automation',
28
+ // A guided start's first posts and products (AGL-3676).
29
+ posts: 'Blog',
30
+ products: 'Store'
25
31
  };
26
32
  /** What an operation is called at the start of a row: its own noun, or the op spelled as words. */ export function aiBuildOpNoun(op) {
27
33
  const known = OP_NOUNS[op];
@@ -58,22 +64,61 @@ const STATES = {
58
64
  failed: 'failed',
59
65
  skipped: 'skipped'
60
66
  };
61
- /** One row an item, in the order the build planned them. */ export function aiBuildItemRows(job) {
67
+ /**
68
+ * The item the build is on (AGL-3596): the one its ledger marks running, else
69
+ * — while the job moves — the first still pending, which is the one its runner
70
+ * builds next. The runner settles an item in the write that records its pass,
71
+ * so the item it is writing reads `pending` until it is done; read as such,
72
+ * every row waited and the build looked stalled. `null` when the job is not
73
+ * moving or nothing is left.
74
+ */ export function aiBuildActiveSlot(job) {
75
+ var _job_items, _ref;
76
+ var _items_find;
77
+ const items = (_job_items = job.items) != null ? _job_items : [];
78
+ const running = items.find((row)=>row.status === 'running');
79
+ if (running) return running.slot;
80
+ if (job.status !== 'queued' && job.status !== 'running') return null;
81
+ return (_ref = (_items_find = items.find((row)=>row.status === 'pending')) == null ? void 0 : _items_find.slot) != null ? _ref : null;
82
+ }
83
+ /**
84
+ * When the active item started: when the last item before it settled, which
85
+ * the ledger records, else when the build step started — the first item's
86
+ * start, and the best a ledger written before settling was recorded has.
87
+ */ export function aiBuildActiveStartedAt(job) {
88
+ var _job_items, _job_steps, _ref;
89
+ let latest = null;
90
+ for (const row of (_job_items = job.items) != null ? _job_items : []){
91
+ const at = row.settledAt ? Date.parse(row.settledAt) : NaN;
92
+ if (Number.isFinite(at) && (!latest || at > latest.at)) latest = {
93
+ at,
94
+ iso: row.settledAt
95
+ };
96
+ }
97
+ if (latest) return latest.iso;
98
+ const step = ((_job_steps = job.steps) != null ? _job_steps : []).find((one)=>one.name !== AI_JOB_PLAN_STEP && one.startedAt);
99
+ return (_ref = step == null ? void 0 : step.startedAt) != null ? _ref : null;
100
+ }
101
+ /** One row an item, in the order the build planned them; the item it is on is the active one. */ export function aiBuildItemRows(job) {
62
102
  var _job_items;
63
- return ((_job_items = job.items) != null ? _job_items : []).map((row)=>{
103
+ const active = aiBuildActiveSlot(job);
104
+ return ((_job_items = job.items) != null ? _job_items : []).map((ledger)=>{
64
105
  var _STATES_row_status;
65
106
  var _row_failure;
107
+ // A building rule's own words never reach a customer (AGL-3596).
108
+ const row = aiCustomerSafeItem(ledger);
66
109
  const parts = [];
67
110
  if (row.status === 'failed' && ((_row_failure = row.failure) == null ? void 0 : _row_failure.message)) parts.push(row.failure.message);
68
111
  if (row.note) parts.push(row.note);
69
112
  const refund = aiBuildItemRefundCopy(row);
70
113
  if (refund) parts.push(refund);
71
- return {
114
+ return _extends({
72
115
  slot: row.slot,
73
116
  label: `${aiBuildOpNoun(row.op)}: ${row.label}`,
74
- state: (_STATES_row_status = STATES[row.status]) != null ? _STATES_row_status : 'waiting',
117
+ state: row.slot === active ? 'active' : (_STATES_row_status = STATES[row.status]) != null ? _STATES_row_status : 'waiting',
75
118
  detail: parts.length ? parts.join(' ') : null
76
- };
119
+ }, row.slot === active ? {
120
+ startedAt: aiBuildActiveStartedAt(job)
121
+ } : {});
77
122
  });
78
123
  }
79
124
  /** How a build came out, in one line: "4 of 5 built; 1 failed." `null` while it runs. */ export function aiBuildOutcomeLine(job) {
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../../../libs/plugins/ai/src/lib/model/ai-build-progress.ts"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport type { AiJobItemLedger, AiJobSummary } from './ai-jobs.types'\n\n/**\n * What a `build` job shows of each item (AGL-3616), wherever it is shown —\n * the AI jobs drawer, the job's own page, the chat card: the item, where it\n * stands, what it cost, and what became of its credits when it failed.\n *\n * Pure: no React, no request.\n */\n\n/** Where one item stands, as a row's icon reads it. */\nexport type AiBuildItemRowState = 'done' | 'active' | 'waiting' | 'failed' | 'skipped'\n\nexport interface AiBuildItemRow {\n slot: string\n /** \"Page: About\", \"Form: Contact\". */\n label: string\n state: AiBuildItemRowState\n /** What the person should know: the failure, the note, what was given back. */\n detail: string | null\n}\n\nconst OP_NOUNS: Readonly<Record<string, string>> = {\n page: 'Page',\n layout: 'Layout',\n form: 'Form',\n component: 'Component',\n email: 'Email design',\n template: 'Page template',\n campaign: 'Email campaign',\n workflow: 'Automation',\n}\n\n/** What an operation is called at the start of a row: its own noun, or the op spelled as words. */\nexport function aiBuildOpNoun(op: string): string {\n const known = OP_NOUNS[op]\n if (known) return known\n const words = op.replace(/[-_]+/g, ' ').trim()\n return words ? `${words[0].toUpperCase()}${words.slice(1)}` : 'Item'\n}\n\n/**\n * What became of a failed item's credits (AGL-3616), in the words every\n * surface uses for a failure on our side: \"This one’s on us — you weren’t\n * charged.\" A failure that was not ours — the model declining, a site at its\n * allowance — says what it used, which was charged. `null` for an item that\n * did not fail.\n */\nexport function aiBuildItemRefundCopy(\n row: Pick<AiJobItemLedger, 'status' | 'failure' | 'creditsRefunded' | 'creditsSpent'>,\n): string | null {\n if (row.status !== 'failed') return null\n if (row.failure?.ours) {\n const refunded = Math.max(0, Math.floor(row.creditsRefunded ?? 0))\n if (refunded > 0) {\n return `This one’s on us — you weren’t charged. The ${refunded} ${refunded === 1 ? 'credit' : 'credits'} it used ${refunded === 1 ? 'is' : 'are'} back in your AI credits.`\n }\n return 'This one’s on us — you weren’t charged.'\n }\n const spent = Math.max(0, Math.floor(row.creditsSpent ?? 0))\n return spent > 0 ? `It used ${spent} ${spent === 1 ? 'credit' : 'credits'}.` : null\n}\n\nconst STATES: Readonly<Record<AiJobItemLedger['status'], AiBuildItemRowState>> = {\n pending: 'waiting',\n running: 'active',\n succeeded: 'done',\n degraded: 'done',\n failed: 'failed',\n skipped: 'skipped',\n}\n\n/** One row an item, in the order the build planned them. */\nexport function aiBuildItemRows(job: Pick<AiJobSummary, 'items'>): AiBuildItemRow[] {\n return (job.items ?? []).map((row) => {\n const parts: string[] = []\n if (row.status === 'failed' && row.failure?.message) parts.push(row.failure.message)\n if (row.note) parts.push(row.note)\n const refund = aiBuildItemRefundCopy(row)\n if (refund) parts.push(refund)\n return {\n slot: row.slot,\n label: `${aiBuildOpNoun(row.op)}: ${row.label}`,\n state: STATES[row.status] ?? 'waiting',\n detail: parts.length ? parts.join(' ') : null,\n }\n })\n}\n\n/** How a build came out, in one line: \"4 of 5 built; 1 failed.\" `null` while it runs. */\nexport function aiBuildOutcomeLine(job: Pick<AiJobSummary, 'items' | 'status'>): string | null {\n const items = job.items ?? []\n if (!items.length || (job.status !== 'done' && job.status !== 'failed')) return null\n const built = items.filter((row) => row.status === 'succeeded' || row.status === 'degraded').length\n const failed = items.filter((row) => row.status === 'failed').length\n const skipped = items.filter((row) => row.status === 'skipped').length\n const tail = [failed ? `${failed} failed` : '', skipped ? `${skipped} not built` : ''].filter(Boolean)\n return `${built} of ${items.length} built${tail.length ? `; ${tail.join(', ')}` : ''}.`\n}\n\n/** Whether a finished build — or a site that built part of itself — has failed items to try again. */\nexport function aiBuildCanRetry(job: Pick<AiJobSummary, 'kind' | 'status' | 'items'>): boolean {\n // A site that built nothing starts over from its own answers instead.\n const finished = job.kind === 'build' ? job.status === 'done' || job.status === 'failed' : job.kind === 'site' && job.status === 'done'\n return (\n finished &&\n (job.items ?? []).some((row) => row.status === 'failed' || (row.status === 'skipped' && !row.degradedBy?.length))\n )\n}\n\n/**\n * What a guided start that built part of its site says (AGL-3616), in the\n * words every surface uses: \"Built 1 of 2 pages. Home couldn’t be built —\n * that one’s on us…\". `null` when every page was built, or none was.\n */\nexport function aiSitePartialCopy(job: Pick<AiJobSummary, 'items' | 'status'>): string | null {\n const pages = (job.items ?? []).filter((row) => row.op === 'page')\n const built = pages.filter((row) => row.status === 'succeeded' || row.status === 'degraded')\n const unbuilt = (job.items ?? []).filter((row) => row.status === 'failed' || row.status === 'skipped')\n if (job.status !== 'done' || !unbuilt.length || !built.length) return null\n const names = unbuilt.map((row) => (row.op === 'page' ? row.label : `The ${aiBuildOpNoun(row.op).toLowerCase()} “${row.label}”`))\n const list = names.length === 1 ? names[0] : `${names.slice(0, -1).join(', ')} and ${names[names.length - 1]}`\n const refunded = unbuilt.reduce((total, row) => total + Math.max(0, Math.floor(row.creditsRefunded ?? 0)), 0)\n const back = refunded > 0 ? ` The ${refunded} ${refunded === 1 ? 'credit' : 'credits'} it used ${refunded === 1 ? 'is' : 'are'} back in your AI credits.` : ''\n // Only a failure on our side says so; a part the AI declined or an allowance\n // stopped was charged for what it used, and the row says that.\n const ours = unbuilt.every((row) => row.status === 'skipped' || row.failure?.ours === true)\n const why = ours ? ` — that one’s on us, you weren’t charged for ${unbuilt.length === 1 ? 'it' : 'them'}.` : '.'\n return `Built ${built.length} of ${pages.length} ${pages.length === 1 ? 'page' : 'pages'}. ${list} couldn’t be built${why}${back} Try again builds only what failed.`\n}\n"],"names":["OP_NOUNS","page","layout","form","component","email","template","campaign","workflow","aiBuildOpNoun","op","known","words","replace","trim","toUpperCase","slice","aiBuildItemRefundCopy","row","status","failure","ours","refunded","Math","max","floor","creditsRefunded","spent","creditsSpent","STATES","pending","running","succeeded","degraded","failed","skipped","aiBuildItemRows","job","items","map","parts","message","push","note","refund","slot","label","state","detail","length","join","aiBuildOutcomeLine","built","filter","tail","Boolean","aiBuildCanRetry","finished","kind","some","degradedBy","aiSitePartialCopy","pages","unbuilt","names","toLowerCase","list","reduce","total","back","every","why"],"mappings":"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"}
1
+ {"version":3,"sources":["../../../../../../../libs/plugins/ai/src/lib/model/ai-build-progress.ts"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { aiCustomerSafeItem } from './ai-job-failure-copy'\nimport { AI_JOB_PLAN_STEP, type AiJobItemLedger, type AiJobSummary } from './ai-jobs.types'\n\n/**\n * What a `build` job shows of each item (AGL-3616), wherever it is shown —\n * the AI jobs drawer, the job's own page, the chat card: the item, where it\n * stands, what it cost, and what became of its credits when it failed.\n *\n * Pure: no React, no request.\n */\n\n/** Where one item stands, as a row's icon reads it. */\nexport type AiBuildItemRowState = 'done' | 'active' | 'waiting' | 'failed' | 'skipped'\n\nexport interface AiBuildItemRow {\n slot: string\n /** \"Page: About\", \"Form: Contact\". */\n label: string\n state: AiBuildItemRowState\n /** What the person should know: the failure, the note, what was given back. */\n detail: string | null\n /** When the active item started, for the elapsed time beside it; absent on every other row. */\n startedAt?: string | null\n}\n\nconst OP_NOUNS: Readonly<Record<string, string>> = {\n page: 'Page',\n layout: 'Layout',\n form: 'Form',\n component: 'Component',\n email: 'Email design',\n template: 'Page template',\n campaign: 'Email campaign',\n workflow: 'Automation',\n // A guided start's first posts and products (AGL-3676).\n posts: 'Blog',\n products: 'Store',\n}\n\n/** What an operation is called at the start of a row: its own noun, or the op spelled as words. */\nexport function aiBuildOpNoun(op: string): string {\n const known = OP_NOUNS[op]\n if (known) return known\n const words = op.replace(/[-_]+/g, ' ').trim()\n return words ? `${words[0].toUpperCase()}${words.slice(1)}` : 'Item'\n}\n\n/**\n * What became of a failed item's credits (AGL-3616), in the words every\n * surface uses for a failure on our side: \"This one’s on us — you weren’t\n * charged.\" A failure that was not ours — the model declining, a site at its\n * allowance — says what it used, which was charged. `null` for an item that\n * did not fail.\n */\nexport function aiBuildItemRefundCopy(\n row: Pick<AiJobItemLedger, 'status' | 'failure' | 'creditsRefunded' | 'creditsSpent'>,\n): string | null {\n if (row.status !== 'failed') return null\n if (row.failure?.ours) {\n const refunded = Math.max(0, Math.floor(row.creditsRefunded ?? 0))\n if (refunded > 0) {\n return `This one’s on us — you weren’t charged. The ${refunded} ${refunded === 1 ? 'credit' : 'credits'} it used ${refunded === 1 ? 'is' : 'are'} back in your AI credits.`\n }\n return 'This one’s on us — you weren’t charged.'\n }\n const spent = Math.max(0, Math.floor(row.creditsSpent ?? 0))\n return spent > 0 ? `It used ${spent} ${spent === 1 ? 'credit' : 'credits'}.` : null\n}\n\nconst STATES: Readonly<Record<AiJobItemLedger['status'], AiBuildItemRowState>> = {\n pending: 'waiting',\n running: 'active',\n succeeded: 'done',\n degraded: 'done',\n failed: 'failed',\n skipped: 'skipped',\n}\n\n/**\n * The item the build is on (AGL-3596): the one its ledger marks running, else\n * — while the job moves — the first still pending, which is the one its runner\n * builds next. The runner settles an item in the write that records its pass,\n * so the item it is writing reads `pending` until it is done; read as such,\n * every row waited and the build looked stalled. `null` when the job is not\n * moving or nothing is left.\n */\nexport function aiBuildActiveSlot(\n job: Pick<AiJobSummary, 'items'> & Partial<Pick<AiJobSummary, 'status'>>,\n): string | null {\n const items = job.items ?? []\n const running = items.find((row) => row.status === 'running')\n if (running) return running.slot\n if (job.status !== 'queued' && job.status !== 'running') return null\n return items.find((row) => row.status === 'pending')?.slot ?? null\n}\n\n/**\n * When the active item started: when the last item before it settled, which\n * the ledger records, else when the build step started — the first item's\n * start, and the best a ledger written before settling was recorded has.\n */\nexport function aiBuildActiveStartedAt(\n job: Pick<AiJobSummary, 'items'> & Partial<Pick<AiJobSummary, 'steps'>>,\n): string | null {\n let latest: { at: number; iso: string } | null = null\n for (const row of job.items ?? []) {\n const at = row.settledAt ? Date.parse(row.settledAt) : NaN\n if (Number.isFinite(at) && (!latest || at > latest.at)) latest = { at, iso: row.settledAt as string }\n }\n if (latest) return latest.iso\n const step = (job.steps ?? []).find((one) => one.name !== AI_JOB_PLAN_STEP && one.startedAt)\n return step?.startedAt ?? null\n}\n\n/** One row an item, in the order the build planned them; the item it is on is the active one. */\nexport function aiBuildItemRows(\n job: Pick<AiJobSummary, 'items'> & Partial<Pick<AiJobSummary, 'status' | 'steps'>>,\n): AiBuildItemRow[] {\n const active = aiBuildActiveSlot(job)\n return (job.items ?? []).map((ledger) => {\n // A building rule's own words never reach a customer (AGL-3596).\n const row = aiCustomerSafeItem(ledger)\n const parts: string[] = []\n if (row.status === 'failed' && row.failure?.message) parts.push(row.failure.message)\n if (row.note) parts.push(row.note)\n const refund = aiBuildItemRefundCopy(row)\n if (refund) parts.push(refund)\n return {\n slot: row.slot,\n label: `${aiBuildOpNoun(row.op)}: ${row.label}`,\n state: row.slot === active ? 'active' : (STATES[row.status] ?? 'waiting'),\n detail: parts.length ? parts.join(' ') : null,\n ...(row.slot === active ? { startedAt: aiBuildActiveStartedAt(job) } : {}),\n }\n })\n}\n\n/** How a build came out, in one line: \"4 of 5 built; 1 failed.\" `null` while it runs. */\nexport function aiBuildOutcomeLine(job: Pick<AiJobSummary, 'items' | 'status'>): string | null {\n const items = job.items ?? []\n if (!items.length || (job.status !== 'done' && job.status !== 'failed')) return null\n const built = items.filter((row) => row.status === 'succeeded' || row.status === 'degraded').length\n const failed = items.filter((row) => row.status === 'failed').length\n const skipped = items.filter((row) => row.status === 'skipped').length\n const tail = [failed ? `${failed} failed` : '', skipped ? `${skipped} not built` : ''].filter(Boolean)\n return `${built} of ${items.length} built${tail.length ? `; ${tail.join(', ')}` : ''}.`\n}\n\n/** Whether a finished build — or a site that built part of itself — has failed items to try again. */\nexport function aiBuildCanRetry(job: Pick<AiJobSummary, 'kind' | 'status' | 'items'>): boolean {\n // A site that built nothing starts over from its own answers instead.\n const finished = job.kind === 'build' ? job.status === 'done' || job.status === 'failed' : job.kind === 'site' && job.status === 'done'\n return (\n finished &&\n (job.items ?? []).some((row) => row.status === 'failed' || (row.status === 'skipped' && !row.degradedBy?.length))\n )\n}\n\n/**\n * What a guided start that built part of its site says (AGL-3616), in the\n * words every surface uses: \"Built 1 of 2 pages. Home couldn’t be built —\n * that one’s on us…\". `null` when every page was built, or none was.\n */\nexport function aiSitePartialCopy(job: Pick<AiJobSummary, 'items' | 'status'>): string | null {\n const pages = (job.items ?? []).filter((row) => row.op === 'page')\n const built = pages.filter((row) => row.status === 'succeeded' || row.status === 'degraded')\n const unbuilt = (job.items ?? []).filter((row) => row.status === 'failed' || row.status === 'skipped')\n if (job.status !== 'done' || !unbuilt.length || !built.length) return null\n const names = unbuilt.map((row) => (row.op === 'page' ? row.label : `The ${aiBuildOpNoun(row.op).toLowerCase()} “${row.label}”`))\n const list = names.length === 1 ? names[0] : `${names.slice(0, -1).join(', ')} and ${names[names.length - 1]}`\n const refunded = unbuilt.reduce((total, row) => total + Math.max(0, Math.floor(row.creditsRefunded ?? 0)), 0)\n const back = refunded > 0 ? ` The ${refunded} ${refunded === 1 ? 'credit' : 'credits'} it used ${refunded === 1 ? 'is' : 'are'} back in your AI credits.` : ''\n // Only a failure on our side says so; a part the AI declined or an allowance\n // stopped was charged for what it used, and the row says that.\n const ours = unbuilt.every((row) => row.status === 'skipped' || row.failure?.ours === true)\n const why = ours ? ` — that one’s on us, you weren’t charged for ${unbuilt.length === 1 ? 'it' : 'them'}.` : '.'\n return `Built ${built.length} of ${pages.length} ${pages.length === 1 ? 'page' : 'pages'}. ${list} couldn’t be built${why}${back} Try again builds only what failed.`\n}\n"],"names":["aiCustomerSafeItem","AI_JOB_PLAN_STEP","OP_NOUNS","page","layout","form","component","email","template","campaign","workflow","posts","products","aiBuildOpNoun","op","known","words","replace","trim","toUpperCase","slice","aiBuildItemRefundCopy","row","status","failure","ours","refunded","Math","max","floor","creditsRefunded","spent","creditsSpent","STATES","pending","running","succeeded","degraded","failed","skipped","aiBuildActiveSlot","job","items","find","slot","aiBuildActiveStartedAt","latest","at","settledAt","Date","parse","NaN","Number","isFinite","iso","step","steps","one","name","startedAt","aiBuildItemRows","active","map","ledger","parts","message","push","note","refund","label","state","detail","length","join","aiBuildOutcomeLine","built","filter","tail","Boolean","aiBuildCanRetry","finished","kind","some","degradedBy","aiSitePartialCopy","pages","unbuilt","names","toLowerCase","list","reduce","total","back","every","why"],"mappings":"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"}
@@ -0,0 +1,109 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2026 Aglyn LLC
4
+ *
5
+ * Licensed under the Apache License, Version 2.0 (the "License");
6
+ * you may not use this file except in compliance with the License.
7
+ * You may obtain a copy of the License at
8
+ *
9
+ * http://www.apache.org/licenses/LICENSE-2.0
10
+ *
11
+ * Unless required by applicable law or agreed to in writing, software
12
+ * distributed under the License is distributed on an "AS IS" BASIS,
13
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ * See the License for the specific language governing permissions and
15
+ * limitations under the License.
16
+ */
17
+ /**
18
+ * An `edit` job (AGL-3616): a change to a page or a layout the site already
19
+ * has, asked for in words, made without the Besigner open.
20
+ *
21
+ * It speaks the Assist edit rung's own protocol — the same tool, the same
22
+ * closed world of element ids, the same validators, the same canvas mutators
23
+ * — against the stored document instead of an open canvas, and the change is
24
+ * saved where no visitor sees it:
25
+ *
26
+ * - on a plan with version history, as a NEW version beside the one it
27
+ * started from, which becomes the page's current version only when the
28
+ * page is not published (no visitor reaches it); a published page's and a
29
+ * layout's current version never move;
30
+ * - on a plan without it, in place, and only on a version no visitor
31
+ * reaches — an unpublished page's, or a version that is not the current
32
+ * one. Anything else is refused, before anything is spent.
33
+ *
34
+ * Pure: the inputs, the sentences a person reads, and the outline the model
35
+ * is shown. The runner is `jobs/ai-job-edit-step.ts`.
36
+ */
37
+ /** The documents an edit job changes: those that keep versions and render on a site. */
38
+ export declare const AI_EDIT_TARGET_KINDS: readonly ["screen", "layout"];
39
+ export type AiEditTargetKind = (typeof AI_EDIT_TARGET_KINDS)[number];
40
+ export interface AiEditJobInputs {
41
+ /** The page's or layout's document id, on the job's site. */
42
+ target: string;
43
+ /** Which collection the id is in; both are looked in, a page's first, when absent. */
44
+ targetKind: AiEditTargetKind | null;
45
+ /** The version to start from; the document's current version when absent. */
46
+ versionId: string | null;
47
+ }
48
+ export declare const AI_EDIT_TARGET_REQUIRED_COPY = "Name the page or layout to change.";
49
+ export declare const AI_EDIT_TARGET_KIND_COPY = "inputs.targetKind must be screen or layout";
50
+ export declare const AI_EDIT_VERSION_ID_COPY = "inputs.versionId must name a version of the page or layout";
51
+ /** A job's inputs read, or the sentence that says what is wrong with them. */
52
+ export declare function parseAiEditJobInputs(inputs: Readonly<Record<string, unknown>> | null | undefined): AiEditJobInputs | string;
53
+ export declare const AI_EDIT_NO_SITE_COPY = "Open the site the change is for before starting the job";
54
+ export declare const AI_EDIT_GONE_COPY = "The page or layout to change is not on the site.";
55
+ export declare const AI_EDIT_VERSION_GONE_COPY = "The version to start from is no longer on the page or layout.";
56
+ export declare const AI_EDIT_EMAIL_COPY = "That is an email design, not a page \u2014 change it from Emails \u2192 Templates.";
57
+ export declare const AI_EDIT_NO_NODES_COPY = "That version has nothing on it to change.";
58
+ /**
59
+ * A change that would land on a version visitors see, on a plan without
60
+ * version history: the versions route's own sentence, after what it means
61
+ * here.
62
+ */
63
+ export declare const AI_EDIT_NEEDS_VERSIONING_COPY = "Visitors see that version, so the change has to go into a new version beside it. Version history requires a Pro plan \u2014 see Billing to upgrade.";
64
+ /** The model answered and no change survived its checks, even after its re-ask. */
65
+ export declare const AI_EDIT_NOTHING_COPY = "No change could be made from that request. Say which part of the page to change, the way it reads on the page, and ask again.";
66
+ /** The stored document moved under the change between the read and the write. */
67
+ export declare const AI_EDIT_STALE_COPY = "The page changed while this edit was being written, so nothing was saved. Ask again.";
68
+ /** The canvas's own guards refused part of the change. */
69
+ export declare const AI_EDIT_REFUSED_COPY = "The editor refused part of this change, so none of it was saved.";
70
+ /** What a version an edit job makes is called, from the change's one-line summary. */
71
+ export declare const AI_EDIT_VERSION_PREFIX = "AI edit";
72
+ /** The longest label a version takes, as the versions route cuts one. */
73
+ export declare const AI_EDIT_VERSION_NAME_MAX_CHARS = 200;
74
+ export declare function aiEditVersionName(summary: string): string;
75
+ /** Where the change landed, which decides what the output's note says. */
76
+ export type AiEditPlacement =
77
+ /** A new version, now the unpublished page's current one. */
78
+ 'new-current'
79
+ /** A new version beside the one it started from, which is unchanged. */
80
+ | 'new-beside'
81
+ /** The version it started from, changed in place: one no visitor reaches. */
82
+ | 'in-place';
83
+ /** The output's note: where the change is, that nothing visitors see moved, and what was left out. */
84
+ export declare function aiEditOutputNote(input: {
85
+ kind: AiEditTargetKind;
86
+ placement: AiEditPlacement;
87
+ leftOut: readonly string[];
88
+ }): string;
89
+ /** What the output says of search fields a published page keeps on the page itself. */
90
+ export declare const AI_EDIT_SEO_LEFT_OUT = "the search title and description, which a published page uses as soon as they are saved \u2014 change them in Page properties";
91
+ /** What the output says of a part a job cannot save on its own. */
92
+ export declare const AI_EDIT_COMPONENT_LEFT_OUT = "saving part of the page as a reusable component, which is done in the editor";
93
+ /**
94
+ * The stored document as the outline the edit rung's protocol reads
95
+ * (`parseAssistEditContext` holds it to its limits): the document root, then
96
+ * every element level by level — each after its parent, so every ancestor
97
+ * chain the check walks is whole — until the rung's cap.
98
+ *
99
+ * In the editor, an outline is the neighborhood of what the author selected.
100
+ * A job has no selection, so it is the TOP of the document, read breadth
101
+ * first: every section, and as deep inside each as the cap reaches. Each
102
+ * element keeps its real child count and the document its real size, so the
103
+ * prompt can say how much the outline leaves out. `null` without a root.
104
+ */
105
+ export declare function aiEditJobOutline(nodes: Readonly<Record<string, unknown>>): {
106
+ selectedId: null;
107
+ total: number;
108
+ nodes: Array<Record<string, unknown>>;
109
+ } | null;
@@ -0,0 +1,157 @@
1
+ import { _ as _extends } from "@swc/helpers/_/_extends";
2
+ /**
3
+ * @license
4
+ * Copyright 2026 Aglyn LLC
5
+ *
6
+ * Licensed under the Apache License, Version 2.0 (the "License");
7
+ * you may not use this file except in compliance with the License.
8
+ * You may obtain a copy of the License at
9
+ *
10
+ * http://www.apache.org/licenses/LICENSE-2.0
11
+ *
12
+ * Unless required by applicable law or agreed to in writing, software
13
+ * distributed under the License is distributed on an "AS IS" BASIS,
14
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ * See the License for the specific language governing permissions and
16
+ * limitations under the License.
17
+ */ import { CANVAS_ROOT_ELEMENT_ID } from "@aglyn/aglyn/foundation/constants/canvas";
18
+ import { ASSIST_EDIT_CONTEXT_MAX_NODES } from "./assist-edit.js";
19
+ /**
20
+ * An `edit` job (AGL-3616): a change to a page or a layout the site already
21
+ * has, asked for in words, made without the Besigner open.
22
+ *
23
+ * It speaks the Assist edit rung's own protocol — the same tool, the same
24
+ * closed world of element ids, the same validators, the same canvas mutators
25
+ * — against the stored document instead of an open canvas, and the change is
26
+ * saved where no visitor sees it:
27
+ *
28
+ * - on a plan with version history, as a NEW version beside the one it
29
+ * started from, which becomes the page's current version only when the
30
+ * page is not published (no visitor reaches it); a published page's and a
31
+ * layout's current version never move;
32
+ * - on a plan without it, in place, and only on a version no visitor
33
+ * reaches — an unpublished page's, or a version that is not the current
34
+ * one. Anything else is refused, before anything is spent.
35
+ *
36
+ * Pure: the inputs, the sentences a person reads, and the outline the model
37
+ * is shown. The runner is `jobs/ai-job-edit-step.ts`.
38
+ */ /** The documents an edit job changes: those that keep versions and render on a site. */ export const AI_EDIT_TARGET_KINDS = [
39
+ 'screen',
40
+ 'layout'
41
+ ];
42
+ const DOCUMENT_ID = /^[A-Za-z0-9_-]{1,64}$/;
43
+ export const AI_EDIT_TARGET_REQUIRED_COPY = 'Name the page or layout to change.';
44
+ export const AI_EDIT_TARGET_KIND_COPY = 'inputs.targetKind must be screen or layout';
45
+ export const AI_EDIT_VERSION_ID_COPY = 'inputs.versionId must name a version of the page or layout';
46
+ /** A job's inputs read, or the sentence that says what is wrong with them. */ export function parseAiEditJobInputs(inputs) {
47
+ const target = inputs == null ? void 0 : inputs['target'];
48
+ if (typeof target !== 'string' || !DOCUMENT_ID.test(target)) return AI_EDIT_TARGET_REQUIRED_COPY;
49
+ const kind = inputs == null ? void 0 : inputs['targetKind'];
50
+ if (kind != null && kind !== '' && !AI_EDIT_TARGET_KINDS.includes(kind)) {
51
+ return AI_EDIT_TARGET_KIND_COPY;
52
+ }
53
+ const versionId = inputs == null ? void 0 : inputs['versionId'];
54
+ if (versionId != null && versionId !== '' && (typeof versionId !== 'string' || !DOCUMENT_ID.test(versionId))) {
55
+ return AI_EDIT_VERSION_ID_COPY;
56
+ }
57
+ return {
58
+ target,
59
+ targetKind: kind ? kind : null,
60
+ versionId: typeof versionId === 'string' && versionId ? versionId : null
61
+ };
62
+ }
63
+ // ── What a person reads ───────────────────────────────────────────────────
64
+ export const AI_EDIT_NO_SITE_COPY = 'Open the site the change is for before starting the job';
65
+ export const AI_EDIT_GONE_COPY = 'The page or layout to change is not on the site.';
66
+ export const AI_EDIT_VERSION_GONE_COPY = 'The version to start from is no longer on the page or layout.';
67
+ export const AI_EDIT_EMAIL_COPY = 'That is an email design, not a page — change it from Emails → Templates.';
68
+ export const AI_EDIT_NO_NODES_COPY = 'That version has nothing on it to change.';
69
+ /**
70
+ * A change that would land on a version visitors see, on a plan without
71
+ * version history: the versions route's own sentence, after what it means
72
+ * here.
73
+ */ export const AI_EDIT_NEEDS_VERSIONING_COPY = 'Visitors see that version, so the change has to go into a new version beside it. Version history requires a Pro plan — see Billing to upgrade.';
74
+ /** The model answered and no change survived its checks, even after its re-ask. */ export const AI_EDIT_NOTHING_COPY = 'No change could be made from that request. Say which part of the page to change, the way it reads on the page, and ask again.';
75
+ /** The stored document moved under the change between the read and the write. */ export const AI_EDIT_STALE_COPY = 'The page changed while this edit was being written, so nothing was saved. Ask again.';
76
+ /** The canvas's own guards refused part of the change. */ export const AI_EDIT_REFUSED_COPY = 'The editor refused part of this change, so none of it was saved.';
77
+ /** What a version an edit job makes is called, from the change's one-line summary. */ export const AI_EDIT_VERSION_PREFIX = 'AI edit';
78
+ /** The longest label a version takes, as the versions route cuts one. */ export const AI_EDIT_VERSION_NAME_MAX_CHARS = 200;
79
+ export function aiEditVersionName(summary) {
80
+ const said = String(summary != null ? summary : '').replace(/\s+/g, ' ').trim();
81
+ return (said ? `${AI_EDIT_VERSION_PREFIX}: ${said}` : AI_EDIT_VERSION_PREFIX).slice(0, AI_EDIT_VERSION_NAME_MAX_CHARS);
82
+ }
83
+ const NOUNS = {
84
+ screen: 'page',
85
+ layout: 'layout'
86
+ };
87
+ /** The output's note: where the change is, that nothing visitors see moved, and what was left out. */ export function aiEditOutputNote(input) {
88
+ const noun = NOUNS[input.kind];
89
+ const where = input.placement === 'new-current' ? `Saved as a new version, now this ${noun}’s current one. The ${noun} is not published, so no visitor sees it until you publish it.` : input.placement === 'new-beside' ? `Saved as a new version beside the one it started from. Nothing visitors see has changed: open it to review it, and publish it when it is ready.` : `Saved on the version it started from, which no visitor sees: open it to review it.`;
90
+ const leftOut = input.leftOut.length ? ` Left out: ${input.leftOut.join('; ')}.` : '';
91
+ return `${where}${leftOut}`.slice(0, 1000);
92
+ }
93
+ /** What the output says of search fields a published page keeps on the page itself. */ export const AI_EDIT_SEO_LEFT_OUT = 'the search title and description, which a published page uses as soon as they are saved — change them in Page properties';
94
+ /** What the output says of a part a job cannot save on its own. */ export const AI_EDIT_COMPONENT_LEFT_OUT = 'saving part of the page as a reusable component, which is done in the editor';
95
+ // ── The outline the model is shown ────────────────────────────────────────
96
+ const isRecord = (value)=>typeof value === 'object' && value !== null && !Array.isArray(value);
97
+ /**
98
+ * The stored document as the outline the edit rung's protocol reads
99
+ * (`parseAssistEditContext` holds it to its limits): the document root, then
100
+ * every element level by level — each after its parent, so every ancestor
101
+ * chain the check walks is whole — until the rung's cap.
102
+ *
103
+ * In the editor, an outline is the neighborhood of what the author selected.
104
+ * A job has no selection, so it is the TOP of the document, read breadth
105
+ * first: every section, and as deep inside each as the cap reaches. Each
106
+ * element keeps its real child count and the document its real size, so the
107
+ * prompt can say how much the outline leaves out. `null` without a root.
108
+ */ export function aiEditJobOutline(nodes) {
109
+ const root = nodes[CANVAS_ROOT_ELEMENT_ID];
110
+ if (!isRecord(root)) return null;
111
+ const childrenOf = (node)=>Array.isArray(node['nodes']) ? node['nodes'].filter((id)=>typeof id === 'string' && isRecord(nodes[id])) : [];
112
+ const order = [
113
+ {
114
+ id: CANVAS_ROOT_ELEMENT_ID,
115
+ parentId: null,
116
+ index: 0
117
+ }
118
+ ];
119
+ const seen = new Set([
120
+ CANVAS_ROOT_ELEMENT_ID
121
+ ]);
122
+ // Every element reachable through child lists, for the document's size.
123
+ let total = 1;
124
+ for(let at = 0; at < order.length; at += 1){
125
+ const { id } = order[at];
126
+ childrenOf(nodes[id]).forEach((child, index)=>{
127
+ if (seen.has(child)) return;
128
+ seen.add(child);
129
+ total += 1;
130
+ order.push({
131
+ id: child,
132
+ parentId: id,
133
+ index
134
+ });
135
+ });
136
+ }
137
+ return {
138
+ selectedId: null,
139
+ total,
140
+ nodes: order.slice(0, ASSIST_EDIT_CONTEXT_MAX_NODES).map(({ id, parentId, index })=>{
141
+ const node = nodes[id];
142
+ return _extends({
143
+ id,
144
+ componentId: node['componentId'],
145
+ parentId,
146
+ index,
147
+ childCount: childrenOf(node).length
148
+ }, typeof node['name'] === 'string' && node['name'] ? {
149
+ name: node['name']
150
+ } : {}, isRecord(node['props']) ? {
151
+ props: node['props']
152
+ } : {});
153
+ })
154
+ };
155
+ }
156
+
157
+ //# sourceMappingURL=ai-edit-job.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../../../../libs/plugins/ai/src/lib/model/ai-edit-job.ts"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { CANVAS_ROOT_ELEMENT_ID } from '@aglyn/aglyn/foundation/constants/canvas'\nimport { ASSIST_EDIT_CONTEXT_MAX_NODES } from './assist-edit'\n\n/**\n * An `edit` job (AGL-3616): a change to a page or a layout the site already\n * has, asked for in words, made without the Besigner open.\n *\n * It speaks the Assist edit rung's own protocol — the same tool, the same\n * closed world of element ids, the same validators, the same canvas mutators\n * — against the stored document instead of an open canvas, and the change is\n * saved where no visitor sees it:\n *\n * - on a plan with version history, as a NEW version beside the one it\n * started from, which becomes the page's current version only when the\n * page is not published (no visitor reaches it); a published page's and a\n * layout's current version never move;\n * - on a plan without it, in place, and only on a version no visitor\n * reaches — an unpublished page's, or a version that is not the current\n * one. Anything else is refused, before anything is spent.\n *\n * Pure: the inputs, the sentences a person reads, and the outline the model\n * is shown. The runner is `jobs/ai-job-edit-step.ts`.\n */\n\n/** The documents an edit job changes: those that keep versions and render on a site. */\nexport const AI_EDIT_TARGET_KINDS = ['screen', 'layout'] as const\nexport type AiEditTargetKind = (typeof AI_EDIT_TARGET_KINDS)[number]\n\nexport interface AiEditJobInputs {\n /** The page's or layout's document id, on the job's site. */\n target: string\n /** Which collection the id is in; both are looked in, a page's first, when absent. */\n targetKind: AiEditTargetKind | null\n /** The version to start from; the document's current version when absent. */\n versionId: string | null\n}\n\nconst DOCUMENT_ID = /^[A-Za-z0-9_-]{1,64}$/\n\nexport const AI_EDIT_TARGET_REQUIRED_COPY = 'Name the page or layout to change.'\nexport const AI_EDIT_TARGET_KIND_COPY = 'inputs.targetKind must be screen or layout'\nexport const AI_EDIT_VERSION_ID_COPY = 'inputs.versionId must name a version of the page or layout'\n\n/** A job's inputs read, or the sentence that says what is wrong with them. */\nexport function parseAiEditJobInputs(\n inputs: Readonly<Record<string, unknown>> | null | undefined,\n): AiEditJobInputs | string {\n const target = inputs?.['target']\n if (typeof target !== 'string' || !DOCUMENT_ID.test(target)) return AI_EDIT_TARGET_REQUIRED_COPY\n const kind = inputs?.['targetKind']\n if (kind != null && kind !== '' && !(AI_EDIT_TARGET_KINDS as readonly unknown[]).includes(kind)) {\n return AI_EDIT_TARGET_KIND_COPY\n }\n const versionId = inputs?.['versionId']\n if (versionId != null && versionId !== '' && (typeof versionId !== 'string' || !DOCUMENT_ID.test(versionId))) {\n return AI_EDIT_VERSION_ID_COPY\n }\n return {\n target,\n targetKind: kind ? (kind as AiEditTargetKind) : null,\n versionId: typeof versionId === 'string' && versionId ? versionId : null,\n }\n}\n\n// ── What a person reads ───────────────────────────────────────────────────\n\nexport const AI_EDIT_NO_SITE_COPY = 'Open the site the change is for before starting the job'\nexport const AI_EDIT_GONE_COPY = 'The page or layout to change is not on the site.'\nexport const AI_EDIT_VERSION_GONE_COPY = 'The version to start from is no longer on the page or layout.'\nexport const AI_EDIT_EMAIL_COPY = 'That is an email design, not a page — change it from Emails → Templates.'\nexport const AI_EDIT_NO_NODES_COPY = 'That version has nothing on it to change.'\n\n/**\n * A change that would land on a version visitors see, on a plan without\n * version history: the versions route's own sentence, after what it means\n * here.\n */\nexport const AI_EDIT_NEEDS_VERSIONING_COPY =\n 'Visitors see that version, so the change has to go into a new version beside it. Version history requires a Pro plan — see Billing to upgrade.'\n\n/** The model answered and no change survived its checks, even after its re-ask. */\nexport const AI_EDIT_NOTHING_COPY =\n 'No change could be made from that request. Say which part of the page to change, the way it reads on the page, and ask again.'\n\n/** The stored document moved under the change between the read and the write. */\nexport const AI_EDIT_STALE_COPY =\n 'The page changed while this edit was being written, so nothing was saved. Ask again.'\n\n/** The canvas's own guards refused part of the change. */\nexport const AI_EDIT_REFUSED_COPY = 'The editor refused part of this change, so none of it was saved.'\n\n/** What a version an edit job makes is called, from the change's one-line summary. */\nexport const AI_EDIT_VERSION_PREFIX = 'AI edit'\n\n/** The longest label a version takes, as the versions route cuts one. */\nexport const AI_EDIT_VERSION_NAME_MAX_CHARS = 200\n\nexport function aiEditVersionName(summary: string): string {\n const said = String(summary ?? '').replace(/\\s+/g, ' ').trim()\n return (said ? `${AI_EDIT_VERSION_PREFIX}: ${said}` : AI_EDIT_VERSION_PREFIX).slice(0, AI_EDIT_VERSION_NAME_MAX_CHARS)\n}\n\n/** Where the change landed, which decides what the output's note says. */\nexport type AiEditPlacement =\n /** A new version, now the unpublished page's current one. */\n | 'new-current'\n /** A new version beside the one it started from, which is unchanged. */\n | 'new-beside'\n /** The version it started from, changed in place: one no visitor reaches. */\n | 'in-place'\n\nconst NOUNS: Readonly<Record<AiEditTargetKind, string>> = { screen: 'page', layout: 'layout' }\n\n/** The output's note: where the change is, that nothing visitors see moved, and what was left out. */\nexport function aiEditOutputNote(input: {\n kind: AiEditTargetKind\n placement: AiEditPlacement\n leftOut: readonly string[]\n}): string {\n const noun = NOUNS[input.kind]\n const where =\n input.placement === 'new-current'\n ? `Saved as a new version, now this ${noun}’s current one. The ${noun} is not published, so no visitor sees it until you publish it.`\n : input.placement === 'new-beside'\n ? `Saved as a new version beside the one it started from. Nothing visitors see has changed: open it to review it, and publish it when it is ready.`\n : `Saved on the version it started from, which no visitor sees: open it to review it.`\n const leftOut = input.leftOut.length ? ` Left out: ${input.leftOut.join('; ')}.` : ''\n return `${where}${leftOut}`.slice(0, 1_000)\n}\n\n/** What the output says of search fields a published page keeps on the page itself. */\nexport const AI_EDIT_SEO_LEFT_OUT =\n 'the search title and description, which a published page uses as soon as they are saved — change them in Page properties'\n\n/** What the output says of a part a job cannot save on its own. */\nexport const AI_EDIT_COMPONENT_LEFT_OUT = 'saving part of the page as a reusable component, which is done in the editor'\n\n// ── The outline the model is shown ────────────────────────────────────────\n\nconst isRecord = (value: unknown): value is Record<string, unknown> =>\n typeof value === 'object' && value !== null && !Array.isArray(value)\n\n/**\n * The stored document as the outline the edit rung's protocol reads\n * (`parseAssistEditContext` holds it to its limits): the document root, then\n * every element level by level — each after its parent, so every ancestor\n * chain the check walks is whole — until the rung's cap.\n *\n * In the editor, an outline is the neighborhood of what the author selected.\n * A job has no selection, so it is the TOP of the document, read breadth\n * first: every section, and as deep inside each as the cap reaches. Each\n * element keeps its real child count and the document its real size, so the\n * prompt can say how much the outline leaves out. `null` without a root.\n */\nexport function aiEditJobOutline(nodes: Readonly<Record<string, unknown>>): {\n selectedId: null\n total: number\n nodes: Array<Record<string, unknown>>\n} | null {\n const root = nodes[CANVAS_ROOT_ELEMENT_ID]\n if (!isRecord(root)) return null\n const childrenOf = (node: Record<string, unknown>): string[] =>\n Array.isArray(node['nodes']) ? node['nodes'].filter((id): id is string => typeof id === 'string' && isRecord(nodes[id])) : []\n const order: Array<{ id: string; parentId: string | null; index: number }> = [\n { id: CANVAS_ROOT_ELEMENT_ID, parentId: null, index: 0 },\n ]\n const seen = new Set<string>([CANVAS_ROOT_ELEMENT_ID])\n // Every element reachable through child lists, for the document's size.\n let total = 1\n for (let at = 0; at < order.length; at += 1) {\n const { id } = order[at]\n childrenOf(nodes[id] as Record<string, unknown>).forEach((child, index) => {\n if (seen.has(child)) return\n seen.add(child)\n total += 1\n order.push({ id: child, parentId: id, index })\n })\n }\n return {\n selectedId: null,\n total,\n nodes: order.slice(0, ASSIST_EDIT_CONTEXT_MAX_NODES).map(({ id, parentId, index }) => {\n const node = nodes[id] as Record<string, unknown>\n return {\n id,\n componentId: node['componentId'],\n parentId,\n index,\n childCount: childrenOf(node).length,\n ...(typeof node['name'] === 'string' && node['name'] ? { name: node['name'] } : {}),\n ...(isRecord(node['props']) ? { props: node['props'] } : {}),\n }\n }),\n }\n}\n"],"names":["CANVAS_ROOT_ELEMENT_ID","ASSIST_EDIT_CONTEXT_MAX_NODES","AI_EDIT_TARGET_KINDS","DOCUMENT_ID","AI_EDIT_TARGET_REQUIRED_COPY","AI_EDIT_TARGET_KIND_COPY","AI_EDIT_VERSION_ID_COPY","parseAiEditJobInputs","inputs","target","test","kind","includes","versionId","targetKind","AI_EDIT_NO_SITE_COPY","AI_EDIT_GONE_COPY","AI_EDIT_VERSION_GONE_COPY","AI_EDIT_EMAIL_COPY","AI_EDIT_NO_NODES_COPY","AI_EDIT_NEEDS_VERSIONING_COPY","AI_EDIT_NOTHING_COPY","AI_EDIT_STALE_COPY","AI_EDIT_REFUSED_COPY","AI_EDIT_VERSION_PREFIX","AI_EDIT_VERSION_NAME_MAX_CHARS","aiEditVersionName","summary","said","String","replace","trim","slice","NOUNS","screen","layout","aiEditOutputNote","input","noun","where","placement","leftOut","length","join","AI_EDIT_SEO_LEFT_OUT","AI_EDIT_COMPONENT_LEFT_OUT","isRecord","value","Array","isArray","aiEditJobOutline","nodes","root","childrenOf","node","filter","id","order","parentId","index","seen","Set","total","at","forEach","child","has","add","push","selectedId","map","componentId","childCount","name","props"],"mappings":"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"}
@@ -0,0 +1,51 @@
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 { AiInsightTable } from './ai-insight';
18
+ /**
19
+ * Whether a site is published and where, read off its host document — the
20
+ * facts an AI job must be told rather than left to infer. Pure: no read, so
21
+ * every job that already holds the host can use it, and the site inventory
22
+ * every AI job will get (AGL-3661) absorbs it rather than duplicating it.
23
+ */
24
+ export interface AiHostPublishContext {
25
+ /** At least one page a visitor can open. */
26
+ published: boolean;
27
+ /** The address visitors use: a custom domain only once it serves, else the platform subdomain. */
28
+ liveUrl: string | null;
29
+ /** The published pages' paths, `/` first. */
30
+ publishedPages: string[];
31
+ /** When the first page went live, in ms, when the screens passed say so. */
32
+ firstPublishedAt: number | null;
33
+ }
34
+ /**
35
+ * `host.screens` is the routing map publishing writes — screen id to path —
36
+ * so its entries are exactly the pages a visitor can reach. `screens`, when a
37
+ * caller has the page documents, adds when the first one went live.
38
+ */
39
+ export declare function aiHostPublishContext(host: Record<string, unknown> | null | undefined, screens?: ReadonlyArray<{
40
+ publishedAt?: unknown;
41
+ deletedAt?: unknown;
42
+ }>): AiHostPublishContext;
43
+ /** The reader id the site-status table carries. Code writes it; the model never chooses it. */
44
+ export declare const AI_SITE_STATUS_READER = "site.status";
45
+ /**
46
+ * The site's publish state as a table an insight can cite (AGL-2915's trace
47
+ * holds it like any other). Without it, a question about launch was answered
48
+ * from traffic alone, and "no views yet" was read as "not live" for a site
49
+ * that had been live for a minute.
50
+ */
51
+ export declare function aiSiteStatusTable(context: AiHostPublishContext, ref: string): AiInsightTable;