@aglyn/plugins-ai 1.0.0-beta.244 → 1.0.0-beta.247

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 (173) hide show
  1. package/package.json +17 -17
  2. package/src/lib/activity/ai-activity-actions.js +7 -1
  3. package/src/lib/activity/ai-activity-actions.js.map +1 -1
  4. package/src/lib/components/ai-job-links.js +21 -0
  5. package/src/lib/components/ai-job-links.js.map +1 -1
  6. package/src/lib/components/ai-product-zones.d.ts +3 -1
  7. package/src/lib/components/ai-product-zones.js.map +1 -1
  8. package/src/lib/components/ai-products-hub-card.component.js +1 -1
  9. package/src/lib/components/ai-products-hub-card.component.js.map +1 -1
  10. package/src/lib/components/ai-products-proposals.component.js +17 -9
  11. package/src/lib/components/ai-products-proposals.component.js.map +1 -1
  12. package/src/lib/components/ai-site-start-card.component.d.ts +1 -1
  13. package/src/lib/components/ai-site-start-card.component.js +98 -23
  14. package/src/lib/components/ai-site-start-card.component.js.map +1 -1
  15. package/src/lib/components/ai-upsell-dialog.component.js +1 -1
  16. package/src/lib/components/ai-upsell-dialog.component.js.map +1 -1
  17. package/src/lib/declarations.server.js +12 -0
  18. package/src/lib/declarations.server.js.map +1 -1
  19. package/src/lib/jobs/ai-build-capabilities.js +216 -2
  20. package/src/lib/jobs/ai-build-capabilities.js.map +1 -1
  21. package/src/lib/jobs/ai-job-build-step.d.ts +3 -1
  22. package/src/lib/jobs/ai-job-build-step.js +124 -18
  23. package/src/lib/jobs/ai-job-build-step.js.map +1 -1
  24. package/src/lib/jobs/ai-job-duplicate-step.d.ts +123 -0
  25. package/src/lib/jobs/ai-job-duplicate-step.js +269 -0
  26. package/src/lib/jobs/ai-job-duplicate-step.js.map +1 -0
  27. package/src/lib/jobs/ai-job-form-dataset.d.ts +8 -5
  28. package/src/lib/jobs/ai-job-form-dataset.js +28 -10
  29. package/src/lib/jobs/ai-job-form-dataset.js.map +1 -1
  30. package/src/lib/jobs/ai-job-form-step.d.ts +20 -4
  31. package/src/lib/jobs/ai-job-form-step.js +98 -28
  32. package/src/lib/jobs/ai-job-form-step.js.map +1 -1
  33. package/src/lib/jobs/ai-job-layout-language.d.ts +6 -2
  34. package/src/lib/jobs/ai-job-layout-language.js +29 -5
  35. package/src/lib/jobs/ai-job-layout-language.js.map +1 -1
  36. package/src/lib/jobs/ai-job-layout-step.js +4 -1
  37. package/src/lib/jobs/ai-job-layout-step.js.map +1 -1
  38. package/src/lib/jobs/ai-job-media-step.d.ts +239 -0
  39. package/src/lib/jobs/ai-job-media-step.js +610 -0
  40. package/src/lib/jobs/ai-job-media-step.js.map +1 -0
  41. package/src/lib/jobs/ai-job-navigation-step.d.ts +157 -0
  42. package/src/lib/jobs/ai-job-navigation-step.js +439 -0
  43. package/src/lib/jobs/ai-job-navigation-step.js.map +1 -0
  44. package/src/lib/jobs/ai-job-page-language.d.ts +4 -1
  45. package/src/lib/jobs/ai-job-page-language.js +30 -5
  46. package/src/lib/jobs/ai-job-page-language.js.map +1 -1
  47. package/src/lib/jobs/ai-job-page-sections.js +5 -4
  48. package/src/lib/jobs/ai-job-page-sections.js.map +1 -1
  49. package/src/lib/jobs/ai-job-page-step.js +3 -2
  50. package/src/lib/jobs/ai-job-page-step.js.map +1 -1
  51. package/src/lib/jobs/ai-job-plan-step.d.ts +14 -3
  52. package/src/lib/jobs/ai-job-plan-step.js +87 -20
  53. package/src/lib/jobs/ai-job-plan-step.js.map +1 -1
  54. package/src/lib/jobs/ai-job-products-step.d.ts +2 -2
  55. package/src/lib/jobs/ai-job-products-step.js +2 -2
  56. package/src/lib/jobs/ai-job-products-step.js.map +1 -1
  57. package/src/lib/jobs/ai-job-settings-step.d.ts +268 -0
  58. package/src/lib/jobs/ai-job-settings-step.js +690 -0
  59. package/src/lib/jobs/ai-job-settings-step.js.map +1 -0
  60. package/src/lib/jobs/ai-job-site-content.d.ts +22 -8
  61. package/src/lib/jobs/ai-job-site-content.js +33 -15
  62. package/src/lib/jobs/ai-job-site-content.js.map +1 -1
  63. package/src/lib/jobs/ai-job-site-datasets.d.ts +3 -1
  64. package/src/lib/jobs/ai-job-site-datasets.js +13 -5
  65. package/src/lib/jobs/ai-job-site-datasets.js.map +1 -1
  66. package/src/lib/jobs/ai-job-site-events.d.ts +148 -0
  67. package/src/lib/jobs/ai-job-site-events.js +313 -0
  68. package/src/lib/jobs/ai-job-site-events.js.map +1 -0
  69. package/src/lib/jobs/ai-job-site-step.d.ts +12 -4
  70. package/src/lib/jobs/ai-job-site-step.js +132 -26
  71. package/src/lib/jobs/ai-job-site-step.js.map +1 -1
  72. package/src/lib/jobs/ai-job-tracking-step.d.ts +184 -0
  73. package/src/lib/jobs/ai-job-tracking-step.js +501 -0
  74. package/src/lib/jobs/ai-job-tracking-step.js.map +1 -0
  75. package/src/lib/jobs/ai-layout-stock-photos.d.ts +21 -0
  76. package/src/lib/jobs/ai-layout-stock-photos.js +41 -4
  77. package/src/lib/jobs/ai-layout-stock-photos.js.map +1 -1
  78. package/src/lib/jobs/ai-site-publish.d.ts +62 -4
  79. package/src/lib/jobs/ai-site-publish.js +202 -56
  80. package/src/lib/jobs/ai-site-publish.js.map +1 -1
  81. package/src/lib/jobs/ai-stock-photo-picker.d.ts +24 -0
  82. package/src/lib/jobs/ai-stock-photo-picker.js +108 -0
  83. package/src/lib/jobs/ai-stock-photo-picker.js.map +1 -0
  84. package/src/lib/jobs/fixtures/ai-jazz-events-build-plan-recording.d.ts +37 -0
  85. package/src/lib/jobs/fixtures/ai-jazz-events-build-plan-recording.js +47 -0
  86. package/src/lib/jobs/fixtures/ai-jazz-events-build-plan-recording.js.map +1 -0
  87. package/src/lib/jobs/fixtures/ai-stock-photo-agl3760-recordings.d.ts +21 -0
  88. package/src/lib/jobs/fixtures/ai-stock-photo-agl3760-recordings.js +128 -0
  89. package/src/lib/jobs/fixtures/ai-stock-photo-agl3760-recordings.js.map +1 -0
  90. package/src/lib/layout-language/ai-layout-compiler.d.ts +16 -7
  91. package/src/lib/layout-language/ai-layout-compiler.js +62 -42
  92. package/src/lib/layout-language/ai-layout-compiler.js.map +1 -1
  93. package/src/lib/layout-language/ai-layout-frame-hollows.d.ts +41 -0
  94. package/src/lib/layout-language/ai-layout-frame-hollows.js +330 -0
  95. package/src/lib/layout-language/ai-layout-frame-hollows.js.map +1 -0
  96. package/src/lib/layout-language/ai-layout-frame.d.ts +24 -5
  97. package/src/lib/layout-language/ai-layout-frame.js +93 -20
  98. package/src/lib/layout-language/ai-layout-frame.js.map +1 -1
  99. package/src/lib/layout-language/ai-layout-gaps.js +3 -1
  100. package/src/lib/layout-language/ai-layout-gaps.js.map +1 -1
  101. package/src/lib/layout-language/ai-layout-labels.d.ts +70 -0
  102. package/src/lib/layout-language/ai-layout-labels.js +162 -0
  103. package/src/lib/layout-language/ai-layout-labels.js.map +1 -0
  104. package/src/lib/layout-language/ai-layout-links.js +5 -2
  105. package/src/lib/layout-language/ai-layout-links.js.map +1 -1
  106. package/src/lib/layout-language/ai-layout-listings.d.ts +49 -1
  107. package/src/lib/layout-language/ai-layout-listings.js +66 -5
  108. package/src/lib/layout-language/ai-layout-listings.js.map +1 -1
  109. package/src/lib/layout-language/ai-layout-tree.d.ts +2 -0
  110. package/src/lib/layout-language/ai-layout-tree.js +17 -0
  111. package/src/lib/layout-language/ai-layout-tree.js.map +1 -1
  112. package/src/lib/model/ai-build-event-page.d.ts +70 -0
  113. package/src/lib/model/ai-build-event-page.js +145 -0
  114. package/src/lib/model/ai-build-event-page.js.map +1 -0
  115. package/src/lib/model/ai-build-job.d.ts +44 -0
  116. package/src/lib/model/ai-build-job.js +141 -13
  117. package/src/lib/model/ai-build-job.js.map +1 -1
  118. package/src/lib/model/ai-build-plan.d.ts +39 -3
  119. package/src/lib/model/ai-build-plan.js +59 -5
  120. package/src/lib/model/ai-build-plan.js.map +1 -1
  121. package/src/lib/model/ai-credit-estimate.d.ts +52 -0
  122. package/src/lib/model/ai-credit-estimate.js +51 -0
  123. package/src/lib/model/ai-credit-estimate.js.map +1 -1
  124. package/src/lib/model/ai-job-activity.js +6 -1
  125. package/src/lib/model/ai-job-activity.js.map +1 -1
  126. package/src/lib/model/ai-jobs.types.d.ts +18 -2
  127. package/src/lib/model/ai-jobs.types.js +6 -1
  128. package/src/lib/model/ai-jobs.types.js.map +1 -1
  129. package/src/lib/model/ai-layout-menus.d.ts +104 -0
  130. package/src/lib/model/ai-layout-menus.js +518 -0
  131. package/src/lib/model/ai-layout-menus.js.map +1 -0
  132. package/src/lib/model/ai-plan-capabilities.d.ts +8 -0
  133. package/src/lib/model/ai-plan-capabilities.js.map +1 -1
  134. package/src/lib/model/ai-products.d.ts +31 -1
  135. package/src/lib/model/ai-products.js +34 -1
  136. package/src/lib/model/ai-products.js.map +1 -1
  137. package/src/lib/model/ai-site-inventory.d.ts +17 -0
  138. package/src/lib/model/ai-site-inventory.js +5 -0
  139. package/src/lib/model/ai-site-inventory.js.map +1 -1
  140. package/src/lib/model/ai-site-job.d.ts +12 -2
  141. package/src/lib/model/ai-site-job.js +39 -12
  142. package/src/lib/model/ai-site-job.js.map +1 -1
  143. package/src/lib/model/ai-site-store-pages.js +1 -1
  144. package/src/lib/model/ai-site-store-pages.js.map +1 -1
  145. package/src/lib/runtime/ai-doctrine-validators.d.ts +78 -3
  146. package/src/lib/runtime/ai-doctrine-validators.js +219 -31
  147. package/src/lib/runtime/ai-doctrine-validators.js.map +1 -1
  148. package/src/lib/runtime/ai-doctrine.d.ts +6 -1
  149. package/src/lib/runtime/ai-doctrine.js +16 -7
  150. package/src/lib/runtime/ai-doctrine.js.map +1 -1
  151. package/src/lib/runtime/ai-eval-live.d.ts +1 -1
  152. package/src/lib/runtime/ai-eval-live.js +1 -1
  153. package/src/lib/runtime/ai-eval-live.js.map +1 -1
  154. package/src/lib/runtime/ai-palette.d.ts +3 -1
  155. package/src/lib/runtime/ai-palette.generated.js +499 -11
  156. package/src/lib/runtime/ai-palette.generated.js.map +1 -1
  157. package/src/lib/runtime/ai-palette.js +5 -3
  158. package/src/lib/runtime/ai-palette.js.map +1 -1
  159. package/src/lib/runtime/ai-products-generation.d.ts +4 -2
  160. package/src/lib/runtime/ai-products-generation.js +12 -6
  161. package/src/lib/runtime/ai-products-generation.js.map +1 -1
  162. package/src/lib/runtime/ai-template-examples.js +8 -2
  163. package/src/lib/runtime/ai-template-examples.js.map +1 -1
  164. package/src/lib/runtime/site-inventory.d.ts +12 -0
  165. package/src/lib/runtime/site-inventory.js +29 -1
  166. package/src/lib/runtime/site-inventory.js.map +1 -1
  167. package/src/lib/server.js +20 -0
  168. package/src/lib/server.js.map +1 -1
  169. package/src/lib/testing/stand-in-dataset-index.js +37 -3
  170. package/src/lib/testing/stand-in-dataset-index.js.map +1 -1
  171. package/src/lib/tools/ai-products-tool.d.ts +3 -1
  172. package/src/lib/tools/ai-products-tool.js +15 -5
  173. package/src/lib/tools/ai-products-tool.js.map +1 -1
