@aglyn/plugins-ai 1.0.0-beta.233 → 1.0.0-beta.235
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.
- package/package.json +17 -17
- package/src/lib/activity/ai-activity-actions.d.ts +25 -0
- package/src/lib/activity/ai-activity-actions.js +85 -4
- package/src/lib/activity/ai-activity-actions.js.map +1 -1
- package/src/lib/components/ai-brief-dialog.component.js +46 -2
- package/src/lib/components/ai-brief-dialog.component.js.map +1 -1
- package/src/lib/components/ai-campaign-create.component.js +1 -1
- package/src/lib/components/ai-campaign-create.component.js.map +1 -1
- package/src/lib/components/ai-credits-card.component.js +3 -3
- package/src/lib/components/ai-credits-card.component.js.map +1 -1
- package/src/lib/components/ai-crm-email-draft.component.js +1 -1
- package/src/lib/components/ai-crm-email-draft.component.js.map +1 -1
- package/src/lib/components/ai-crm-import-mapping.component.js +1 -1
- package/src/lib/components/ai-crm-import-mapping.component.js.map +1 -1
- package/src/lib/components/ai-crm-record-card.component.js +1 -1
- package/src/lib/components/ai-crm-record-card.component.js.map +1 -1
- package/src/lib/components/ai-describe-automation.component.js +4 -2
- package/src/lib/components/ai-describe-automation.component.js.map +1 -1
- package/src/lib/components/ai-describe-org-automation.component.js +1 -1
- package/src/lib/components/ai-describe-org-automation.component.js.map +1 -1
- package/src/lib/components/ai-experiment-cards.component.js +2 -2
- package/src/lib/components/ai-experiment-cards.component.js.map +1 -1
- package/src/lib/components/ai-explain-automation.component.js +1 -1
- package/src/lib/components/ai-explain-automation.component.js.map +1 -1
- package/src/lib/components/ai-insight-card.component.js +3 -1
- package/src/lib/components/ai-insight-card.component.js.map +1 -1
- package/src/lib/components/ai-job-links.d.ts +6 -0
- package/src/lib/components/ai-job-links.js +9 -0
- package/src/lib/components/ai-job-links.js.map +1 -1
- package/src/lib/components/ai-jobs-list-page.component.d.ts +6 -1
- package/src/lib/components/ai-jobs-list-page.component.js +15 -2
- package/src/lib/components/ai-jobs-list-page.component.js.map +1 -1
- package/src/lib/components/ai-logic.component.js +5 -3
- package/src/lib/components/ai-logic.component.js.map +1 -1
- package/src/lib/components/ai-media-create.component.js +88 -16
- package/src/lib/components/ai-media-create.component.js.map +1 -1
- package/src/lib/components/ai-model-selector.component.js +8 -0
- package/src/lib/components/ai-model-selector.component.js.map +1 -1
- package/src/lib/components/ai-overlay-cards.component.js +2 -2
- package/src/lib/components/ai-overlay-cards.component.js.map +1 -1
- package/src/lib/components/ai-product-copy-card.component.js +2 -1
- package/src/lib/components/ai-product-copy-card.component.js.map +1 -1
- package/src/lib/components/ai-products-hub-card.component.js +2 -1
- package/src/lib/components/ai-products-hub-card.component.js.map +1 -1
- package/src/lib/components/ai-revise-automation.component.js +1 -1
- package/src/lib/components/ai-revise-automation.component.js.map +1 -1
- package/src/lib/components/ai-seo-fields-card.component.js +7 -3
- package/src/lib/components/ai-seo-fields-card.component.js.map +1 -1
- package/src/lib/components/ai-site-batch-card.component.js +7 -4
- package/src/lib/components/ai-site-batch-card.component.js.map +1 -1
- package/src/lib/components/ai-site-build-page.component.js +48 -6
- package/src/lib/components/ai-site-build-page.component.js.map +1 -1
- package/src/lib/components/ai-site-seo-start-card.component.js +7 -4
- package/src/lib/components/ai-site-seo-start-card.component.js.map +1 -1
- package/src/lib/components/ai-site-start-card.component.js +152 -36
- package/src/lib/components/ai-site-start-card.component.js.map +1 -1
- package/src/lib/components/ai-theme-proposal-card.component.js +1 -0
- package/src/lib/components/ai-theme-proposal-card.component.js.map +1 -1
- package/src/lib/components/ai-upsell-dialog.component.js +17 -3
- package/src/lib/components/ai-upsell-dialog.component.js.map +1 -1
- package/src/lib/components/ai-usage-strip.component.js +13 -2
- package/src/lib/components/ai-usage-strip.component.js.map +1 -1
- package/src/lib/components/assist-build-card.component.js +20 -3
- package/src/lib/components/assist-build-card.component.js.map +1 -1
- package/src/lib/components/assist-jobs-drawer.component.js +7 -1
- package/src/lib/components/assist-jobs-drawer.component.js.map +1 -1
- package/src/lib/components/billing-ai-allotments.component.js +2 -2
- package/src/lib/components/billing-ai-allotments.component.js.map +1 -1
- package/src/lib/components/billing-ai-top-users.component.js +1 -0
- package/src/lib/components/billing-ai-top-users.component.js.map +1 -1
- package/src/lib/components/billing-assist-overage-card.component.js +2 -2
- package/src/lib/components/billing-assist-overage-card.component.js.map +1 -1
- package/src/lib/components/host-ai-allotments.component.js +2 -2
- package/src/lib/components/host-ai-allotments.component.js.map +1 -1
- package/src/lib/components/member-ai-allotment-card.component.js +2 -2
- package/src/lib/components/member-ai-allotment-card.component.js.map +1 -1
- package/src/lib/components/staff-org-ai-card.component.js +1 -0
- package/src/lib/components/staff-org-ai-card.component.js.map +1 -1
- package/src/lib/components/staff-org-ai-conversations.component.d.ts +9 -3
- package/src/lib/components/staff-org-ai-conversations.component.js +174 -83
- package/src/lib/components/staff-org-ai-conversations.component.js.map +1 -1
- package/src/lib/components/staff-user-ai-usage-card.component.js +2 -1
- package/src/lib/components/staff-user-ai-usage-card.component.js.map +1 -1
- package/src/lib/jobs/ai-job-admission.d.ts +2 -1
- package/src/lib/jobs/ai-job-admission.js.map +1 -1
- package/src/lib/jobs/ai-job-email-step.d.ts +39 -0
- package/src/lib/jobs/ai-job-email-step.js +116 -5
- package/src/lib/jobs/ai-job-email-step.js.map +1 -1
- package/src/lib/jobs/ai-job-layout-language.d.ts +3 -0
- package/src/lib/jobs/ai-job-layout-language.js +6 -1
- package/src/lib/jobs/ai-job-layout-language.js.map +1 -1
- package/src/lib/jobs/ai-job-layout-site-pages.d.ts +14 -0
- package/src/lib/jobs/ai-job-layout-site-pages.js +43 -11
- package/src/lib/jobs/ai-job-layout-site-pages.js.map +1 -1
- package/src/lib/jobs/ai-job-layout-step.js +3 -2
- package/src/lib/jobs/ai-job-layout-step.js.map +1 -1
- package/src/lib/jobs/ai-job-page-language.d.ts +26 -1
- package/src/lib/jobs/ai-job-page-language.js +75 -13
- package/src/lib/jobs/ai-job-page-language.js.map +1 -1
- package/src/lib/jobs/ai-job-page-step.d.ts +3 -0
- package/src/lib/jobs/ai-job-page-step.js +32 -7
- package/src/lib/jobs/ai-job-page-step.js.map +1 -1
- package/src/lib/jobs/ai-job-plan-step.d.ts +34 -0
- package/src/lib/jobs/ai-job-plan-step.js +106 -14
- package/src/lib/jobs/ai-job-plan-step.js.map +1 -1
- package/src/lib/jobs/ai-job-site-content.d.ts +81 -13
- package/src/lib/jobs/ai-job-site-content.js +210 -43
- package/src/lib/jobs/ai-job-site-content.js.map +1 -1
- package/src/lib/jobs/ai-job-site-step.d.ts +19 -0
- package/src/lib/jobs/ai-job-site-step.js +152 -51
- package/src/lib/jobs/ai-job-site-step.js.map +1 -1
- package/src/lib/jobs/ai-jobs.d.ts +8 -4
- package/src/lib/jobs/ai-jobs.js +19 -2
- package/src/lib/jobs/ai-jobs.js.map +1 -1
- package/src/lib/jobs/ai-layout-stock-photos.d.ts +98 -0
- package/src/lib/jobs/ai-layout-stock-photos.js +248 -0
- package/src/lib/jobs/ai-layout-stock-photos.js.map +1 -0
- package/src/lib/jobs/ai-site-publish.d.ts +11 -0
- package/src/lib/jobs/ai-site-publish.js +31 -1
- package/src/lib/jobs/ai-site-publish.js.map +1 -1
- package/src/lib/jobs/fixtures/ai-juniper-portfolio-page-recording.d.ts +151 -0
- package/src/lib/jobs/fixtures/ai-juniper-portfolio-page-recording.js +183 -0
- package/src/lib/jobs/fixtures/ai-juniper-portfolio-page-recording.js.map +1 -0
- package/src/lib/jobs/fixtures/ai-slow-roads-site-plan-recording.d.ts +27 -0
- package/src/lib/jobs/fixtures/ai-slow-roads-site-plan-recording.js +192 -0
- package/src/lib/jobs/fixtures/ai-slow-roads-site-plan-recording.js.map +1 -0
- package/src/lib/jobs/fixtures/ai-yoga-site-plan-recording.d.ts +27 -0
- package/src/lib/jobs/fixtures/ai-yoga-site-plan-recording.js +222 -0
- package/src/lib/jobs/fixtures/ai-yoga-site-plan-recording.js.map +1 -0
- package/src/lib/layout-language/ai-layout-compiler.d.ts +37 -0
- package/src/lib/layout-language/ai-layout-compiler.js +1003 -19
- package/src/lib/layout-language/ai-layout-compiler.js.map +1 -1
- package/src/lib/layout-language/ai-layout-design.d.ts +114 -0
- package/src/lib/layout-language/ai-layout-design.js +209 -0
- package/src/lib/layout-language/ai-layout-design.js.map +1 -0
- package/src/lib/layout-language/ai-layout-frame.d.ts +12 -0
- package/src/lib/layout-language/ai-layout-frame.js +33 -8
- package/src/lib/layout-language/ai-layout-frame.js.map +1 -1
- package/src/lib/layout-language/ai-layout-gaps.js +18 -2
- package/src/lib/layout-language/ai-layout-gaps.js.map +1 -1
- package/src/lib/layout-language/ai-layout-language.d.ts +2 -0
- package/src/lib/layout-language/ai-layout-language.js +15 -1
- package/src/lib/layout-language/ai-layout-language.js.map +1 -1
- package/src/lib/layout-language/ai-layout-links.d.ts +36 -0
- package/src/lib/layout-language/ai-layout-links.js +26 -2
- package/src/lib/layout-language/ai-layout-links.js.map +1 -1
- package/src/lib/layout-language/ai-layout-listings.d.ts +125 -0
- package/src/lib/layout-language/ai-layout-listings.js +187 -0
- package/src/lib/layout-language/ai-layout-listings.js.map +1 -0
- package/src/lib/layout-language/ai-layout-pictures.d.ts +11 -5
- package/src/lib/layout-language/ai-layout-pictures.js +80 -17
- package/src/lib/layout-language/ai-layout-pictures.js.map +1 -1
- package/src/lib/model/ai-job-notice.d.ts +9 -1
- package/src/lib/model/ai-job-notice.js +23 -0
- package/src/lib/model/ai-job-notice.js.map +1 -1
- package/src/lib/model/ai-plan-capabilities.d.ts +7 -0
- package/src/lib/model/ai-plan-capabilities.js.map +1 -1
- package/src/lib/model/ai-site-build-progress.d.ts +12 -2
- package/src/lib/model/ai-site-build-progress.js +104 -15
- package/src/lib/model/ai-site-build-progress.js.map +1 -1
- package/src/lib/model/ai-site-job.d.ts +236 -24
- package/src/lib/model/ai-site-job.js +269 -22
- package/src/lib/model/ai-site-job.js.map +1 -1
- package/src/lib/model/ai-site-kinds.d.ts +30 -8
- package/src/lib/model/ai-site-kinds.js +735 -116
- package/src/lib/model/ai-site-kinds.js.map +1 -1
- package/src/lib/model/ai-site-look.d.ts +21 -0
- package/src/lib/model/ai-site-look.js +63 -14
- package/src/lib/model/ai-site-look.js.map +1 -1
- package/src/lib/model/ai-site-start-seo.d.ts +30 -0
- package/src/lib/model/ai-site-start-seo.js +132 -11
- package/src/lib/model/ai-site-start-seo.js.map +1 -1
- package/src/lib/model/ai-site-start.d.ts +2 -2
- package/src/lib/model/ai-site-start.js +3 -3
- package/src/lib/model/ai-site-start.js.map +1 -1
- package/src/lib/plugin.js +15 -3
- package/src/lib/plugin.js.map +1 -1
- package/src/lib/runtime/ai-doctrine-validators.d.ts +32 -1
- package/src/lib/runtime/ai-doctrine-validators.js +227 -4
- package/src/lib/runtime/ai-doctrine-validators.js.map +1 -1
- package/src/lib/runtime/ai-doctrine.js +5 -3
- package/src/lib/runtime/ai-doctrine.js.map +1 -1
- package/src/lib/runtime/ai-palette.generated.d.ts +2 -0
- package/src/lib/runtime/ai-palette.generated.js +31 -5
- package/src/lib/runtime/ai-palette.generated.js.map +1 -1
- package/src/lib/server/ai-admin-conversations.d.ts +9 -0
- package/src/lib/server/ai-admin-conversations.js +151 -9
- package/src/lib/server/ai-admin-conversations.js.map +1 -1
- package/src/lib/server/ai-jobs-resume.js.map +1 -1
- package/src/lib/server/ai-jobs-route.js +15 -3
- package/src/lib/server/ai-jobs-route.js.map +1 -1
- package/src/lib/server/assist-edit.js +5 -2
- package/src/lib/server/assist-edit.js.map +1 -1
- package/src/lib/usage/free-ai-credits-left.d.ts +54 -0
- package/src/lib/usage/free-ai-credits-left.js +62 -0
- package/src/lib/usage/free-ai-credits-left.js.map +1 -0
- package/src/lib/usage/staff-org-ai-conversations.d.ts +23 -0
- package/src/lib/usage/staff-org-ai-conversations.js +45 -0
- package/src/lib/usage/staff-org-ai-conversations.js.map +1 -1
|
@@ -19,17 +19,19 @@ import { resolveOrgIdForHost } from "@aglyn/tenant-data-admin/server/organizatio
|
|
|
19
19
|
import { isAiPlanNewRef } from "../model/ai-build-plan.js";
|
|
20
20
|
import { aiBuildDegradation, aiBuildInitialLedger, aiBuildItemDelivered, aiBuildItemOpen, aiBuildNextUnit } from "../model/ai-build-job.js";
|
|
21
21
|
import { aiBuildBuiltRefs, aiUnitErrorRetryable, aiUnitFailure, aiUnitSpend } from "./ai-build-unit-outcome.js";
|
|
22
|
-
import { AI_SITE_EMAIL_TYPE, AI_SITE_MAX_SECTIONS, AI_SITE_PAGES, aiSiteNameSentence, aiSitePagesRefusal, aiSitePlanRefusal, aiSiteSubmissions, aiSiteWords, parseAiSiteJobInputs } from "../model/ai-site-job.js";
|
|
22
|
+
import { AI_SITE_EMAIL_TYPE, AI_SITE_MAX_SECTIONS, AI_SITE_PAGES, aiFreeSiteShortfall, aiFreeSiteShortfallText, aiSiteNameSentence, aiSitePagesRefusal, aiSitePlanRefusal, aiSiteSubmissions, aiSiteWords, parseAiSiteJobInputs, aiSiteBlogNavPage, aiSiteIsBlogStandIn, aiSitePlanWithoutBlogStandIns } from "../model/ai-site-job.js";
|
|
23
|
+
import { readFreeAiCreditsLeft } from "../usage/free-ai-credits-left.js";
|
|
23
24
|
import { AI_SITE_SEO_OUTPUT_ID, aiSiteSeoProposalForInputs } from "../model/ai-site-start-seo.js";
|
|
24
25
|
import { aiModelForStep } from "../providers/routing.js";
|
|
25
26
|
import { registerAiJobAdmission } from "./ai-job-admission.js";
|
|
26
27
|
import { aiOriginJobId, aiRecordedJobDraftId } from "./ai-job-draft-ids.js";
|
|
27
28
|
import { readAiDraftNodes } from "./ai-job-drafts.js";
|
|
28
|
-
import { AI_LAYOUT_SITE_PAGES_INPUT, aiLayoutSitePagesOfPlan } from "./ai-job-layout-site-pages.js";
|
|
29
|
+
import { AI_LAYOUT_SITE_ALIASES_INPUT, AI_LAYOUT_SITE_PAGES_INPUT, AI_LAYOUT_SITE_PAGES_MAX, aiLayoutIsHomeSlug, aiLayoutSitePagesOfPlan } from "./ai-job-layout-site-pages.js";
|
|
29
30
|
import { aiPageSectionNodeId } from "./ai-job-page-sections.js";
|
|
31
|
+
import { AI_LAYOUT_LISTINGS_INPUT } from "../layout-language/ai-layout-listings.js";
|
|
30
32
|
import { AI_LAYOUT_FORM_PAGE_INPUT, AI_LAYOUT_LANGUAGE_INPUT, aiLayoutFormPageOfPlan } from "./ai-job-page-language.js";
|
|
31
33
|
import { aiJobPublishesSite, aiPublishGuidedSite } from "./ai-site-publish.js";
|
|
32
|
-
import { AI_SITE_CONTENT_INPUT, AI_SITE_POST_BUDGET, AI_SITE_POSTS, AI_SITE_POSTS_LABEL, AI_SITE_PRODUCTS_LABEL, aiPublishSitePosts, aiSiteContentBriefLines, aiSiteContentPart, aiSiteContentRefusal, aiSiteProductsBriefLine, createAiSiteProductsRunner, runAiSitePostsUnit } from "./ai-job-site-content.js";
|
|
34
|
+
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";
|
|
33
35
|
import { dropPluginSiteCache } from "@aglyn/aglyn/plugin-manager/plugin-site-cache";
|
|
34
36
|
import { AI_SITE_LOOK_BUDGET, aiRunSiteLook } from "./ai-job-site-look.js";
|
|
35
37
|
import { aiConfirmedPlan, aiUnspentOutcome } from "./ai-job-generation.js";
|
|
@@ -429,39 +431,79 @@ export const AI_SITE_NO_PLAN_COPY = 'This site job has no confirmed plan to buil
|
|
|
429
431
|
// ids are minted on the plan, and the platform writes the header's links.
|
|
430
432
|
// A page is told them too, so its buttons may go to a page built after it.
|
|
431
433
|
if (job.kind === 'site' && (unit.kind === 'layout' || unit.kind === 'page')) {
|
|
432
|
-
|
|
433
|
-
|
|
434
|
+
var _job_outputs1;
|
|
435
|
+
// A guided start links every page the person asked for (AGL-3660), and
|
|
436
|
+
// the blog its first posts are written into, by its path, second after
|
|
437
|
+
// Home (AGL-3676): the live Slow Roads start linked an "Articles" page
|
|
438
|
+
// and never the blog.
|
|
439
|
+
// A planned page standing in for that blog — "Articles", "Journal" — is
|
|
440
|
+
// merged into it (AGL-3676): not linked, not built, and every link to it
|
|
441
|
+
// goes to the blog, under words that name the blog.
|
|
442
|
+
const writesPosts = aiSiteWritesPosts(job);
|
|
443
|
+
const merged = writesPosts ? aiSitePlanWithoutBlogStandIns(plan.screens) : {
|
|
444
|
+
screens: plan.screens,
|
|
445
|
+
standIns: []
|
|
446
|
+
};
|
|
447
|
+
const planned = aiLayoutSitePagesOfPlan(merged.screens, {
|
|
434
448
|
guided: true
|
|
435
449
|
});
|
|
450
|
+
const blogPage = aiSiteBlogNavPage(merged.screens);
|
|
451
|
+
const blog = writesPosts ? [
|
|
452
|
+
blogPage
|
|
453
|
+
] : [];
|
|
454
|
+
const homes = planned.filter((page)=>aiLayoutIsHomeSlug(page.slug));
|
|
455
|
+
const pages = [
|
|
456
|
+
...homes,
|
|
457
|
+
...blog,
|
|
458
|
+
...planned.filter((page)=>!aiLayoutIsHomeSlug(page.slug))
|
|
459
|
+
].slice(0, AI_LAYOUT_SITE_PAGES_MAX);
|
|
436
460
|
if (pages.length) unitInputs[AI_LAYOUT_SITE_PAGES_INPUT] = pages;
|
|
461
|
+
const aliases = merged.standIns.filter((screen)=>typeof screen.id === 'string' && !!screen.id).map((screen)=>({
|
|
462
|
+
id: screen.id,
|
|
463
|
+
label: blogPage.label,
|
|
464
|
+
slug: blogPage.slug,
|
|
465
|
+
href: blogPage.href,
|
|
466
|
+
standsInFor: screen.title
|
|
467
|
+
}));
|
|
468
|
+
if (aliases.length) unitInputs[AI_LAYOUT_SITE_ALIASES_INPUT] = aliases;
|
|
469
|
+
// The store's catalog and the blog, listed by the sections that show them,
|
|
470
|
+
// and the cart in a selling site's header (AGL-3676).
|
|
471
|
+
const listings = aiSiteListings({
|
|
472
|
+
outputs: (_job_outputs1 = job.outputs) != null ? _job_outputs1 : [],
|
|
473
|
+
screens: merged.screens,
|
|
474
|
+
sells: aiSiteSellsProducts(job)
|
|
475
|
+
});
|
|
476
|
+
if (listings.length) unitInputs[AI_LAYOUT_LISTINGS_INPUT] = listings;
|
|
437
477
|
}
|
|
438
478
|
// A site's pages and its layout are designed in the layout language and
|
|
439
479
|
// compiled (AGL-3660), and a page is told which page places the site's form.
|
|
440
480
|
if (unit.kind === 'layout' || unit.kind === 'page') {
|
|
441
|
-
var
|
|
481
|
+
var _job_outputs2;
|
|
442
482
|
var _look_proposal;
|
|
443
483
|
// The look designed first (AGL-3660): its header arrangement and band rhythm.
|
|
444
|
-
const look = ((
|
|
484
|
+
const look = ((_job_outputs2 = job.outputs) != null ? _job_outputs2 : []).find((output)=>output.resource === 'theme' && output.id === 'look');
|
|
445
485
|
const style = look == null ? void 0 : (_look_proposal = look.proposal) == null ? void 0 : _look_proposal['style'];
|
|
446
486
|
if (style) unitInputs['siteStyle'] = {
|
|
447
487
|
headerAlign: style['headerAlign'],
|
|
448
|
-
rhythm: style['rhythm']
|
|
488
|
+
rhythm: style['rhythm'],
|
|
489
|
+
seed: style['seed']
|
|
449
490
|
};
|
|
450
491
|
unitInputs[AI_LAYOUT_LANGUAGE_INPUT] = true;
|
|
451
492
|
const formPage = aiLayoutFormPageOfPlan(plan);
|
|
452
493
|
if (formPage) unitInputs[AI_LAYOUT_FORM_PAGE_INPUT] = formPage;
|
|
453
494
|
}
|
|
454
495
|
if (unit.kind === 'posts') {
|
|
455
|
-
var
|
|
496
|
+
var _job_outputs3, _inputs_businessName;
|
|
456
497
|
// The posts already written (one a pass), the addresses the site's own
|
|
457
498
|
// pages answer at, and the byline the person gave (AGL-3676).
|
|
458
499
|
const posts = {
|
|
459
|
-
written: ((
|
|
500
|
+
written: ((_job_outputs3 = job.outputs) != null ? _job_outputs3 : []).filter((output)=>output.resource === 'entry').map((output)=>({
|
|
460
501
|
id: output.id,
|
|
461
502
|
title: output.label
|
|
462
503
|
})),
|
|
463
504
|
total: AI_SITE_POSTS,
|
|
464
|
-
|
|
505
|
+
// A page standing in for the blog is merged into it, so its address is the blog's to take.
|
|
506
|
+
avoidSlugs: aiSitePlanWithoutBlogStandIns(plan.screens).screens.map((screen)=>screen.slug.replace(/^\/+/, '').split('/')[0]).filter(Boolean),
|
|
465
507
|
byline: typeof inputs === 'string' ? '' : (_inputs_businessName = inputs.businessName) != null ? _inputs_businessName : ''
|
|
466
508
|
};
|
|
467
509
|
unitInputs[AI_SITE_CONTENT_INPUT] = posts;
|
|
@@ -484,52 +526,93 @@ export const AI_SITE_NO_PLAN_COPY = 'This site job has no confirmed plan to buil
|
|
|
484
526
|
brief: brief.join('\n').slice(0, AI_JOB_BRIEF_MAX_CHARS)
|
|
485
527
|
});
|
|
486
528
|
}
|
|
529
|
+
/**
|
|
530
|
+
* Whether this site start writes its first posts (AGL-3676): its ledger owes
|
|
531
|
+
* the posts part and has not given up on it. The ledger is written before the
|
|
532
|
+
* layout is built, so the header knows the blog before it exists.
|
|
533
|
+
*/ export function aiSiteWritesPosts(job) {
|
|
534
|
+
var _job_items;
|
|
535
|
+
return ((_job_items = job.items) != null ? _job_items : []).some((row)=>row.slot === 'posts' && row.status !== 'skipped' && row.status !== 'failed');
|
|
536
|
+
}
|
|
537
|
+
/** What the row of a planned page merged into the blog says (AGL-3676). */ export const AI_SITE_BLOG_MERGED_NOTE = 'Your blog takes this page’s place: its posts are listed there, and its links go to it.';
|
|
538
|
+
/**
|
|
539
|
+
* Whether this site start sells (AGL-3676): its ledger owes the store's first
|
|
540
|
+
* products and has not given up on them, so the layout built before them
|
|
541
|
+
* carries the cart.
|
|
542
|
+
*/ export function aiSiteSellsProducts(job) {
|
|
543
|
+
var _job_items;
|
|
544
|
+
return ((_job_items = job.items) != null ? _job_items : []).some((row)=>row.slot === 'products' && row.status !== 'skipped' && row.status !== 'failed');
|
|
545
|
+
}
|
|
487
546
|
/**
|
|
488
547
|
* A scaffold is admitted with inputs that read, for a site of the job's own
|
|
489
548
|
* org, and only where this deployment has loaded the step that builds a page:
|
|
490
549
|
* a scaffold whose pages nothing can build is not a scaffold.
|
|
491
|
-
*/ export
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
// taste, four to eight on a paid plan.
|
|
499
|
-
const freeTaste = aiSiteFreeTaste(context.org);
|
|
500
|
-
const pages = aiSitePagesRefusal(inputs.pages, freeTaste);
|
|
501
|
-
if (pages) return {
|
|
502
|
-
status: 400,
|
|
503
|
-
error: pages
|
|
504
|
-
};
|
|
505
|
-
if (context.plan) {
|
|
506
|
-
const shape = aiSitePlanRefusal(context.plan, {
|
|
507
|
-
freeTaste
|
|
508
|
-
});
|
|
509
|
-
if (shape) return {
|
|
550
|
+
*/ export function createAiSiteJobAdmission(deps = {}) {
|
|
551
|
+
var _deps_freeCreditsLeft, _deps_now;
|
|
552
|
+
const freeCreditsLeft = (_deps_freeCreditsLeft = deps.freeCreditsLeft) != null ? _deps_freeCreditsLeft : readFreeAiCreditsLeft;
|
|
553
|
+
const now = (_deps_now = deps.now) != null ? _deps_now : ()=>new Date();
|
|
554
|
+
return async (context)=>{
|
|
555
|
+
const inputs = parseAiSiteJobInputs(context.inputs);
|
|
556
|
+
if (typeof inputs === 'string') return {
|
|
510
557
|
status: 400,
|
|
511
|
-
error:
|
|
558
|
+
error: inputs
|
|
512
559
|
};
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
560
|
+
// The workspace's own page band (AGL-3594): one or two pages on the Free
|
|
561
|
+
// taste, four to eight on a paid plan.
|
|
562
|
+
const freeTaste = aiSiteFreeTaste(context.org);
|
|
563
|
+
const pages = aiSitePagesRefusal(inputs.pages, freeTaste);
|
|
564
|
+
if (pages) return {
|
|
516
565
|
status: 400,
|
|
517
|
-
error:
|
|
566
|
+
error: pages
|
|
518
567
|
};
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
568
|
+
// A Free start that what is left of the month's Free credits cannot pay for
|
|
569
|
+
// is refused before it spends (AGL-3660), on the figure the dialog quotes —
|
|
570
|
+
// the dialog asks the same, and this is what a stale dialog meets. Only at
|
|
571
|
+
// creation: a resume is the same job carrying on from where it paused.
|
|
572
|
+
if (freeTaste && !context.plan) {
|
|
573
|
+
const credits = await freeCreditsLeft(context.firestore, {
|
|
574
|
+
orgId: context.orgId,
|
|
575
|
+
org: context.org,
|
|
576
|
+
now: now()
|
|
577
|
+
});
|
|
578
|
+
const shortfall = aiFreeSiteShortfall(credits, inputs.pages);
|
|
579
|
+
if (credits && shortfall) {
|
|
580
|
+
return {
|
|
581
|
+
status: 429,
|
|
582
|
+
error: aiFreeSiteShortfallText(shortfall, credits.resetsOn)
|
|
583
|
+
};
|
|
584
|
+
}
|
|
585
|
+
}
|
|
586
|
+
if (context.plan) {
|
|
587
|
+
const shape = aiSitePlanRefusal(context.plan, {
|
|
588
|
+
freeTaste
|
|
589
|
+
});
|
|
590
|
+
if (shape) return {
|
|
591
|
+
status: 400,
|
|
592
|
+
error: shape
|
|
593
|
+
};
|
|
594
|
+
}
|
|
595
|
+
if (!context.hostId) {
|
|
596
|
+
return {
|
|
597
|
+
status: 400,
|
|
598
|
+
error: 'Open the site the scaffold is for before starting the job'
|
|
599
|
+
};
|
|
600
|
+
}
|
|
601
|
+
const owner = await resolveOrgIdForHost(context.hostId);
|
|
602
|
+
if (!owner || owner !== context.orgId) return {
|
|
603
|
+
status: 404,
|
|
604
|
+
error: 'Unknown site'
|
|
529
605
|
};
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
606
|
+
if (!aiJobStepRunnerFor('page')) {
|
|
607
|
+
return {
|
|
608
|
+
status: 400,
|
|
609
|
+
error: AI_SITE_NO_PAGE_STEP_COPY
|
|
610
|
+
};
|
|
611
|
+
}
|
|
612
|
+
return null;
|
|
613
|
+
};
|
|
614
|
+
}
|
|
615
|
+
export const aiSiteJobAdmission = createAiSiteJobAdmission();
|
|
533
616
|
/** Whether a scaffold's workspace spends the Free taste (AGL-3594); a missing org reads as paid, as the band has always been. */ export function aiSiteFreeTaste(org) {
|
|
534
617
|
return Boolean(org) && resolveEffectivePlan(org) === 'free';
|
|
535
618
|
}
|
|
@@ -709,12 +792,18 @@ export function createAiJobSiteStep(deps = {}) {
|
|
|
709
792
|
]));
|
|
710
793
|
const next = aiBuildNextUnit(ledgerUnits, ledger);
|
|
711
794
|
/** A guided start's last pass puts what it built on the site, once (AGL-3596): only its pages that were built. */ const finish = async (outcome, pages)=>{
|
|
795
|
+
var _postsRow_outputs;
|
|
712
796
|
if (!aiJobPublishesSite(job) || job.sitePublish || !job.hostId || !pages.length) return outcome;
|
|
713
|
-
|
|
797
|
+
// A blog the header links by path before its posts exist (AGL-3660):
|
|
798
|
+
// owed and not delivered, its links come out of what is published.
|
|
799
|
+
const postsRow = rows.get('posts');
|
|
800
|
+
const sitePublish = await publish(context.firestore, _extends({
|
|
714
801
|
job,
|
|
715
802
|
outputs: pages,
|
|
716
803
|
now: context.now
|
|
717
|
-
}
|
|
804
|
+
}, postsRow ? {
|
|
805
|
+
blogUnwritten: !aiBuildItemDelivered(postsRow) || !((_postsRow_outputs = postsRow.outputs) == null ? void 0 : _postsRow_outputs.length)
|
|
806
|
+
} : {})).catch((error)=>{
|
|
718
807
|
// The site is built either way; the pages stay drafts and say so.
|
|
719
808
|
console.error('ai site publish threw', {
|
|
720
809
|
orgId: job.orgId,
|
|
@@ -807,6 +896,16 @@ export function createAiJobSiteStep(deps = {}) {
|
|
|
807
896
|
// A blog's posts and a store's products ask, before their first pass,
|
|
808
897
|
// whether this member may have them here (AGL-3676): a refusal spends
|
|
809
898
|
// nothing, and the row says why, as a build's item does.
|
|
899
|
+
// A planned page standing in for the blog this start writes is merged into
|
|
900
|
+
// it (AGL-3676): not built, its address the blog's, its links the blog's.
|
|
901
|
+
// The plan step asks for a plan without one only once.
|
|
902
|
+
if (unit.kind === 'page' && unit.screen && aiSiteIsBlogStandIn(unit.screen) && aiSiteWritesPosts(job)) {
|
|
903
|
+
return closing(settle({
|
|
904
|
+
slot: unit.slot,
|
|
905
|
+
status: 'skipped',
|
|
906
|
+
note: AI_SITE_BLOG_MERGED_NOTE
|
|
907
|
+
}));
|
|
908
|
+
}
|
|
810
909
|
if ((unit.kind === 'posts' || unit.kind === 'products') && ((_rows_get = rows.get(unit.slot)) == null ? void 0 : _rows_get.status) !== 'running') {
|
|
811
910
|
const refusal = await contentRefusal(unit.kind, _extends({}, context, {
|
|
812
911
|
job
|
|
@@ -900,7 +999,9 @@ export function createAiJobSiteStep(deps = {}) {
|
|
|
900
999
|
slot: unit.slot,
|
|
901
1000
|
status: degraded ? 'degraded' : 'succeeded',
|
|
902
1001
|
outputs: outcome.outputs.map((output)=>output.id),
|
|
903
|
-
|
|
1002
|
+
// A store's products are listed before they are priced (AGL-3676):
|
|
1003
|
+
// the row says what is left before the store sells.
|
|
1004
|
+
note: unit.kind === 'products' && outcome.outputs.length ? AI_SITE_PRODUCTS_PRICE_NOTE : note
|
|
904
1005
|
}, degraded ? {
|
|
905
1006
|
degradedBy: degradation.degradedBy
|
|
906
1007
|
} : {}), spent);
|