@@ -34,10 +34,11 @@ import { aiPageSectionNodeId } from "./ai-job-page-sections.js";
34
34
  import { AI_LAYOUT_LISTINGS_INPUT, aiLayoutIsShopPage } from "../layout-language/ai-layout-listings.js";
35
35
  import { aiSiteKindOfInputs } from "../model/ai-site-kinds.js";
36
36
  import { AI_LAYOUT_FORM_PAGE_INPUT, AI_LAYOUT_LANGUAGE_INPUT, aiLayoutFormPageOfPlan } from "./ai-job-page-language.js";
37
- import { aiJobPublishesSite, aiMergeSitePublish, aiPublishGuidedSite } from "./ai-site-publish.js";
37
+ import { aiJobPublishesSite, aiMergeSitePublish, aiPublishGuidedSite, aiRestoreGuidedBlogEntry } from "./ai-site-publish.js";
38
38
  import { AI_SITE_CONTENT_INPUT, AI_SITE_POST_BUDGET, AI_SITE_POSTS, AI_SITE_POSTS_LABEL, AI_SITE_PRODUCTS_LABEL, AI_SITE_PRODUCTS_PRICE_NOTE, aiPublishSitePosts, aiSiteContentBriefLines, aiSiteContentPart, aiSiteContentRefusal, aiSiteListings, aiSiteProductsBriefLine, createAiSiteProductsRunner, runAiSitePostsUnit } from "./ai-job-site-content.js";
39
39
  import { dropPluginSiteCache } from "@aglyn/aglyn/plugin-manager/plugin-site-cache";
40
40
  import { AI_SITE_DATASET_BUDGET, AI_SITE_DATASET_INPUT, AI_SITE_DATASETS_MAX, aiSiteDatasetBriefLines, aiSiteDatasetInputOf, aiSiteDatasetListings, aiSiteDatasetPlacedPhotos, aiSiteDatasetRefusal, aiSitePlanDatasets, aiSiteRecordTemplateOf, runAiSiteDatasetUnit } from "./ai-job-site-datasets.js";
41
+ import { AI_SITE_EVENT_INPUT, AI_SITE_EVENT_LABEL, AI_SITE_EVENT_MINIMUM_MS, AI_SITE_EVENTS_MAX, aiSiteEventListings, aiSiteEventRefusal, aiSitePlanEvents, runAiSiteEventUnit } from "./ai-job-site-events.js";
41
42
  import { AI_SITE_LOOK_BUDGET, aiRunSiteLook } from "./ai-job-site-look.js";
42
43
  import { AI_SITE_STORE_PAGES_INPUT, aiSiteStorePagesRefusal, runAiSiteStorePagesUnit } from "./ai-job-site-store-pages.js";
43
44
  import { AI_SITE_STORE_LINKS_INPUT, AI_SITE_STORE_PAGES_LABEL, AI_SITE_STORE_PAGES_NOTE, aiStoreFrameLinks, aiStorePagesOfPlan } from "../model/ai-site-store-pages.js";
@@ -88,6 +89,12 @@ import { aiJobStepRunMinimumMs, aiJobStepRunnerFor, registerAiJobStep, registerA
88
89
  jobKind: 'text',
89
90
  resource: 'draft'
90
91
  },
92
+ // An event-led start's first events (AGL-3755): the events-calendar
93
+ // plugin's writer keeps each, run by the scaffold's own pass.
94
+ event: {
95
+ jobKind: 'text',
96
+ resource: 'draft'
97
+ },
91
98
  // The scaffold's own runner writes them, by code (`ai-job-site-store-pages.ts`).
92
99
  store: {
93
100
  jobKind: 'text',
@@ -138,7 +145,7 @@ export const AI_SITE_NO_PLAN_COPY = 'This site job has no confirmed plan to buil
138
145
  * (one a pass, the largest part) and a welcome email — with nothing to
139
146
  * spare, so a runner that never finishes is still bounded while a real site
140
147
  * is not.
141
- */ export const AI_SITE_MAX_PASSES = AI_SITE_PAGES.max * (AI_SITE_MAX_SECTIONS + 1) + CREATION_UNITS.length + AI_SITE_DATASETS_MAX + AI_SITE_POSTS + 2;
148
+ */ export const AI_SITE_MAX_PASSES = AI_SITE_PAGES.max * (AI_SITE_MAX_SECTIONS + 1) + CREATION_UNITS.length + AI_SITE_DATASETS_MAX + AI_SITE_EVENTS_MAX + AI_SITE_POSTS + 2;
142
149
  /**
143
150
  * The units a plan implies, in build order: the palette first, because a
144
151
  * member reads it while the pages are still building; then the layout every
@@ -200,6 +207,16 @@ export const AI_SITE_NO_PLAN_COPY = 'This site job has no confirmed plan to buil
200
207
  label: AI_SITE_PRODUCTS_LABEL
201
208
  }));
202
209
  }
210
+ // An event-led start's first events (AGL-3755), before the pages that list them.
211
+ aiSitePlanEvents(plan).forEach((item, index)=>{
212
+ units.push(_extends({
213
+ kind: 'event'
214
+ }, UNIT_KINDS.event, {
215
+ slot: `v${index}`,
216
+ item,
217
+ label: item.name || AI_SITE_EVENT_LABEL
218
+ }));
219
+ });
203
220
  plan.screens.forEach((screen, index)=>{
204
221
  units.push(_extends({
205
222
  kind: 'page'
@@ -376,9 +393,9 @@ export const AI_SITE_NO_PLAN_COPY = 'This site job has no confirmed plan to buil
376
393
  * palette change — and a unit whose plan recorded no id are named by this
377
394
  * job's id and the unit's slot, the name every draft of such a plan has.
378
395
  */ export function aiSiteUnitJobId(job, unit) {
379
- var _ref, _ref1;
380
- var _unit_creation, _unit_screen;
381
- const recorded = (_ref = (_ref1 = (_unit_creation = unit.creation) == null ? void 0 : _unit_creation.id) != null ? _ref1 : (_unit_screen = unit.screen) == null ? void 0 : _unit_screen.id) != null ? _ref : unit.kind === 'email' ? aiRecordedJobDraftId(job, 'email') : null;
396
+ var _ref, _ref1, _ref2;
397
+ var _unit_creation, _unit_screen, _unit_item;
398
+ const recorded = (_ref = (_ref1 = (_ref2 = (_unit_creation = unit.creation) == null ? void 0 : _unit_creation.id) != null ? _ref2 : (_unit_screen = unit.screen) == null ? void 0 : _unit_screen.id) != null ? _ref1 : (_unit_item = unit.item) == null ? void 0 : _unit_item.id) != null ? _ref : unit.kind === 'email' ? aiRecordedJobDraftId(job, 'email') : null;
382
399
  return recorded || `${job.$id}-${unit.slot}`;
383
400
  }
384
401
  /**
@@ -491,7 +508,7 @@ export const AI_SITE_NO_PLAN_COPY = 'This site job has no confirmed plan to buil
491
508
  // ids are minted on the plan, and the platform writes the header's links.
492
509
  // A page is told them too, so its buttons may go to a page built after it.
493
510
  if (job.kind === 'site' && (unit.kind === 'layout' || unit.kind === 'page')) {
494
- var _job_outputs4, _job_outputs5;
511
+ var _job_outputs4, _job_outputs5, _job_outputs6;
495
512
  var _aiSiteKindOfInputs, _aiSiteKindOfInputs1;
496
513
  // A guided start links every page the person asked for (AGL-3660), and
497
514
  // the blog its first posts are written into, by its path, second after
@@ -551,6 +568,11 @@ export const AI_SITE_NO_PLAN_COPY = 'This site job has no confirmed plan to buil
551
568
  datasets: aiSitePlanDatasets(plan),
552
569
  screens: merged.screens,
553
570
  delivered
571
+ }), // The events this start drafted, in the section that names them (AGL-3755).
572
+ ...aiSiteEventListings({
573
+ outputs: (_job_outputs6 = job.outputs) != null ? _job_outputs6 : [],
574
+ items: aiSitePlanEvents(plan),
575
+ screens: merged.screens
554
576
  }));
555
577
  if (listings.length) unitInputs[AI_LAYOUT_LISTINGS_INPUT] = listings;
556
578
  // A paid store's header links its account beside the cart, and its footer
@@ -565,10 +587,10 @@ export const AI_SITE_NO_PLAN_COPY = 'This site job has no confirmed plan to buil
565
587
  // A site's pages and its layout are designed in the layout language and
566
588
  // compiled (AGL-3660), and a page is told which page places the site's form.
567
589
  if (unit.kind === 'layout' || unit.kind === 'page') {
568
- var _job_outputs6;
590
+ var _job_outputs7;
569
591
  var _look_proposal;
570
592
  // The look designed first (AGL-3660): its header arrangement and band rhythm.
571
- const look = ((_job_outputs6 = job.outputs) != null ? _job_outputs6 : []).find((output)=>output.resource === 'theme' && output.id === 'look');
593
+ const look = ((_job_outputs7 = job.outputs) != null ? _job_outputs7 : []).find((output)=>output.resource === 'theme' && output.id === 'look');
572
594
  const style = look == null ? void 0 : (_look_proposal = look.proposal) == null ? void 0 : _look_proposal['style'];
573
595
  if (style) unitInputs['siteStyle'] = {
574
596
  headerAlign: style['headerAlign'],
@@ -580,11 +602,11 @@ export const AI_SITE_NO_PLAN_COPY = 'This site job has no confirmed plan to buil
580
602
  if (formPage) unitInputs[AI_LAYOUT_FORM_PAGE_INPUT] = formPage;
581
603
  }
582
604
  if (unit.kind === 'posts') {
583
- var _job_outputs7, _inputs_businessName;
605
+ var _job_outputs8, _inputs_businessName;
584
606
  // The posts already written (one a pass), the addresses the site's own
585
607
  // pages answer at, and the byline the person gave (AGL-3676).
586
608
  const posts = {
587
- written: ((_job_outputs7 = job.outputs) != null ? _job_outputs7 : []).filter((output)=>output.resource === 'entry').map((output)=>({
609
+ written: ((_job_outputs8 = job.outputs) != null ? _job_outputs8 : []).filter((output)=>output.resource === 'entry').map((output)=>({
588
610
  id: output.id,
589
611
  title: output.label
590
612
  })),
@@ -596,6 +618,8 @@ export const AI_SITE_NO_PLAN_COPY = 'This site job has no confirmed plan to buil
596
618
  unitInputs[AI_SITE_CONTENT_INPUT] = posts;
597
619
  }
598
620
  if (unit.kind === 'products') unitInputs['target'] = 'catalog';
621
+ // The event an event unit drafts (AGL-3755).
622
+ if (unit.kind === 'event' && unit.item) unitInputs[AI_SITE_EVENT_INPUT] = unit.item;
599
623
  // Where the plan lists a dataset, which its design reads, and the form
600
624
  // that writes to it (AGL-3616).
601
625
  if (unit.kind === 'dataset' && unit.creation) {
@@ -845,7 +869,7 @@ export const aiSiteJobAdmission = createAiSiteJobAdmission();
845
869
  }).map((unit)=>unit.slot);
846
870
  return units.map((unit)=>_extends({
847
871
  slot: unit.slot,
848
- op: unit.kind === 'theme' || unit.kind === 'posts' || unit.kind === 'products' || unit.kind === 'dataset' || unit.kind === 'store' ? unit.kind : unit.jobKind,
872
+ op: unit.kind === 'theme' || unit.kind === 'posts' || unit.kind === 'products' || unit.kind === 'dataset' || unit.kind === 'event' || unit.kind === 'store' ? unit.kind : unit.jobKind,
849
873
  label: unit.label
850
874
  }, unit.creation ? {
851
875
  creation: unit.creation
@@ -891,22 +915,24 @@ export const aiSiteJobAdmission = createAiSiteJobAdmission();
891
915
  return aiSiteJobUnits(plan, {
892
916
  welcomeEmail: aiSiteWelcomeEmail(inputs, freeTaste),
893
917
  content: aiSiteContentPart(job.inputs, freeTaste)
894
- }).filter((unit)=>unit.kind === 'store' && ledgered || unit.kind === 'theme' || unit.kind === 'posts' || unit.kind === 'dataset' || unit.kind !== 'store' && runnerFor(unit.jobKind));
918
+ }).filter((unit)=>unit.kind === 'store' && ledgered || unit.kind === 'theme' || unit.kind === 'posts' || unit.kind === 'dataset' || unit.kind === 'event' || unit.kind !== 'store' && runnerFor(unit.jobKind));
895
919
  }
896
920
  export function createAiJobSiteStep(deps = {}) {
897
- var _deps_runnerFor, _deps_readNodes, _deps_publish, _deps_look, _deps_contentRefusal, _deps_datasetRefusal, _deps_storePagesRefusal, _deps_publishPosts, _deps_dropCache;
921
+ var _deps_runnerFor, _deps_readNodes, _deps_publish, _deps_look, _deps_contentRefusal, _deps_datasetRefusal, _deps_eventRefusal, _deps_storePagesRefusal, _deps_publishPosts, _deps_dropCache, _deps_restoreBlogEntry;
898
922
  const runnerFor = (_deps_runnerFor = deps.runnerFor) != null ? _deps_runnerFor : aiJobStepRunnerFor;
899
923
  const readNodes = (_deps_readNodes = deps.readNodes) != null ? _deps_readNodes : readAiDraftNodes;
900
924
  const publish = (_deps_publish = deps.publish) != null ? _deps_publish : aiPublishGuidedSite;
901
925
  const look = (_deps_look = deps.look) != null ? _deps_look : aiRunSiteLook;
902
926
  const contentRefusal = (_deps_contentRefusal = deps.contentRefusal) != null ? _deps_contentRefusal : aiSiteContentRefusal;
903
927
  const datasetRefusal = (_deps_datasetRefusal = deps.datasetRefusal) != null ? _deps_datasetRefusal : aiSiteDatasetRefusal;
928
+ const eventRefusal = (_deps_eventRefusal = deps.eventRefusal) != null ? _deps_eventRefusal : aiSiteEventRefusal;
904
929
  const storePagesRefusal = (_deps_storePagesRefusal = deps.storePagesRefusal) != null ? _deps_storePagesRefusal : aiSiteStorePagesRefusal;
905
930
  const publishPosts = (_deps_publishPosts = deps.publishPosts) != null ? _deps_publishPosts : aiPublishSitePosts;
906
931
  const dropCache = (_deps_dropCache = deps.dropCache) != null ? _deps_dropCache : dropPluginSiteCache;
932
+ const restoreBlogEntry = (_deps_restoreBlogEntry = deps.restoreBlogEntry) != null ? _deps_restoreBlogEntry : aiRestoreGuidedBlogEntry;
907
933
  return async (context)=>{
908
- var _ref, _job_outputs, _deps_posts, _deps_products, _deps_dataset, _deps_storePages, _job_outputs1;
909
- var _job_items, _rows_get, _rows_get1, _rows_get2;
934
+ var _ref, _job_outputs, _deps_posts, _deps_products, _deps_dataset, _deps_event, _deps_storePages, _job_outputs1;
935
+ var _job_items, _rows_get, _rows_get1, _rows_get2, _rows_get3;
910
936
  const { job } = context;
911
937
  // The scaffold asks no model of its own. What it names where it spends
912
938
  // nothing is the model its plan ran on, which is the one exchange this
@@ -953,13 +979,21 @@ export function createAiJobSiteStep(deps = {}) {
953
979
  */ const finish = async (outcome, pages)=>{
954
980
  var _job_sitePublish, _ref;
955
981
  var _postsRow_outputs;
956
- if (!aiJobPublishesSite(job) || !job.hostId || !pages.length) return outcome;
982
+ if (!aiJobPublishesSite(job) || !job.hostId) return outcome;
957
983
  const previous = (_job_sitePublish = job.sitePublish) != null ? _job_sitePublish : null;
984
+ const wasLive = Boolean(previous == null ? void 0 : previous.published.length);
958
985
  const live = new Set(((_ref = previous == null ? void 0 : previous.published) != null ? _ref : []).map((page)=>page.id));
959
986
  const fresh = pages.filter((page)=>!live.has(page.id));
960
- if (!fresh.length) return outcome;
987
+ // Posts Try again wrote for a site already live go live too, pages or not (AGL-3739).
988
+ const postsRetried = wasLive && postsRebuilt();
989
+ if (!fresh.length && !postsRetried) return outcome;
961
990
  // A canceled start never puts the site live (AGL-3616): its pages stay drafts.
962
991
  if (await aiJobCancelAsked(context.firestore, job, context.signal)) return outcome;
992
+ if (!fresh.length) {
993
+ var _ref1;
994
+ if (await finishPosts()) await finishBlogEntry((_ref1 = previous == null ? void 0 : previous.published) != null ? _ref1 : []);
995
+ return outcome;
996
+ }
963
997
  // A blog the header links by path before its posts exist (AGL-3660):
964
998
  // owed and not delivered, its links come out of what is published.
965
999
  const postsRow = rows.get('posts');
@@ -971,8 +1005,10 @@ export function createAiJobSiteStep(deps = {}) {
971
1005
  blogUnwritten: !aiBuildItemDelivered(postsRow) || !((_postsRow_outputs = postsRow.outputs) == null ? void 0 : _postsRow_outputs.length)
972
1006
  } : {}, rows.get('store') ? {
973
1007
  unwrittenHrefs: unwrittenStoreHrefs(pages)
974
- } : {}, (previous == null ? void 0 : previous.published.length) ? {
1008
+ } : {}, wasLive ? {
975
1009
  retry: true
1010
+ } : {}, plan.language ? {
1011
+ language: plan.language
976
1012
  } : {})).catch((error)=>{
977
1013
  // The site is built either way; the pages stay drafts and say so.
978
1014
  console.error('ai site publish threw', {
@@ -982,17 +1018,38 @@ export function createAiJobSiteStep(deps = {}) {
982
1018
  });
983
1019
  return null;
984
1020
  });
985
- // The blog's posts went live with the first publish that put a page live.
986
- if ((sitePublish == null ? void 0 : sitePublish.published.length) && !(previous == null ? void 0 : previous.published.length)) await finishPosts();
1021
+ // The blog's posts go live with the first publish that puts a page
1022
+ // live, and on a site already live, when Try again wrote them; then
1023
+ // the header links the blog again, which the first publish took out.
1024
+ if (wasLive ? postsRetried : sitePublish == null ? void 0 : sitePublish.published.length) {
1025
+ var _ref2, _ref3;
1026
+ const posted = await finishPosts();
1027
+ if (posted && wasLive) await finishBlogEntry([
1028
+ ...(_ref2 = previous == null ? void 0 : previous.published) != null ? _ref2 : [],
1029
+ ...(_ref3 = sitePublish == null ? void 0 : sitePublish.published) != null ? _ref3 : []
1030
+ ]);
1031
+ }
987
1032
  if (!sitePublish) return outcome;
988
1033
  return _extends({}, outcome, {
989
1034
  sitePublish: previous ? aiMergeSitePublish(previous, sitePublish) : sitePublish
990
1035
  });
991
1036
  };
992
- /** The blog's posts go live with its pages (AGL-3676), as a person's Publish would put them. */ const finishPosts = async ()=>{
1037
+ /**
1038
+ * Whether the blog's posts part was written by Try again: delivered on a
1039
+ * later attempt than its first. Publishing them again on a later retry
1040
+ * leaves a post already published as it is.
1041
+ */ const postsRebuilt = ()=>{
1042
+ var _row_outputs;
1043
+ const row = rows.get('posts');
1044
+ return Boolean(row && row.attempt > 1 && aiBuildItemDelivered(row) && ((_row_outputs = row.outputs) == null ? void 0 : _row_outputs.length));
1045
+ };
1046
+ /**
1047
+ * The blog's posts go live with its pages (AGL-3676), as a person's
1048
+ * Publish would put them. Whether any did.
1049
+ */ const finishPosts = async ()=>{
993
1050
  var _job_outputs;
994
1051
  const row = rows.get('posts');
995
- if (!row || !aiBuildItemDelivered(row) || !job.hostId) return;
1052
+ if (!row || !aiBuildItemDelivered(row) || !job.hostId) return false;
996
1053
  const ids = new Set(row.outputs);
997
1054
  const posts = ((_job_outputs = job.outputs) != null ? _job_outputs : []).filter((output)=>output.resource === 'entry' && ids.has(output.id));
998
1055
  const published = await publishPosts(context.firestore, {
@@ -1000,7 +1057,7 @@ export function createAiJobSiteStep(deps = {}) {
1000
1057
  outputs: posts,
1001
1058
  now: context.now
1002
1059
  });
1003
- if (!(published == null ? void 0 : published.paths.length)) return;
1060
+ if (!(published == null ? void 0 : published.paths.length)) return false;
1004
1061
  await dropCache({
1005
1062
  hostIds: [
1006
1063
  job.hostId
@@ -1013,6 +1070,34 @@ export function createAiJobSiteStep(deps = {}) {
1013
1070
  jobId: job.$id,
1014
1071
  error
1015
1072
  }));
1073
+ return true;
1074
+ };
1075
+ /**
1076
+ * A blog whose posts Try again put live on a site already live (AGL-3747):
1077
+ * the first publish took every link to it out (AGL-3660), so its header
1078
+ * entry goes back, after the home page's, where no link opens it yet. The
1079
+ * site is live either way; a layout it cannot change is logged.
1080
+ */ const finishBlogEntry = async (published)=>{
1081
+ var _ref;
1082
+ var _published_find;
1083
+ const blog = aiSiteBlogNavPage(aiSitePlanWithoutBlogStandIns(plan.screens).screens);
1084
+ await restoreBlogEntry(context.firestore, {
1085
+ job,
1086
+ pageIds: published.map((page)=>page.id),
1087
+ homeId: (_ref = (_published_find = published.find((page)=>page.path === '/')) == null ? void 0 : _published_find.id) != null ? _ref : null,
1088
+ blog: {
1089
+ label: blog.label,
1090
+ href: blog.href
1091
+ },
1092
+ now: context.now
1093
+ }).catch((error)=>{
1094
+ console.error('ai site blog entry not restored', {
1095
+ orgId: job.orgId,
1096
+ jobId: job.$id,
1097
+ error
1098
+ });
1099
+ return false;
1100
+ });
1016
1101
  };
1017
1102
  /**
1018
1103
  * The pages built so far, as the job reported them. A dataset's record
@@ -1053,7 +1138,7 @@ export function createAiJobSiteStep(deps = {}) {
1053
1138
  const catalog = unit.kind === 'products' ? runnerFor('products') : undefined;
1054
1139
  const runner = unit.kind === 'theme' ? (lookContext)=>look(lookContext, lookContext.job) : unit.kind === 'posts' ? (_deps_posts = deps.posts) != null ? _deps_posts : runAiSitePostsUnit : unit.kind === 'products' ? (_deps_products = deps.products) != null ? _deps_products : catalog ? createAiSiteProductsRunner({
1055
1140
  catalog
1056
- }) : undefined : unit.kind === 'dataset' ? (_deps_dataset = deps.dataset) != null ? _deps_dataset : runAiSiteDatasetUnit : unit.kind === 'store' ? (_deps_storePages = deps.storePages) != null ? _deps_storePages : runAiSiteStorePagesUnit : runnerFor(unit.jobKind);
1141
+ }) : undefined : unit.kind === 'dataset' ? (_deps_dataset = deps.dataset) != null ? _deps_dataset : runAiSiteDatasetUnit : unit.kind === 'event' ? (_deps_event = deps.event) != null ? _deps_event : runAiSiteEventUnit : unit.kind === 'store' ? (_deps_storePages = deps.storePages) != null ? _deps_storePages : runAiSiteStorePagesUnit : runnerFor(unit.jobKind);
1057
1142
  if (!runner) return _extends({}, aiUnspentOutcome(model), init);
1058
1143
  const othersOpen = ledgerUnits.some((one)=>{
1059
1144
  var _rows_get;
@@ -1132,9 +1217,29 @@ export function createAiJobSiteStep(deps = {}) {
1132
1217
  note: `Not built: ${refusal}`
1133
1218
  }));
1134
1219
  }
1220
+ // An event asks the same (AGL-3755): the events plugin runs here, and its
1221
+ // writer admits this member now.
1222
+ if (unit.kind === 'event' && ((_rows_get2 = rows.get(unit.slot)) == null ? void 0 : _rows_get2.status) !== 'running') {
1223
+ const refusal = await eventRefusal(_extends({}, context, {
1224
+ job
1225
+ })).catch((error)=>{
1226
+ console.error('ai site event admission failed', {
1227
+ orgId: job.orgId,
1228
+ jobId: job.$id,
1229
+ slot: unit.slot,
1230
+ error
1231
+ });
1232
+ return AI_SITE_UNIT_EMPTY_COPY;
1233
+ });
1234
+ if (refusal) return closing(settle({
1235
+ slot: unit.slot,
1236
+ status: 'skipped',
1237
+ note: `Not built: ${refusal}`
1238
+ }));
1239
+ }
1135
1240
  // The store's own pages ask the same (AGL-3676): a plan with a store, the
1136
1241
  // commerce plugin here, and a member who may edit the site's pages.
1137
- if (unit.kind === 'store' && ((_rows_get2 = rows.get(unit.slot)) == null ? void 0 : _rows_get2.status) !== 'running') {
1242
+ if (unit.kind === 'store' && ((_rows_get3 = rows.get(unit.slot)) == null ? void 0 : _rows_get3.status) !== 'running') {
1138
1243
  const refusal = await storePagesRefusal(_extends({}, context, {
1139
1244
  job
1140
1245
  })).catch((error)=>{
@@ -1282,7 +1387,7 @@ export const runAiJobSiteStep = createAiJobSiteStep();
1282
1387
  const units = aiSiteJobUnits(plan, {
1283
1388
  welcomeEmail: inputs.welcomeEmail,
1284
1389
  content: aiSiteContentPart(job.inputs, false)
1285
- }).filter((unit)=>(unit.kind === 'theme' || unit.kind === 'posts' || unit.kind === 'dataset' || unit.kind === 'store' || aiJobStepRunnerFor(unit.jobKind)) && (!owed.size || owed.has(unit.slot)));
1390
+ }).filter((unit)=>(unit.kind === 'theme' || unit.kind === 'posts' || unit.kind === 'dataset' || unit.kind === 'event' || unit.kind === 'store' || aiJobStepRunnerFor(unit.jobKind)) && (!owed.size || owed.has(unit.slot)));
1286
1391
  const outputs = (_job_outputs = job.outputs) != null ? _job_outputs : [];
1287
1392
  const ledger = ((_job_items1 = job.items) == null ? void 0 : _job_items1.length) ? job.items : aiSiteInitialLedger(units, outputs);
1288
1393
  const next = aiBuildNextUnit(aiSiteLedgerUnits(units), ledger);
@@ -1291,6 +1396,7 @@ export const runAiJobSiteStep = createAiJobSiteStep();
1291
1396
  if (unit.kind === 'theme') return AI_SITE_LOOK_BUDGET.minimumMs;
1292
1397
  if (unit.kind === 'posts') return AI_SITE_POST_BUDGET.minimumMs;
1293
1398
  if (unit.kind === 'dataset') return AI_SITE_DATASET_BUDGET.minimumMs;
1399
+ if (unit.kind === 'event') return AI_SITE_EVENT_MINIMUM_MS;
1294
1400
  // The store's pages ask no model: five draft writes (AGL-3676).
1295
1401
  if (unit.kind === 'store') return AI_SITE_STORE_PAGES_MINIMUM_MS;
1296
1402
  return aiJobStepRunMinimumMs(aiSiteUnitJob(job, unit, aiBuildBuiltRefs(aiSiteLedgerUnits(units), ledger, outputs)));