@aglyn/plugins-ai 1.0.0-beta.285 → 1.0.0-beta.287
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/assets/site-styles/nonprofit.webp +0 -0
- package/src/lib/assets/site-styles/professional.webp +0 -0
- package/src/lib/assets/site-styles/store.webp +0 -0
- package/src/lib/assets/site-styles/trades.webp +0 -0
- package/src/lib/components/ai-theme-proposal-card.component.js +12 -3
- package/src/lib/components/ai-theme-proposal-card.component.js.map +1 -1
- package/src/lib/declarations.js +5 -2
- package/src/lib/declarations.js.map +1 -1
- package/src/lib/declarations.server.js +12 -0
- package/src/lib/declarations.server.js.map +1 -1
- package/src/lib/jobs/ai-build-capabilities.d.ts +3 -1
- package/src/lib/jobs/ai-build-capabilities.js +27 -2
- package/src/lib/jobs/ai-build-capabilities.js.map +1 -1
- package/src/lib/jobs/ai-image-reads.d.ts +59 -0
- package/src/lib/jobs/ai-image-reads.js +138 -0
- package/src/lib/jobs/ai-image-reads.js.map +1 -0
- package/src/lib/jobs/ai-job-build-step.d.ts +29 -0
- package/src/lib/jobs/ai-job-build-step.js +83 -12
- package/src/lib/jobs/ai-job-build-step.js.map +1 -1
- package/src/lib/jobs/ai-job-duplicate-step.d.ts +2 -1
- package/src/lib/jobs/ai-job-duplicate-step.js +6 -6
- package/src/lib/jobs/ai-job-duplicate-step.js.map +1 -1
- package/src/lib/jobs/ai-job-import-step.d.ts +4 -2
- package/src/lib/jobs/ai-job-import-step.js +15 -11
- package/src/lib/jobs/ai-job-import-step.js.map +1 -1
- package/src/lib/jobs/ai-job-insight-step.d.ts +10 -0
- package/src/lib/jobs/ai-job-insight-step.js +23 -5
- package/src/lib/jobs/ai-job-insight-step.js.map +1 -1
- package/src/lib/jobs/ai-job-layout-language.js +2 -1
- package/src/lib/jobs/ai-job-layout-language.js.map +1 -1
- package/src/lib/jobs/ai-job-media-step.d.ts +2 -1
- package/src/lib/jobs/ai-job-media-step.js +6 -8
- package/src/lib/jobs/ai-job-media-step.js.map +1 -1
- package/src/lib/jobs/ai-job-navigation-step.d.ts +2 -1
- package/src/lib/jobs/ai-job-navigation-step.js +7 -9
- package/src/lib/jobs/ai-job-navigation-step.js.map +1 -1
- package/src/lib/jobs/ai-job-page-language.js +7 -1
- package/src/lib/jobs/ai-job-page-language.js.map +1 -1
- package/src/lib/jobs/ai-job-page-sections.js +16 -3
- package/src/lib/jobs/ai-job-page-sections.js.map +1 -1
- package/src/lib/jobs/ai-job-page-step.js +9 -1
- package/src/lib/jobs/ai-job-page-step.js.map +1 -1
- package/src/lib/jobs/ai-job-plan-step.d.ts +30 -8
- package/src/lib/jobs/ai-job-plan-step.js +78 -13
- package/src/lib/jobs/ai-job-plan-step.js.map +1 -1
- package/src/lib/jobs/ai-job-privacy-step.d.ts +4 -2
- package/src/lib/jobs/ai-job-privacy-step.js +14 -15
- package/src/lib/jobs/ai-job-privacy-step.js.map +1 -1
- package/src/lib/jobs/ai-job-products-step.js +5 -3
- package/src/lib/jobs/ai-job-products-step.js.map +1 -1
- package/src/lib/jobs/ai-job-settings-step.d.ts +2 -1
- package/src/lib/jobs/ai-job-settings-step.js +7 -8
- package/src/lib/jobs/ai-job-settings-step.js.map +1 -1
- package/src/lib/jobs/ai-job-site-content.d.ts +34 -1
- package/src/lib/jobs/ai-job-site-content.js +67 -8
- package/src/lib/jobs/ai-job-site-content.js.map +1 -1
- package/src/lib/jobs/ai-job-site-datasets.d.ts +53 -3
- package/src/lib/jobs/ai-job-site-datasets.js +298 -30
- package/src/lib/jobs/ai-job-site-datasets.js.map +1 -1
- package/src/lib/jobs/ai-job-site-step.js +6 -3
- package/src/lib/jobs/ai-job-site-step.js.map +1 -1
- package/src/lib/jobs/ai-job-site-store-pages.js +3 -3
- package/src/lib/jobs/ai-job-site-store-pages.js.map +1 -1
- package/src/lib/jobs/ai-job-tracking-step.d.ts +2 -1
- package/src/lib/jobs/ai-job-tracking-step.js +7 -8
- package/src/lib/jobs/ai-job-tracking-step.js.map +1 -1
- package/src/lib/jobs/ai-jobs-beat.d.ts +11 -7
- package/src/lib/jobs/ai-jobs-beat.js +18 -8
- package/src/lib/jobs/ai-jobs-beat.js.map +1 -1
- package/src/lib/jobs/ai-jobs-notify.d.ts +66 -1
- package/src/lib/jobs/ai-jobs-notify.js +136 -3
- package/src/lib/jobs/ai-jobs-notify.js.map +1 -1
- package/src/lib/jobs/ai-layout-stock-photos.d.ts +59 -4
- package/src/lib/jobs/ai-layout-stock-photos.js +897 -81
- package/src/lib/jobs/ai-layout-stock-photos.js.map +1 -1
- package/src/lib/jobs/ai-product-image.d.ts +14 -0
- package/src/lib/jobs/ai-product-image.js +73 -21
- package/src/lib/jobs/ai-product-image.js.map +1 -1
- package/src/lib/jobs/ai-theme-brand-inputs.d.ts +9 -1
- package/src/lib/jobs/ai-theme-brand-inputs.js +28 -2
- package/src/lib/jobs/ai-theme-brand-inputs.js.map +1 -1
- package/src/lib/jobs/fixtures/ai-site-agl4065-datasets.d.ts +175 -0
- package/src/lib/jobs/fixtures/ai-site-agl4065-datasets.js +601 -0
- package/src/lib/jobs/fixtures/ai-site-agl4065-datasets.js.map +1 -0
- package/src/lib/jobs/fixtures/ai-site-agl4065-pages.d.ts +46 -0
- package/src/lib/jobs/fixtures/ai-site-agl4065-pages.js +2862 -0
- package/src/lib/jobs/fixtures/ai-site-agl4065-pages.js.map +1 -0
- package/src/lib/jobs/fixtures/ai-site-agl4065-plans.d.ts +74 -0
- package/src/lib/jobs/fixtures/ai-site-agl4065-plans.js +888 -0
- package/src/lib/jobs/fixtures/ai-site-agl4065-plans.js.map +1 -0
- package/src/lib/jobs/fixtures/ai-stock-photo-agl4065-judge.d.ts +29 -0
- package/src/lib/jobs/fixtures/ai-stock-photo-agl4065-judge.js +81 -0
- package/src/lib/jobs/fixtures/ai-stock-photo-agl4065-judge.js.map +1 -0
- package/src/lib/jobs/fixtures/ai-stock-photo-agl4065-recordings.d.ts +87 -0
- package/src/lib/jobs/fixtures/ai-stock-photo-agl4065-recordings.js +225 -0
- package/src/lib/jobs/fixtures/ai-stock-photo-agl4065-recordings.js.map +1 -0
- package/src/lib/layout-language/ai-layout-compiler.d.ts +11 -0
- package/src/lib/layout-language/ai-layout-compiler.js +194 -18
- package/src/lib/layout-language/ai-layout-compiler.js.map +1 -1
- package/src/lib/layout-language/ai-layout-copy.d.ts +37 -0
- package/src/lib/layout-language/ai-layout-copy.js +383 -3
- package/src/lib/layout-language/ai-layout-copy.js.map +1 -1
- package/src/lib/layout-language/ai-layout-design.d.ts +19 -0
- package/src/lib/layout-language/ai-layout-design.js +31 -11
- package/src/lib/layout-language/ai-layout-design.js.map +1 -1
- package/src/lib/layout-language/ai-layout-listings.d.ts +7 -1
- package/src/lib/layout-language/ai-layout-listings.js +9 -1
- package/src/lib/layout-language/ai-layout-listings.js.map +1 -1
- package/src/lib/layout-language/ai-layout-pictures.d.ts +30 -0
- package/src/lib/layout-language/ai-layout-pictures.js +131 -3
- package/src/lib/layout-language/ai-layout-pictures.js.map +1 -1
- package/src/lib/layout-language/ai-layout-storefront.d.ts +18 -4
- package/src/lib/layout-language/ai-layout-storefront.js +100 -20
- package/src/lib/layout-language/ai-layout-storefront.js.map +1 -1
- package/src/lib/model/ai-build-job.d.ts +7 -0
- package/src/lib/model/ai-build-job.js +36 -7
- package/src/lib/model/ai-build-job.js.map +1 -1
- package/src/lib/model/ai-build-plan.d.ts +28 -4
- package/src/lib/model/ai-build-plan.js +49 -9
- package/src/lib/model/ai-build-plan.js.map +1 -1
- package/src/lib/model/ai-build-progress.js +3 -1
- package/src/lib/model/ai-build-progress.js.map +1 -1
- package/src/lib/model/ai-job-notice.d.ts +8 -0
- package/src/lib/model/ai-job-notice.js +33 -0
- package/src/lib/model/ai-job-notice.js.map +1 -1
- package/src/lib/model/ai-job-plan-lines.d.ts +2 -1
- package/src/lib/model/ai-job-plan-lines.js +6 -1
- package/src/lib/model/ai-job-plan-lines.js.map +1 -1
- package/src/lib/model/ai-jobs.types.d.ts +8 -0
- package/src/lib/model/ai-jobs.types.js.map +1 -1
- package/src/lib/model/ai-permissions.d.ts +13 -0
- package/src/lib/model/ai-permissions.js +29 -1
- package/src/lib/model/ai-permissions.js.map +1 -1
- package/src/lib/model/ai-products.d.ts +18 -0
- package/src/lib/model/ai-products.js +32 -0
- package/src/lib/model/ai-products.js.map +1 -1
- package/src/lib/model/ai-site-inspiration.d.ts +3 -2
- package/src/lib/model/ai-site-inspiration.js +3 -2
- package/src/lib/model/ai-site-inspiration.js.map +1 -1
- package/src/lib/plugin.js +4 -13
- package/src/lib/plugin.js.map +1 -1
- package/src/lib/providers/anthropic.js +9 -2
- package/src/lib/providers/anthropic.js.map +1 -1
- package/src/lib/providers/catalog.js +14 -5
- package/src/lib/providers/catalog.js.map +1 -1
- package/src/lib/providers/contract.d.ts +24 -1
- package/src/lib/providers/contract.js.map +1 -1
- package/src/lib/providers/routing.js +5 -2
- package/src/lib/providers/routing.js.map +1 -1
- package/src/lib/runtime/ai-dataset-generation.d.ts +99 -1
- package/src/lib/runtime/ai-dataset-generation.js +251 -3
- package/src/lib/runtime/ai-dataset-generation.js.map +1 -1
- package/src/lib/runtime/ai-dev-replay.d.ts +1 -0
- package/src/lib/runtime/ai-dev-replay.js +4 -2
- package/src/lib/runtime/ai-dev-replay.js.map +1 -1
- package/src/lib/runtime/ai-doctrine-validators.d.ts +47 -3
- package/src/lib/runtime/ai-doctrine-validators.js +343 -27
- package/src/lib/runtime/ai-doctrine-validators.js.map +1 -1
- package/src/lib/runtime/ai-doctrine.js +8 -2
- package/src/lib/runtime/ai-doctrine.js.map +1 -1
- package/src/lib/runtime/ai-icon-library.d.ts +27 -1
- package/src/lib/runtime/ai-icon-library.js +30 -3
- package/src/lib/runtime/ai-icon-library.js.map +1 -1
- package/src/lib/runtime/ai-products-generation.d.ts +11 -1
- package/src/lib/runtime/ai-products-generation.js +51 -4
- package/src/lib/runtime/ai-products-generation.js.map +1 -1
- package/src/lib/runtime/assist-answer-cache.d.ts +2 -0
- package/src/lib/runtime/assist-answer-cache.js +5 -2
- package/src/lib/runtime/assist-answer-cache.js.map +1 -1
- package/src/lib/server/ai-allotments.js +7 -2
- package/src/lib/server/ai-allotments.js.map +1 -1
- package/src/lib/server/ai-experiment-versions.js +5 -5
- package/src/lib/server/ai-experiment-versions.js.map +1 -1
- package/src/lib/server/ai-host-permissions-roster.d.ts +25 -0
- package/src/lib/server/ai-host-permissions-roster.js +33 -0
- package/src/lib/server/ai-host-permissions-roster.js.map +1 -0
- package/src/lib/server/ai-host-permissions.js +8 -6
- package/src/lib/server/ai-host-permissions.js.map +1 -1
- package/src/lib/server/ai-image-reads-route.d.ts +17 -0
- package/src/lib/server/ai-image-reads-route.js +106 -0
- package/src/lib/server/ai-image-reads-route.js.map +1 -0
- package/src/lib/server/ai-seo-apply.js +5 -5
- package/src/lib/server/ai-seo-apply.js.map +1 -1
- package/src/lib/server/ai-site-import-route.js +7 -4
- package/src/lib/server/ai-site-import-route.js.map +1 -1
- package/src/lib/server/assist-build.js +1 -0
- package/src/lib/server/assist-build.js.map +1 -1
- package/src/lib/server/assist-chat.d.ts +11 -7
- package/src/lib/server/assist-chat.js +185 -48
- package/src/lib/server/assist-chat.js.map +1 -1
- package/src/lib/server/assist-docs-query.d.ts +51 -0
- package/src/lib/server/assist-docs-query.js +57 -0
- package/src/lib/server/assist-docs-query.js.map +1 -0
- package/src/lib/server/assist-jobs-context.d.ts +102 -0
- package/src/lib/server/assist-jobs-context.js +227 -0
- package/src/lib/server/assist-jobs-context.js.map +1 -0
- package/src/lib/server/assist-view-context.d.ts +8 -4
- package/src/lib/server/assist-view-context.js +12 -7
- package/src/lib/server/assist-view-context.js.map +1 -1
- package/src/lib/server.js +12 -0
- package/src/lib/server.js.map +1 -1
- package/src/lib/tools/ai-dataset-tool.d.ts +11 -1
- package/src/lib/tools/ai-dataset-tool.js +24 -7
- package/src/lib/tools/ai-dataset-tool.js.map +1 -1
- package/src/lib/tools/ai-duplicate-resource-tool.js +5 -6
- package/src/lib/tools/ai-duplicate-resource-tool.js.map +1 -1
- package/src/lib/components/ai-collaborator-permissions-column.component.d.ts +0 -32
- package/src/lib/components/ai-collaborator-permissions-column.component.js +0 -132
- package/src/lib/components/ai-collaborator-permissions-column.component.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../../../../libs/plugins/ai/src/lib/model/ai-products.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 { AiJobOutput, AiJobSummary } from './ai-jobs.types'\nimport { AI_PRODUCTS_BULK_MAX, aiProductsBulkBrief, aiProductsBulkInputs } from './ai-products-bulk'\n\nexport { AI_PRODUCTS_BULK_MAX, aiProductsBulkBrief }\n\n/**\n * COMMERCE BY AI (AGL-2916): what a `products` job is asked, and what it\n * proposes. Pure, so the step that asks, the console cards that start a job\n * and show its proposals, and the eval harness all read one shape.\n *\n * `inputs.target` names the work:\n *\n * - `product` — one product's copy, from what its editor holds right now:\n * the name, the text, the tags, the categories and options it has, and the\n * first photo. The editor may hold a product nobody has saved yet, so the\n * job never reads a product document for this target.\n * - `bulk` — the copy of up to `AI_PRODUCTS_BULK_MAX` saved products, one\n * product a pass, each read from the catalog as it is reached.\n * - `catalog` — a store's first products from the brief: names, copy, tags\n * and options, what each photo should show, and a suggested price by what\n * the product is (`aiCatalogPrice`, Zach 2026-10-12). No picture.\n * - `categories` — store categories and a first set of discounts from the brief.\n *\n * Every output is a PROPOSAL (`resource: 'product'`, with `proposal`), and the\n * job writes nothing. The commerce plugin's own surfaces write what a person\n * accepts, through the doors those surfaces already use.\n */\n\nexport const AI_PRODUCTS_TARGETS = ['product', 'bulk', 'catalog', 'categories'] as const\nexport type AiProductsTarget = (typeof AI_PRODUCTS_TARGETS)[number]\n\nexport const AI_PRODUCT_TYPES = ['physical', 'digital', 'service'] as const\nexport type AiProductType = (typeof AI_PRODUCT_TYPES)[number]\n\n/** The longest product name the editor saves. */\nexport const AI_PRODUCT_NAME_MAX_CHARS = 120\n\n/** How much of a product's existing description a request carries. */\nexport const AI_PRODUCT_TEXT_MAX_CHARS = 2_000\n\n/** The longest description the job proposes. */\nexport const AI_PRODUCT_DESCRIPTION_MAX_CHARS = 1_200\n\nexport const AI_PRODUCT_TAGS_MAX = 8\nexport const AI_PRODUCT_TAG_MAX_CHARS = 30\n\n/** The most categories one product's proposal names. */\nexport const AI_PRODUCT_CATEGORIES_MAX = 3\n\n/** The most of a site's categories a request lists to choose from. */\nexport const AI_PRODUCT_CATEGORY_LIST_MAX = 100\n\n/** A product's option axes, as the commerce editor bounds them. */\nexport const AI_PRODUCT_OPTIONS_MAX = 3\nexport const AI_PRODUCT_OPTION_VALUES_MAX = 25\nexport const AI_PRODUCT_OPTION_NAME_MAX_CHARS = 30\n\n/** How many products a catalog proposal holds. */\nexport const AI_CATALOG_PRODUCTS = { min: 1, max: 12 } as const\n\n/**\n * A proposed product is shorter than a written one: its description and tags\n * are a start the owner completes, and twelve of them at every bound still fit\n * one answer (`ai-job-products-step.spec.ts` measures it).\n */\nexport const AI_CATALOG_DESCRIPTION_MAX_CHARS = 600\nexport const AI_CATALOG_TAGS_MAX = 6\n\n/** A proposed product's options: few axes and few short values, so its variants stay a short list. */\nexport const AI_CATALOG_OPTIONS_MAX = 2\nexport const AI_CATALOG_OPTION_VALUES_MAX = 6\nexport const AI_CATALOG_OPTION_VALUE_MAX_CHARS = 30\n\n/** What a proposed product's photo should show, in one sentence. */\nexport const AI_CATALOG_PHOTO_MAX_CHARS = 160\n\n/**\n * A proposed product's suggested price, in US dollars — the one currency a\n * catalog prices in (`priceUsd`) — and the range code keeps it to (Zach,\n * 2026-10-12): a store's first products priced by what each one is (a bar\n * of handmade soap about $8–12, a candle $18–32, a gift set $30–45) instead\n * of every one at the commerce default. Never $0 or less, nothing past what\n * a small shop's first product plausibly lists at; a price outside the range,\n * or none, is no price, and the writer gives the product its default price.\n * Below the commerce ceiling (`COMMERCE_MAX_PRICE_USD`, $10,000) by design.\n */\nexport const AI_CATALOG_PRICE_USD = { min: 1, max: 5_000 } as const\n\n/**\n * A proposed price as code keeps it: a finite number of dollars (or a plain\n * \"$12.50\" a model wrote as text) inside `AI_CATALOG_PRICE_USD`, rounded to\n * whole cents; anything else — missing, zero, negative, absurd, not a number\n * — is `null`, so the product takes the store's default price for the owner\n * to change. The model is never re-asked for a price: a bad one costs the\n * product only its suggestion.\n */\nexport function aiCatalogPrice(raw: unknown): number | null {\n let value: number | null = null\n if (typeof raw === 'number') value = raw\n else if (typeof raw === 'string') {\n const match = /^\\s*(?:US\\s*)?\\$?\\s*(\\d{1,6}(?:\\.\\d{1,2})?)\\s*(?:USD)?\\s*$/i.exec(raw)\n value = match ? Number(match[1]) : null\n }\n if (value === null || !Number.isFinite(value)) return null\n const cents = Math.round(value * 100)\n if (cents < AI_CATALOG_PRICE_USD.min * 100 || cents > AI_CATALOG_PRICE_USD.max * 100) return null\n return cents / 100\n}\n\nexport const AI_CATEGORIES_MAX = 12\nexport const AI_DISCOUNTS_MAX = 5\nexport const AI_CATEGORY_NAME_MAX_CHARS = 60\nexport const AI_PROPOSAL_WHY_MAX_CHARS = 200\n\n/** The highest percentage a proposed discount takes off, and the most a fixed one takes, in dollars. */\nexport const AI_DISCOUNT_MAX_PERCENT = 90\nexport const AI_DISCOUNT_MAX_FIXED_USD = 1_000\n\n/** A discount code: letters, digits, dashes and underscores, stored upper case. */\nexport const AI_DISCOUNT_CODE = /^[A-Z0-9_-]{3,20}$/\n\n/** An option axis. */\nexport interface AiProductOption {\n name: string\n values: string[]\n}\n\n/** One product as its editor hands it to a `product` job. */\nexport interface AiProductFacts {\n /** `null` for a product nobody has saved yet. */\n id: string | null\n name: string\n type: AiProductType\n /** The product's current description, cut to `AI_PRODUCT_TEXT_MAX_CHARS`. */\n text: string\n tags: string[]\n categoryIds: string[]\n options: AiProductOption[]\n /** The first photo's stored media value, or `null`. */\n imageUrl: string | null\n seoTitle: string\n seoDescription: string\n}\n\n/** A site's product category, as a request lists it to choose from. */\nexport interface AiProductCategory {\n id: string\n name: string\n}\n\n/** The merchant's own words about a product, which a claim in its copy may repeat. */\nexport function aiProductMerchantWords(product: Pick<AiProductFacts, 'name' | 'text' | 'tags'>): string {\n return [product.name, product.text, ...product.tags].join('\\n')\n}\n\nexport type AiProductsJobInputs =\n | { target: 'product'; product: AiProductFacts }\n | { target: 'bulk'; productIds: string[] }\n | { target: 'catalog' }\n | { target: 'categories' }\n\nconst ID = /^[A-Za-z0-9_-]{1,64}$/\n\nconst text = (value: unknown, max: number): string =>\n typeof value === 'string' ? value.replace(/\\s+/g, ' ').trim().slice(0, max) : ''\n\n/** A list stored as JSON, read defensively: strings only, trimmed, bounded. */\nfunction jsonStrings(value: unknown, max: number, maxChars: number): string[] {\n if (typeof value !== 'string' || !value.trim()) return []\n try {\n const parsed: unknown = JSON.parse(value)\n if (!Array.isArray(parsed)) return []\n return parsed\n .map((entry) => text(entry, maxChars))\n .filter(Boolean)\n .slice(0, max)\n } catch {\n return []\n }\n}\n\nfunction jsonOptions(value: unknown): AiProductOption[] {\n if (typeof value !== 'string' || !value.trim()) return []\n try {\n const parsed: unknown = JSON.parse(value)\n if (!Array.isArray(parsed)) return []\n return parsed\n .map((entry) => {\n const record = (entry ?? {}) as Record<string, unknown>\n return {\n name: text(record['name'], AI_PRODUCT_OPTION_NAME_MAX_CHARS),\n values: Array.isArray(record['values'])\n ? record['values'].map((value) => text(value, 40)).filter(Boolean).slice(0, AI_PRODUCT_OPTION_VALUES_MAX)\n : [],\n }\n })\n .slice(0, AI_PRODUCT_OPTIONS_MAX)\n } catch {\n return []\n }\n}\n\n/**\n * How large a job's inputs may be once written as JSON: under the 8,000\n * characters the create door admits, with room for the door's own keys.\n */\nexport const AI_PRODUCTS_INPUTS_MAX_JSON_CHARS = 7_500\n\n/**\n * A job's inputs for a target, as the console sends them: every value a\n * scalar, lists as JSON or as comma-separated ids, each bounded, and the\n * product's text shortened last until the whole fits what the create door\n * admits.\n */\nexport function aiProductsJobInputs(input: AiProductsJobInputs): Record<string, string> {\n switch (input.target) {\n case 'product': {\n const product = input.product\n const inputs: Record<string, string> = {\n target: 'product',\n productId: product.id ?? '',\n name: text(product.name, AI_PRODUCT_NAME_MAX_CHARS),\n type: product.type,\n text: product.text.slice(0, AI_PRODUCT_TEXT_MAX_CHARS),\n tags: JSON.stringify(product.tags.slice(0, 10).map((tag) => tag.slice(0, 40))),\n categoryIds: product.categoryIds.filter((id) => ID.test(id)).slice(0, 10).join(','),\n options: JSON.stringify(\n product.options.slice(0, AI_PRODUCT_OPTIONS_MAX).map((option) => ({\n name: option.name.slice(0, AI_PRODUCT_OPTION_NAME_MAX_CHARS),\n values: option.values.slice(0, AI_PRODUCT_OPTION_VALUES_MAX).map((value) => value.slice(0, 40)),\n })),\n ),\n imageUrl: (product.imageUrl ?? '').slice(0, 300),\n seoTitle: product.seoTitle.slice(0, 100),\n seoDescription: product.seoDescription.slice(0, 200),\n }\n while (JSON.stringify(inputs).length > AI_PRODUCTS_INPUTS_MAX_JSON_CHARS && inputs['text']) {\n inputs['text'] = inputs['text'].slice(0, Math.max(0, inputs['text'].length - 250))\n }\n return inputs\n }\n case 'bulk':\n return aiProductsBulkInputs(input.productIds)\n default:\n return { target: input.target }\n }\n}\n\n/** Why a `products` job's inputs cannot run, in words a person can act on. */\nexport const AI_PRODUCTS_NO_TARGET_COPY = 'This AI job does not say what to write for your products.'\nexport const AI_PRODUCTS_NO_NAME_COPY = 'Give the product a name before writing its copy.'\nexport const AI_PRODUCTS_NO_SELECTION_COPY = 'Pick the products to write copy for.'\nexport const AI_PRODUCTS_TOO_MANY_COPY = `Pick at most ${AI_PRODUCTS_BULK_MAX} products at a time.`\n\n/** A job's inputs read back, or the sentence that says why they cannot run. */\nexport function parseAiProductsJobInputs(raw: Readonly<Record<string, unknown>> | undefined): AiProductsJobInputs | string {\n const inputs = raw ?? {}\n const target = inputs['target']\n if (!(AI_PRODUCTS_TARGETS as readonly unknown[]).includes(target)) return AI_PRODUCTS_NO_TARGET_COPY\n if (target === 'product') {\n const name = text(inputs['name'], AI_PRODUCT_NAME_MAX_CHARS)\n if (!name) return AI_PRODUCTS_NO_NAME_COPY\n const type = inputs['type']\n const id = typeof inputs['productId'] === 'string' && ID.test(inputs['productId']) ? inputs['productId'] : null\n return {\n target,\n product: {\n id,\n name,\n type: (AI_PRODUCT_TYPES as readonly unknown[]).includes(type) ? (type as AiProductType) : 'physical',\n text: typeof inputs['text'] === 'string' ? inputs['text'].trim().slice(0, AI_PRODUCT_TEXT_MAX_CHARS) : '',\n tags: jsonStrings(inputs['tags'], 10, 40),\n categoryIds: String(inputs['categoryIds'] ?? '')\n .split(',')\n .map((part) => part.trim())\n .filter((part) => ID.test(part))\n .slice(0, 10),\n options: jsonOptions(inputs['options']),\n imageUrl: text(inputs['imageUrl'], 300) || null,\n seoTitle: text(inputs['seoTitle'], 100),\n seoDescription: text(inputs['seoDescription'], 200),\n },\n }\n }\n if (target === 'bulk') {\n const ids = String(inputs['productIds'] ?? '')\n .split(',')\n .map((part) => part.trim())\n .filter((part) => ID.test(part))\n const unique = [...new Set(ids)]\n if (!unique.length) return AI_PRODUCTS_NO_SELECTION_COPY\n if (unique.length > AI_PRODUCTS_BULK_MAX) return AI_PRODUCTS_TOO_MANY_COPY\n return { target, productIds: unique }\n }\n return { target: target as 'catalog' | 'categories' }\n}\n\n/* ------------------------------------------------------------------------ *\n * Proposals\n * ------------------------------------------------------------------------ */\n\n/** A product's copy, as proposed. */\nexport interface AiProductCopy {\n description: string\n seoTitle: string\n seoDescription: string\n tags: string[]\n categoryIds: string[]\n /** One name per option the product had, in order. */\n optionNames: string[]\n}\n\n/** What became of the product's photo. */\nexport type AiProductPhotoRead =\n /** The photo was read. */\n | 'read'\n /** The product has no photo. */\n | 'none'\n /** The photo is not an asset of this site's media library, or its org's. */\n | 'not-in-library'\n /** The photo could not be read. */\n | 'unreadable'\n /** The model this job ran on does not read pictures. */\n | 'model'\n\nexport interface AiProductCopyProposal {\n kind: 'copy'\n product: { id: string | null; name: string }\n /** `null` when there was nothing to propose: see `skipped`. */\n values: AiProductCopy | null\n /** The categories `values` names, with the names they had when the job read them. */\n categories: Array<{ id: string; name: string }>\n /** The option names the product had, beside the ones proposed. */\n optionNamesBefore: string[]\n /** The facts the copy marks as missing, in square brackets, for a person to fill in. */\n gaps: string[]\n photo: AiProductPhotoRead\n /** Why a bulk pass proposed nothing for this product, in customer-safe words. */\n skipped: string | null\n notes: string[]\n}\n\nexport interface AiCatalogProduct {\n name: string\n type: AiProductType\n description: string\n tags: string[]\n options: AiProductOption[]\n seoTitle: string\n seoDescription: string\n /** What the product's photo should show; nothing is uploaded or linked. */\n photo: string\n /**\n * The suggested price for every variant, in US dollars, as `aiCatalogPrice`\n * kept it; `null` (or absent, on a proposal made before 2026-10-12) when\n * the model gave none in range, and the store's default price stands in.\n */\n price?: number | null\n}\n\nexport interface AiCatalogProposal {\n kind: 'catalog'\n products: AiCatalogProduct[]\n notes: string[]\n}\n\nexport type AiDiscountKind = 'percent' | 'fixed' | 'free_shipping'\n\nexport interface AiProposedDiscount {\n name: string\n /** The code a shopper types, upper case; `null` for an automatic discount. */\n code: string | null\n kind: AiDiscountKind\n /** A `percent` discount's percentage. */\n valuePct: number | null\n /** A `fixed` discount's amount off, in cents. */\n valueCents: number | null\n /** The smallest order it applies to, in cents; `null` for any order. */\n minSubtotalCents: number | null\n why: string\n}\n\nexport interface AiCategoriesProposal {\n kind: 'categories'\n categories: Array<{ name: string; why: string }>\n discounts: AiProposedDiscount[]\n notes: string[]\n}\n\nexport type AiProductsProposal = AiProductCopyProposal | AiCatalogProposal | AiCategoriesProposal\n\n/** Output ids, so a pass that runs again finds what it already proposed. */\nexport const AI_PRODUCTS_OUTPUT_IDS = {\n copy: (productId: string | null) => `copy:${productId ?? 'new'}`,\n catalog: 'catalog',\n categories: 'categories',\n} as const\n\nconst isRecord = (value: unknown): value is Record<string, unknown> =>\n typeof value === 'object' && value !== null && !Array.isArray(value)\n\n/** An output's proposal, or `null` for an output that is not a products proposal. */\nexport function aiProductsProposalOf(output: Pick<AiJobOutput, 'resource' | 'proposal'> | null | undefined): AiProductsProposal | null {\n if (!output || output.resource !== 'product' || !isRecord(output.proposal)) return null\n const kind = output.proposal['kind']\n return kind === 'copy' || kind === 'catalog' || kind === 'categories'\n ? (output.proposal as unknown as AiProductsProposal)\n : null\n}\n\n/** A job's copy proposals, in the order the job made them. */\nexport function aiProductCopyProposals(job: Pick<AiJobSummary, 'outputs'> | null | undefined): AiProductCopyProposal[] {\n return (job?.outputs ?? [])\n .map((output) => aiProductsProposalOf(output))\n .filter((proposal): proposal is AiProductCopyProposal => proposal?.kind === 'copy')\n}\n\n/** A job's proposal of one kind, or `null`. */\nexport function aiProductsProposalOfKind<K extends AiProductsProposal['kind']>(\n job: Pick<AiJobSummary, 'outputs'> | null | undefined,\n kind: K,\n): Extract<AiProductsProposal, { kind: K }> | null {\n for (const output of job?.outputs ?? []) {\n const proposal = aiProductsProposalOf(output)\n if (proposal?.kind === kind) return proposal as Extract<AiProductsProposal, { kind: K }>\n }\n return null\n}\n\n/** The gaps a text marks for a person in square brackets, as `[material]`, each once. */\nexport function aiProductGaps(...texts: readonly string[]): string[] {\n const found = new Set<string>()\n for (const value of texts) {\n for (const match of value.matchAll(/\\[([^\\]\\n]{1,60})\\]/g)) found.add(match[1].trim())\n }\n return [...found].filter(Boolean)\n}\n\n/* ------------------------------------------------------------------------ *\n * The console's cards\n * ------------------------------------------------------------------------ */\n\n/** The option the import zone sets to write the imported products' copy. */\nexport const AI_PRODUCTS_IMPORT_WRITE_COPY = 'ai.writeCopy'\n\nconst BULK_BRIEF = /^Write storefront copy for (\\d+) products?$/\n\n/** How many products a bulk copy job was asked for, read from its brief; `null` for any other job. */\nexport function aiProductsBulkCount(job: Pick<AiJobSummary, 'brief'> | null | undefined): number | null {\n const match = BULK_BRIEF.exec(job?.brief ?? '')\n return match ? Number(match[1]) : null\n}\n"],"names":["AI_PRODUCTS_BULK_MAX","aiProductsBulkBrief","aiProductsBulkInputs","AI_PRODUCTS_TARGETS","AI_PRODUCT_TYPES","AI_PRODUCT_NAME_MAX_CHARS","AI_PRODUCT_TEXT_MAX_CHARS","AI_PRODUCT_DESCRIPTION_MAX_CHARS","AI_PRODUCT_TAGS_MAX","AI_PRODUCT_TAG_MAX_CHARS","AI_PRODUCT_CATEGORIES_MAX","AI_PRODUCT_CATEGORY_LIST_MAX","AI_PRODUCT_OPTIONS_MAX","AI_PRODUCT_OPTION_VALUES_MAX","AI_PRODUCT_OPTION_NAME_MAX_CHARS","AI_CATALOG_PRODUCTS","min","max","AI_CATALOG_DESCRIPTION_MAX_CHARS","AI_CATALOG_TAGS_MAX","AI_CATALOG_OPTIONS_MAX","AI_CATALOG_OPTION_VALUES_MAX","AI_CATALOG_OPTION_VALUE_MAX_CHARS","AI_CATALOG_PHOTO_MAX_CHARS","AI_CATALOG_PRICE_USD","aiCatalogPrice","raw","value","match","exec","Number","isFinite","cents","Math","round","AI_CATEGORIES_MAX","AI_DISCOUNTS_MAX","AI_CATEGORY_NAME_MAX_CHARS","AI_PROPOSAL_WHY_MAX_CHARS","AI_DISCOUNT_MAX_PERCENT","AI_DISCOUNT_MAX_FIXED_USD","AI_DISCOUNT_CODE","aiProductMerchantWords","product","name","text","tags","join","ID","replace","trim","slice","jsonStrings","maxChars","parsed","JSON","parse","Array","isArray","map","entry","filter","Boolean","jsonOptions","record","values","AI_PRODUCTS_INPUTS_MAX_JSON_CHARS","aiProductsJobInputs","input","target","inputs","productId","id","type","stringify","tag","categoryIds","test","options","option","imageUrl","seoTitle","seoDescription","length","productIds","AI_PRODUCTS_NO_TARGET_COPY","AI_PRODUCTS_NO_NAME_COPY","AI_PRODUCTS_NO_SELECTION_COPY","AI_PRODUCTS_TOO_MANY_COPY","parseAiProductsJobInputs","includes","String","split","part","ids","unique","Set","AI_PRODUCTS_OUTPUT_IDS","copy","catalog","categories","isRecord","aiProductsProposalOf","output","resource","proposal","kind","aiProductCopyProposals","job","outputs","aiProductsProposalOfKind","aiProductGaps","texts","found","matchAll","add","AI_PRODUCTS_IMPORT_WRITE_COPY","BULK_BRIEF","aiProductsBulkCount","brief"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../../../../../../libs/plugins/ai/src/lib/model/ai-products.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 { AiJobOutput, AiJobSummary } from './ai-jobs.types'\nimport { AI_PRODUCTS_BULK_MAX, aiProductsBulkBrief, aiProductsBulkInputs } from './ai-products-bulk'\n\nexport { AI_PRODUCTS_BULK_MAX, aiProductsBulkBrief }\n\n/**\n * COMMERCE BY AI (AGL-2916): what a `products` job is asked, and what it\n * proposes. Pure, so the step that asks, the console cards that start a job\n * and show its proposals, and the eval harness all read one shape.\n *\n * `inputs.target` names the work:\n *\n * - `product` — one product's copy, from what its editor holds right now:\n * the name, the text, the tags, the categories and options it has, and the\n * first photo. The editor may hold a product nobody has saved yet, so the\n * job never reads a product document for this target.\n * - `bulk` — the copy of up to `AI_PRODUCTS_BULK_MAX` saved products, one\n * product a pass, each read from the catalog as it is reached.\n * - `catalog` — a store's first products from the brief: names, copy, tags\n * and options, what each photo should show, and a suggested price by what\n * the product is (`aiCatalogPrice`, Zach 2026-10-12). No picture.\n * - `categories` — store categories and a first set of discounts from the brief.\n *\n * Every output is a PROPOSAL (`resource: 'product'`, with `proposal`), and the\n * job writes nothing. The commerce plugin's own surfaces write what a person\n * accepts, through the doors those surfaces already use.\n */\n\nexport const AI_PRODUCTS_TARGETS = ['product', 'bulk', 'catalog', 'categories'] as const\nexport type AiProductsTarget = (typeof AI_PRODUCTS_TARGETS)[number]\n\nexport const AI_PRODUCT_TYPES = ['physical', 'digital', 'service'] as const\nexport type AiProductType = (typeof AI_PRODUCT_TYPES)[number]\n\n/** The longest product name the editor saves. */\nexport const AI_PRODUCT_NAME_MAX_CHARS = 120\n\n/** How much of a product's existing description a request carries. */\nexport const AI_PRODUCT_TEXT_MAX_CHARS = 2_000\n\n/** The longest description the job proposes. */\nexport const AI_PRODUCT_DESCRIPTION_MAX_CHARS = 1_200\n\nexport const AI_PRODUCT_TAGS_MAX = 8\nexport const AI_PRODUCT_TAG_MAX_CHARS = 30\n\n/** The most categories one product's proposal names. */\nexport const AI_PRODUCT_CATEGORIES_MAX = 3\n\n/** The most of a site's categories a request lists to choose from. */\nexport const AI_PRODUCT_CATEGORY_LIST_MAX = 100\n\n/** A product's option axes, as the commerce editor bounds them. */\nexport const AI_PRODUCT_OPTIONS_MAX = 3\nexport const AI_PRODUCT_OPTION_VALUES_MAX = 25\nexport const AI_PRODUCT_OPTION_NAME_MAX_CHARS = 30\n\n/** How many products a catalog proposal holds. */\nexport const AI_CATALOG_PRODUCTS = { min: 1, max: 12 } as const\n\n/**\n * A proposed product is shorter than a written one: its description and tags\n * are a start the owner completes, and twelve of them at every bound still fit\n * one answer (`ai-job-products-step.spec.ts` measures it).\n */\nexport const AI_CATALOG_DESCRIPTION_MAX_CHARS = 600\nexport const AI_CATALOG_TAGS_MAX = 6\n\n/** A proposed product's options: few axes and few short values, so its variants stay a short list. */\nexport const AI_CATALOG_OPTIONS_MAX = 2\nexport const AI_CATALOG_OPTION_VALUES_MAX = 6\nexport const AI_CATALOG_OPTION_VALUE_MAX_CHARS = 30\n\n/** What a proposed product's photo should show, in one sentence. */\nexport const AI_CATALOG_PHOTO_MAX_CHARS = 160\n\n/**\n * A proposed product's suggested price, in US dollars — the one currency a\n * catalog prices in (`priceUsd`) — and the range code keeps it to (Zach,\n * 2026-10-12): a store's first products priced by what each one is (a bar\n * of handmade soap about $8–12, a candle $18–32, a gift set $30–45) instead\n * of every one at the commerce default. Never $0 or less, nothing past what\n * a small shop's first product plausibly lists at; a price outside the range,\n * or none, is no price, and the writer gives the product its default price.\n * Below the commerce ceiling (`COMMERCE_MAX_PRICE_USD`, $10,000) by design.\n */\nexport const AI_CATALOG_PRICE_USD = { min: 1, max: 5_000 } as const\n\n/**\n * A proposed price as code keeps it: a finite number of dollars (or a plain\n * \"$12.50\" a model wrote as text) inside `AI_CATALOG_PRICE_USD`, rounded to\n * whole cents; anything else — missing, zero, negative, absurd, not a number\n * — is `null`, so the product takes the store's default price for the owner\n * to change. The model is never re-asked for a price: a bad one costs the\n * product only its suggestion.\n */\nexport function aiCatalogPrice(raw: unknown): number | null {\n let value: number | null = null\n if (typeof raw === 'number') value = raw\n else if (typeof raw === 'string') {\n const match = /^\\s*(?:US\\s*)?\\$?\\s*(\\d{1,6}(?:\\.\\d{1,2})?)\\s*(?:USD)?\\s*$/i.exec(raw)\n value = match ? Number(match[1]) : null\n }\n if (value === null || !Number.isFinite(value)) return null\n const cents = Math.round(value * 100)\n if (cents < AI_CATALOG_PRICE_USD.min * 100 || cents > AI_CATALOG_PRICE_USD.max * 100) return null\n return cents / 100\n}\n\nexport const AI_CATEGORIES_MAX = 12\nexport const AI_DISCOUNTS_MAX = 5\nexport const AI_CATEGORY_NAME_MAX_CHARS = 60\nexport const AI_PROPOSAL_WHY_MAX_CHARS = 200\n\n/** The highest percentage a proposed discount takes off, and the most a fixed one takes, in dollars. */\nexport const AI_DISCOUNT_MAX_PERCENT = 90\nexport const AI_DISCOUNT_MAX_FIXED_USD = 1_000\n\n/** A discount code: letters, digits, dashes and underscores, stored upper case. */\nexport const AI_DISCOUNT_CODE = /^[A-Z0-9_-]{3,20}$/\n\n/** An option axis. */\nexport interface AiProductOption {\n name: string\n values: string[]\n}\n\n/** One product as its editor hands it to a `product` job. */\nexport interface AiProductFacts {\n /** `null` for a product nobody has saved yet. */\n id: string | null\n name: string\n type: AiProductType\n /** The product's current description, cut to `AI_PRODUCT_TEXT_MAX_CHARS`. */\n text: string\n tags: string[]\n categoryIds: string[]\n options: AiProductOption[]\n /** The first photo's stored media value, or `null`. */\n imageUrl: string | null\n seoTitle: string\n seoDescription: string\n}\n\n/** A site's product category, as a request lists it to choose from. */\nexport interface AiProductCategory {\n id: string\n name: string\n}\n\n/** The merchant's own words about a product, which a claim in its copy may repeat. */\nexport function aiProductMerchantWords(product: Pick<AiProductFacts, 'name' | 'text' | 'tags'>): string {\n return [product.name, product.text, ...product.tags].join('\\n')\n}\n\nexport type AiProductsJobInputs =\n | { target: 'product'; product: AiProductFacts }\n | { target: 'bulk'; productIds: string[] }\n | { target: 'catalog' }\n | { target: 'categories' }\n\nconst ID = /^[A-Za-z0-9_-]{1,64}$/\n\nconst text = (value: unknown, max: number): string =>\n typeof value === 'string' ? value.replace(/\\s+/g, ' ').trim().slice(0, max) : ''\n\n/** A list stored as JSON, read defensively: strings only, trimmed, bounded. */\nfunction jsonStrings(value: unknown, max: number, maxChars: number): string[] {\n if (typeof value !== 'string' || !value.trim()) return []\n try {\n const parsed: unknown = JSON.parse(value)\n if (!Array.isArray(parsed)) return []\n return parsed\n .map((entry) => text(entry, maxChars))\n .filter(Boolean)\n .slice(0, max)\n } catch {\n return []\n }\n}\n\nfunction jsonOptions(value: unknown): AiProductOption[] {\n if (typeof value !== 'string' || !value.trim()) return []\n try {\n const parsed: unknown = JSON.parse(value)\n if (!Array.isArray(parsed)) return []\n return parsed\n .map((entry) => {\n const record = (entry ?? {}) as Record<string, unknown>\n return {\n name: text(record['name'], AI_PRODUCT_OPTION_NAME_MAX_CHARS),\n values: Array.isArray(record['values'])\n ? record['values'].map((value) => text(value, 40)).filter(Boolean).slice(0, AI_PRODUCT_OPTION_VALUES_MAX)\n : [],\n }\n })\n .slice(0, AI_PRODUCT_OPTIONS_MAX)\n } catch {\n return []\n }\n}\n\n/**\n * How large a job's inputs may be once written as JSON: under the 8,000\n * characters the create door admits, with room for the door's own keys.\n */\nexport const AI_PRODUCTS_INPUTS_MAX_JSON_CHARS = 7_500\n\n/**\n * A job's inputs for a target, as the console sends them: every value a\n * scalar, lists as JSON or as comma-separated ids, each bounded, and the\n * product's text shortened last until the whole fits what the create door\n * admits.\n */\nexport function aiProductsJobInputs(input: AiProductsJobInputs): Record<string, string> {\n switch (input.target) {\n case 'product': {\n const product = input.product\n const inputs: Record<string, string> = {\n target: 'product',\n productId: product.id ?? '',\n name: text(product.name, AI_PRODUCT_NAME_MAX_CHARS),\n type: product.type,\n text: product.text.slice(0, AI_PRODUCT_TEXT_MAX_CHARS),\n tags: JSON.stringify(product.tags.slice(0, 10).map((tag) => tag.slice(0, 40))),\n categoryIds: product.categoryIds.filter((id) => ID.test(id)).slice(0, 10).join(','),\n options: JSON.stringify(\n product.options.slice(0, AI_PRODUCT_OPTIONS_MAX).map((option) => ({\n name: option.name.slice(0, AI_PRODUCT_OPTION_NAME_MAX_CHARS),\n values: option.values.slice(0, AI_PRODUCT_OPTION_VALUES_MAX).map((value) => value.slice(0, 40)),\n })),\n ),\n imageUrl: (product.imageUrl ?? '').slice(0, 300),\n seoTitle: product.seoTitle.slice(0, 100),\n seoDescription: product.seoDescription.slice(0, 200),\n }\n while (JSON.stringify(inputs).length > AI_PRODUCTS_INPUTS_MAX_JSON_CHARS && inputs['text']) {\n inputs['text'] = inputs['text'].slice(0, Math.max(0, inputs['text'].length - 250))\n }\n return inputs\n }\n case 'bulk':\n return aiProductsBulkInputs(input.productIds)\n default:\n return { target: input.target }\n }\n}\n\n/** Why a `products` job's inputs cannot run, in words a person can act on. */\nexport const AI_PRODUCTS_NO_TARGET_COPY = 'This AI job does not say what to write for your products.'\nexport const AI_PRODUCTS_NO_NAME_COPY = 'Give the product a name before writing its copy.'\nexport const AI_PRODUCTS_NO_SELECTION_COPY = 'Pick the products to write copy for.'\nexport const AI_PRODUCTS_TOO_MANY_COPY = `Pick at most ${AI_PRODUCTS_BULK_MAX} products at a time.`\n\n/** A job's inputs read back, or the sentence that says why they cannot run. */\nexport function parseAiProductsJobInputs(raw: Readonly<Record<string, unknown>> | undefined): AiProductsJobInputs | string {\n const inputs = raw ?? {}\n const target = inputs['target']\n if (!(AI_PRODUCTS_TARGETS as readonly unknown[]).includes(target)) return AI_PRODUCTS_NO_TARGET_COPY\n if (target === 'product') {\n const name = text(inputs['name'], AI_PRODUCT_NAME_MAX_CHARS)\n if (!name) return AI_PRODUCTS_NO_NAME_COPY\n const type = inputs['type']\n const id = typeof inputs['productId'] === 'string' && ID.test(inputs['productId']) ? inputs['productId'] : null\n return {\n target,\n product: {\n id,\n name,\n type: (AI_PRODUCT_TYPES as readonly unknown[]).includes(type) ? (type as AiProductType) : 'physical',\n text: typeof inputs['text'] === 'string' ? inputs['text'].trim().slice(0, AI_PRODUCT_TEXT_MAX_CHARS) : '',\n tags: jsonStrings(inputs['tags'], 10, 40),\n categoryIds: String(inputs['categoryIds'] ?? '')\n .split(',')\n .map((part) => part.trim())\n .filter((part) => ID.test(part))\n .slice(0, 10),\n options: jsonOptions(inputs['options']),\n imageUrl: text(inputs['imageUrl'], 300) || null,\n seoTitle: text(inputs['seoTitle'], 100),\n seoDescription: text(inputs['seoDescription'], 200),\n },\n }\n }\n if (target === 'bulk') {\n const ids = String(inputs['productIds'] ?? '')\n .split(',')\n .map((part) => part.trim())\n .filter((part) => ID.test(part))\n const unique = [...new Set(ids)]\n if (!unique.length) return AI_PRODUCTS_NO_SELECTION_COPY\n if (unique.length > AI_PRODUCTS_BULK_MAX) return AI_PRODUCTS_TOO_MANY_COPY\n return { target, productIds: unique }\n }\n return { target: target as 'catalog' | 'categories' }\n}\n\n/* ------------------------------------------------------------------------ *\n * Proposals\n * ------------------------------------------------------------------------ */\n\n/** A product's copy, as proposed. */\nexport interface AiProductCopy {\n description: string\n seoTitle: string\n seoDescription: string\n tags: string[]\n categoryIds: string[]\n /** One name per option the product had, in order. */\n optionNames: string[]\n}\n\n/** What became of the product's photo. */\nexport type AiProductPhotoRead =\n /** The photo was read. */\n | 'read'\n /** The product has no photo. */\n | 'none'\n /** The photo is not an asset of this site's media library, or its org's. */\n | 'not-in-library'\n /** The photo could not be read. */\n | 'unreadable'\n /** The model this job ran on does not read pictures. */\n | 'model'\n\nexport interface AiProductCopyProposal {\n kind: 'copy'\n product: { id: string | null; name: string }\n /** `null` when there was nothing to propose: see `skipped`. */\n values: AiProductCopy | null\n /** The categories `values` names, with the names they had when the job read them. */\n categories: Array<{ id: string; name: string }>\n /** The option names the product had, beside the ones proposed. */\n optionNamesBefore: string[]\n /** The facts the copy marks as missing, in square brackets, for a person to fill in. */\n gaps: string[]\n photo: AiProductPhotoRead\n /** Why a bulk pass proposed nothing for this product, in customer-safe words. */\n skipped: string | null\n notes: string[]\n}\n\nexport interface AiCatalogProduct {\n name: string\n type: AiProductType\n description: string\n tags: string[]\n options: AiProductOption[]\n seoTitle: string\n seoDescription: string\n /** What the product's photo should show; nothing is uploaded or linked. */\n photo: string\n /**\n * The suggested price for every variant, in US dollars, as `aiCatalogPrice`\n * kept it; `null` (or absent, on a proposal made before 2026-10-12) when\n * the model gave none in range, and the store's default price stands in.\n */\n price?: number | null\n}\n\nexport interface AiCatalogProposal {\n kind: 'catalog'\n products: AiCatalogProduct[]\n notes: string[]\n}\n\n// ── A product a shopper would buy (AGL-4065) ────────────────────────────\n\n/**\n * The re-ask a catalog whose names are kinds of product is answered with\n * (AGL-4065). The 2026-10-25 Berm & Bolt Moto Parts start listed \"Riding Gear\n * Item\", \"OEM ATV Parts Order\" and \"Aftermarket Dirt Bike Part\" at suggested\n * prices, from a brief that named kinds of part and no product.\n */\nexport const AI_CATALOG_NAME_REASK =\n 'Name real products a shopper would buy, never a category with “Item” or “Order” after it; where the brief names kinds of product and no product, name each one a plain item of one of those kinds, never a brand or a model the brief does not name.'\n\n/** The code a catalog's kind-for-a-name is refused under. */\nexport const AI_CATALOG_NAME_CODE = 'catalog-name-kind'\n\n/** A name's last word that names a kind of thing, or a transaction, never one thing a shopper buys. */\nconst KIND_HEAD =\n /\\b(?:items?|orders?|products?|parts?|things?|options?|selections?|assortments?|stuff|goods|merchandise|gear|accessor(?:y|ies)|suppl(?:y|ies)|equipment|essentials?|requests?|inquir(?:y|ies))$/i\n\n/** Makes a product name carries only where the brief names them: vehicles, apparel and electronics most of all. */\nconst BRANDS =\n /\\b(?:porsche|ferrari|lamborghini|bmw|mercedes|audi|volkswagen|toyota|honda|yamaha|kawasaki|suzuki|ktm|ducati|harley(?:-davidson)?|husqvarna|gasgas|polaris|can-am|tesla|ford|chevrolet|chevy|dodge|jeep|nissan|subaru|mazda|nike|adidas|reebok|samsung|iphone|playstation|xbox|nintendo|starbucks|coca-cola|pepsi)\\b/i\n\n/** A model number: letters and figures run together, as \"CRF450R\" or \"KX250\". */\nconst MODEL_CODE = /\\b(?=[A-Z0-9-]*\\d)(?=[A-Z0-9-]*[A-Z])[A-Z0-9][A-Z0-9-]{3,}\\b/\n\n/** The make a text names that the brief does not (AGL-4065), or `null`: a sample row or a product names none. Pure. */\nexport function aiTextNamesBrand(text: string, brief: string): string | null {\n const brand = BRANDS.exec(text)?.[0]\n return brand && !brief.toLowerCase().includes(brand.toLowerCase()) ? brand : null\n}\n\n/**\n * Why a proposed product's name is not one a shopper would buy (AGL-4065), or\n * `null`: a kind of product with a word like \"Item\", \"Order\" or \"Part\" after\n * it, or a make or a model number the brief does not name. \"Dirt Bike Tire\"\n * and \"Motocross helmet\" are products; \"Riding Gear Item\" is a kind. Pure.\n */\nexport function aiCatalogNameProblem(name: string, brief: string): string | null {\n const plain = name.replace(/\\s+/g, ' ').trim()\n if (!plain) return null\n const words = brief.toLowerCase()\n if (KIND_HEAD.test(plain.replace(/[^\\p{L}\\p{N}]+$/u, ''))) return `“${plain}” names a kind of product, not one a shopper buys`\n if (aiTextNamesBrand(plain, brief)) return `“${plain}” names a make the brief does not`\n const model = MODEL_CODE.exec(plain)?.[0]\n if (model && !words.includes(model.toLowerCase())) return `“${plain}” names a model the brief does not`\n return null\n}\n\nexport type AiDiscountKind = 'percent' | 'fixed' | 'free_shipping'\n\nexport interface AiProposedDiscount {\n name: string\n /** The code a shopper types, upper case; `null` for an automatic discount. */\n code: string | null\n kind: AiDiscountKind\n /** A `percent` discount's percentage. */\n valuePct: number | null\n /** A `fixed` discount's amount off, in cents. */\n valueCents: number | null\n /** The smallest order it applies to, in cents; `null` for any order. */\n minSubtotalCents: number | null\n why: string\n}\n\nexport interface AiCategoriesProposal {\n kind: 'categories'\n categories: Array<{ name: string; why: string }>\n discounts: AiProposedDiscount[]\n notes: string[]\n}\n\nexport type AiProductsProposal = AiProductCopyProposal | AiCatalogProposal | AiCategoriesProposal\n\n/** Output ids, so a pass that runs again finds what it already proposed. */\nexport const AI_PRODUCTS_OUTPUT_IDS = {\n copy: (productId: string | null) => `copy:${productId ?? 'new'}`,\n catalog: 'catalog',\n categories: 'categories',\n} as const\n\nconst isRecord = (value: unknown): value is Record<string, unknown> =>\n typeof value === 'object' && value !== null && !Array.isArray(value)\n\n/** An output's proposal, or `null` for an output that is not a products proposal. */\nexport function aiProductsProposalOf(output: Pick<AiJobOutput, 'resource' | 'proposal'> | null | undefined): AiProductsProposal | null {\n if (!output || output.resource !== 'product' || !isRecord(output.proposal)) return null\n const kind = output.proposal['kind']\n return kind === 'copy' || kind === 'catalog' || kind === 'categories'\n ? (output.proposal as unknown as AiProductsProposal)\n : null\n}\n\n/** A job's copy proposals, in the order the job made them. */\nexport function aiProductCopyProposals(job: Pick<AiJobSummary, 'outputs'> | null | undefined): AiProductCopyProposal[] {\n return (job?.outputs ?? [])\n .map((output) => aiProductsProposalOf(output))\n .filter((proposal): proposal is AiProductCopyProposal => proposal?.kind === 'copy')\n}\n\n/** A job's proposal of one kind, or `null`. */\nexport function aiProductsProposalOfKind<K extends AiProductsProposal['kind']>(\n job: Pick<AiJobSummary, 'outputs'> | null | undefined,\n kind: K,\n): Extract<AiProductsProposal, { kind: K }> | null {\n for (const output of job?.outputs ?? []) {\n const proposal = aiProductsProposalOf(output)\n if (proposal?.kind === kind) return proposal as Extract<AiProductsProposal, { kind: K }>\n }\n return null\n}\n\n/** The gaps a text marks for a person in square brackets, as `[material]`, each once. */\nexport function aiProductGaps(...texts: readonly string[]): string[] {\n const found = new Set<string>()\n for (const value of texts) {\n for (const match of value.matchAll(/\\[([^\\]\\n]{1,60})\\]/g)) found.add(match[1].trim())\n }\n return [...found].filter(Boolean)\n}\n\n/* ------------------------------------------------------------------------ *\n * The console's cards\n * ------------------------------------------------------------------------ */\n\n/** The option the import zone sets to write the imported products' copy. */\nexport const AI_PRODUCTS_IMPORT_WRITE_COPY = 'ai.writeCopy'\n\nconst BULK_BRIEF = /^Write storefront copy for (\\d+) products?$/\n\n/** How many products a bulk copy job was asked for, read from its brief; `null` for any other job. */\nexport function aiProductsBulkCount(job: Pick<AiJobSummary, 'brief'> | null | undefined): number | null {\n const match = BULK_BRIEF.exec(job?.brief ?? '')\n return match ? Number(match[1]) : null\n}\n"],"names":["AI_PRODUCTS_BULK_MAX","aiProductsBulkBrief","aiProductsBulkInputs","AI_PRODUCTS_TARGETS","AI_PRODUCT_TYPES","AI_PRODUCT_NAME_MAX_CHARS","AI_PRODUCT_TEXT_MAX_CHARS","AI_PRODUCT_DESCRIPTION_MAX_CHARS","AI_PRODUCT_TAGS_MAX","AI_PRODUCT_TAG_MAX_CHARS","AI_PRODUCT_CATEGORIES_MAX","AI_PRODUCT_CATEGORY_LIST_MAX","AI_PRODUCT_OPTIONS_MAX","AI_PRODUCT_OPTION_VALUES_MAX","AI_PRODUCT_OPTION_NAME_MAX_CHARS","AI_CATALOG_PRODUCTS","min","max","AI_CATALOG_DESCRIPTION_MAX_CHARS","AI_CATALOG_TAGS_MAX","AI_CATALOG_OPTIONS_MAX","AI_CATALOG_OPTION_VALUES_MAX","AI_CATALOG_OPTION_VALUE_MAX_CHARS","AI_CATALOG_PHOTO_MAX_CHARS","AI_CATALOG_PRICE_USD","aiCatalogPrice","raw","value","match","exec","Number","isFinite","cents","Math","round","AI_CATEGORIES_MAX","AI_DISCOUNTS_MAX","AI_CATEGORY_NAME_MAX_CHARS","AI_PROPOSAL_WHY_MAX_CHARS","AI_DISCOUNT_MAX_PERCENT","AI_DISCOUNT_MAX_FIXED_USD","AI_DISCOUNT_CODE","aiProductMerchantWords","product","name","text","tags","join","ID","replace","trim","slice","jsonStrings","maxChars","parsed","JSON","parse","Array","isArray","map","entry","filter","Boolean","jsonOptions","record","values","AI_PRODUCTS_INPUTS_MAX_JSON_CHARS","aiProductsJobInputs","input","target","inputs","productId","id","type","stringify","tag","categoryIds","test","options","option","imageUrl","seoTitle","seoDescription","length","productIds","AI_PRODUCTS_NO_TARGET_COPY","AI_PRODUCTS_NO_NAME_COPY","AI_PRODUCTS_NO_SELECTION_COPY","AI_PRODUCTS_TOO_MANY_COPY","parseAiProductsJobInputs","includes","String","split","part","ids","unique","Set","AI_CATALOG_NAME_REASK","AI_CATALOG_NAME_CODE","KIND_HEAD","BRANDS","MODEL_CODE","aiTextNamesBrand","brief","brand","toLowerCase","aiCatalogNameProblem","plain","words","model","AI_PRODUCTS_OUTPUT_IDS","copy","catalog","categories","isRecord","aiProductsProposalOf","output","resource","proposal","kind","aiProductCopyProposals","job","outputs","aiProductsProposalOfKind","aiProductGaps","texts","found","matchAll","add","AI_PRODUCTS_IMPORT_WRITE_COPY","BULK_BRIEF","aiProductsBulkCount"],"mappings":"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"}
|
|
@@ -25,8 +25,9 @@
|
|
|
25
25
|
* (`jobs/ai-site-inspiration-signals.ts`). Never a word, a picture or a logo
|
|
26
26
|
* of theirs: nothing a page says reaches a prompt.
|
|
27
27
|
*
|
|
28
|
-
* Behind `release_ai_site_inspiration`,
|
|
29
|
-
* guided start asks for no site and a job's inspiration is
|
|
28
|
+
* Behind `release_ai_site_inspiration`, on by default since 2026-10-28:
|
|
29
|
+
* turned off, the guided start asks for no site and a job's inspiration is
|
|
30
|
+
* never read.
|
|
30
31
|
*
|
|
31
32
|
* Pure and console-safe: the input's name, the limits and how an answer is
|
|
32
33
|
* read. No network.
|
|
@@ -24,8 +24,9 @@
|
|
|
24
24
|
* (`jobs/ai-site-inspiration-signals.ts`). Never a word, a picture or a logo
|
|
25
25
|
* of theirs: nothing a page says reaches a prompt.
|
|
26
26
|
*
|
|
27
|
-
* Behind `release_ai_site_inspiration`,
|
|
28
|
-
* guided start asks for no site and a job's inspiration is
|
|
27
|
+
* Behind `release_ai_site_inspiration`, on by default since 2026-10-28:
|
|
28
|
+
* turned off, the guided start asks for no site and a job's inspiration is
|
|
29
|
+
* never read.
|
|
29
30
|
*
|
|
30
31
|
* Pure and console-safe: the input's name, the limits and how an answer is
|
|
31
32
|
* read. No network.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../../../../libs/plugins/ai/src/lib/model/ai-site-inspiration.ts"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Sites I like (AGL-3975, part of AGL-3973): the sites a person names in the\n * guided start as inspiration, as the job carries them.\n *\n * Free names one site and a paid plan three. From each the site job takes\n * SIGNALS only — how the sections run, the colors, the type's mood, the shape\n * of buttons and cards, how the pages move and, on a paid plan, which\n * features it offers — each read by code into the site job's own closed sets\n * (`jobs/ai-site-inspiration-signals.ts`). Never a word, a picture or a logo\n * of theirs: nothing a page says reaches a prompt.\n *\n * Behind `release_ai_site_inspiration`,
|
|
1
|
+
{"version":3,"sources":["../../../../../../../libs/plugins/ai/src/lib/model/ai-site-inspiration.ts"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Sites I like (AGL-3975, part of AGL-3973): the sites a person names in the\n * guided start as inspiration, as the job carries them.\n *\n * Free names one site and a paid plan three. From each the site job takes\n * SIGNALS only — how the sections run, the colors, the type's mood, the shape\n * of buttons and cards, how the pages move and, on a paid plan, which\n * features it offers — each read by code into the site job's own closed sets\n * (`jobs/ai-site-inspiration-signals.ts`). Never a word, a picture or a logo\n * of theirs: nothing a page says reaches a prompt.\n *\n * Behind `release_ai_site_inspiration`, on by default since 2026-10-28:\n * turned off, the guided start asks for no site and a job's inspiration is\n * never read.\n *\n * Pure and console-safe: the input's name, the limits and how an answer is\n * read. No network.\n */\n\n/** The release flag the whole feature waits behind. */\nexport const AI_SITE_INSPIRATION_FLAG = 'release_ai_site_inspiration' as const\n\n/**\n * The job input the sites travel in: one string, the addresses separated by\n * spaces, because a job's inputs are scalars (`parseCreateAiJobBody`).\n */\nexport const AI_SITE_INSPIRATION_INPUT = 'inspiration'\n\n/** How many sites a plan may name: Free one, every paid plan three. */\nexport const AI_SITE_INSPIRATION_LIMITS = { free: 1, paid: 3 } as const\n\n/** The most any job may carry, whatever its plan. */\nexport const AI_SITE_INSPIRATION_MAX = AI_SITE_INSPIRATION_LIMITS.paid\n\n/** The longest address one site may be given as. */\nexport const AI_SITE_INSPIRATION_URL_MAX_CHARS = 300\n\n/** What the guided start says a paid plan adds, beside a Free workspace's locked fields. */\nexport const AI_SITE_INSPIRATION_PAID_NOTE = `Paid plans can name up to ${AI_SITE_INSPIRATION_LIMITS.paid} sites, and also match the features they offer, like booking, a store or a blog.`\n\n/** How many sites a workspace may name. */\nexport function aiSiteInspirationLimit(freeTaste: boolean | null | undefined): number {\n return freeTaste ? AI_SITE_INSPIRATION_LIMITS.free : AI_SITE_INSPIRATION_LIMITS.paid\n}\n\n/**\n * One address as the job keeps it: https only, no credentials, the default\n * port, no fragment. `null` for anything else. A bare host (\"example.com\")\n * is read as its https address, the way a person types one.\n */\nexport function aiSiteInspirationUrl(value: unknown): string | null {\n if (typeof value !== 'string') return null\n const trimmed = value.trim()\n if (!trimmed || trimmed.length > AI_SITE_INSPIRATION_URL_MAX_CHARS) return null\n const written = /^[a-z][a-z0-9+.-]*:/i.test(trimmed) ? trimmed : `https://${trimmed}`\n let url: URL\n try {\n url = new URL(written)\n } catch {\n return null\n }\n if (url.protocol !== 'https:' || url.username || url.password) return null\n if (url.port && url.port !== '443') return null\n // A host with no dot is a typo or an internal name, never a public site.\n if (!url.hostname.includes('.') || url.hostname.endsWith('.')) return null\n url.hash = ''\n return url.toString()\n}\n\n/**\n * The sites a job's inputs name, or the sentence the door refuses them with.\n * Absent or empty is none. Each must be an https address; more than\n * {@link AI_SITE_INSPIRATION_MAX} is refused, and the same site twice counts\n * once. The plan's own limit is the door's (`aiSiteInspirationRefusal`).\n */\nexport function parseAiSiteInspiration(\n inputs: Readonly<Record<string, unknown>> | null | undefined,\n): string[] | string {\n const raw = inputs?.[AI_SITE_INSPIRATION_INPUT]\n if (raw === undefined || raw === null || raw === '') return []\n if (typeof raw !== 'string') {\n return `${AI_SITE_INSPIRATION_INPUT} must be text: the addresses of the sites you like, separated by spaces`\n }\n const urls: string[] = []\n for (const word of raw.split(/\\s+/).filter(Boolean)) {\n const url = aiSiteInspirationUrl(word)\n if (!url) return 'Give each site you like as its https address, like https://example.com.'\n if (!urls.includes(url)) urls.push(url)\n }\n if (urls.length > AI_SITE_INSPIRATION_MAX) return `Name at most ${AI_SITE_INSPIRATION_MAX} sites you like.`\n return urls\n}\n\n/** Why a workspace may not name this many sites, in a sentence a member reads; `null` when it may. */\nexport function aiSiteInspirationRefusal(urls: readonly string[], freeTaste: boolean | null | undefined): string | null {\n const limit = aiSiteInspirationLimit(freeTaste)\n if (urls.length <= limit) return null\n return freeTaste\n ? `A Free workspace can name ${AI_SITE_INSPIRATION_LIMITS.free} site you like. ${AI_SITE_INSPIRATION_PAID_NOTE}`\n : `Name at most ${limit} sites you like.`\n}\n\n/** The sites as the job input carries them; empty for none, which the start leaves out of its inputs. */\nexport function aiSiteInspirationInput(urls: readonly string[]): string {\n const kept: string[] = []\n for (const url of urls.map(aiSiteInspirationUrl)) {\n if (url && !kept.includes(url)) kept.push(url)\n }\n return kept.slice(0, AI_SITE_INSPIRATION_MAX).join(' ')\n}\n\n/** A site as the review names it: its host, without `www.`. */\nexport function aiSiteInspirationHost(url: string): string {\n try {\n return new URL(url).hostname.replace(/^www\\./, '')\n } catch {\n return url\n }\n}\n"],"names":["AI_SITE_INSPIRATION_FLAG","AI_SITE_INSPIRATION_INPUT","AI_SITE_INSPIRATION_LIMITS","free","paid","AI_SITE_INSPIRATION_MAX","AI_SITE_INSPIRATION_URL_MAX_CHARS","AI_SITE_INSPIRATION_PAID_NOTE","aiSiteInspirationLimit","freeTaste","aiSiteInspirationUrl","value","trimmed","trim","length","written","test","url","URL","protocol","username","password","port","hostname","includes","endsWith","hash","toString","parseAiSiteInspiration","inputs","raw","undefined","urls","word","split","filter","Boolean","push","aiSiteInspirationRefusal","limit","aiSiteInspirationInput","kept","map","slice","join","aiSiteInspirationHost","replace"],"mappings":"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"}
|
package/src/lib/plugin.js
CHANGED
|
@@ -28,7 +28,6 @@ import { lazyWidget } from "./lazy-widget.js";
|
|
|
28
28
|
*/ /** What a page shows while its code arrives. */ const PAGE_LOADING = createElement(LinearProgress, {
|
|
29
29
|
'aria-label': 'Loading'
|
|
30
30
|
});
|
|
31
|
-
const AiCollaboratorPermissionsCell = lazyWidget('AiCollaboratorPermissionsCell', ()=>import("./components/ai-collaborator-permissions-column.component.js").then((m)=>m.AiCollaboratorPermissionsCell));
|
|
32
31
|
const AiSaveAsComponent = lazyWidget('AiSaveAsComponent', ()=>import("./components/ai-save-as-component.component.js").then((m)=>m.AiSaveAsComponent));
|
|
33
32
|
const AiGenerateSectionControl = lazyWidget('AiGenerateSectionControl', ()=>import("./components/besigner-ai-controls.component.js").then((m)=>m.AiGenerateSectionControl));
|
|
34
33
|
const AiRewriteControl = lazyWidget('AiRewriteControl', ()=>import("./components/besigner-ai-controls.component.js").then((m)=>m.AiRewriteControl));
|
|
@@ -197,18 +196,10 @@ const AiJobsPage = lazyWidget('AiJobsPage', ()=>import("./components/ai-jobs-pag
|
|
|
197
196
|
permission: 'billing.view',
|
|
198
197
|
Component: AiTopUsersCard
|
|
199
198
|
},
|
|
200
|
-
// The collaborators table's AI
|
|
201
|
-
//
|
|
202
|
-
//
|
|
203
|
-
|
|
204
|
-
slot: 'hostMembers',
|
|
205
|
-
widgetId: 'ai-collaborator-permissions',
|
|
206
|
-
title: 'AI',
|
|
207
|
-
column: {
|
|
208
|
-
header: 'AI'
|
|
209
|
-
},
|
|
210
|
-
Component: AiCollaboratorPermissionsCell
|
|
211
|
-
},
|
|
199
|
+
// The collaborators table's AI toggles (AGL-2927) are the platform's
|
|
200
|
+
// own per-site Permissions dialog now (AGL-4047), which draws every
|
|
201
|
+
// per-site key, these two included; `/api/ai/host-permissions` stays
|
|
202
|
+
// for the native apps.
|
|
212
203
|
// The copy assistant's besigner controls (AGL-89, AGL-169): Generate a
|
|
213
204
|
// section on every editor's toolbar, and Rewrite with AI under the
|
|
214
205
|
// selected element's fields. Each opens the provider's dialog, and is
|
package/src/lib/plugin.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../../../libs/plugins/ai/src/lib/plugin.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 { PLATFORM_BRAND_NAME, aiAddonName, registerConsoleExtension } from '@aglyn/aglyn'\nimport { LinearProgress } from '@mui/material'\nimport { createElement } from 'react'\nimport { AiAssistProviderOnHost } from './components/ai-assist-provider-on-host.component'\nimport { AI_PLUGIN_ID } from './constants'\nimport { registerAiDeclarations } from './declarations'\nimport { lazyWidget } from './lazy-widget'\n\n/*\n * Every component below is registered by name and loaded the first time the\n * shell draws it (AGL-3649); see `lazyWidget`. The console loads this plugin\n * on every screen, so a static import of a component here is downloaded by\n * every reader of every page, staff cards included.\n */\n\n/** What a page shows while its code arrives. */\nconst PAGE_LOADING = createElement(LinearProgress, { 'aria-label': 'Loading' })\n\nconst AiCollaboratorPermissionsCell = lazyWidget(\n 'AiCollaboratorPermissionsCell',\n () =>\n import('./components/ai-collaborator-permissions-column.component').then(\n (m) => m.AiCollaboratorPermissionsCell,\n ),\n)\nconst AiSaveAsComponent = lazyWidget('AiSaveAsComponent', () =>\n import('./components/ai-save-as-component.component').then(\n (m) => m.AiSaveAsComponent,\n ),\n)\nconst AiGenerateSectionControl = lazyWidget('AiGenerateSectionControl', () =>\n import('./components/besigner-ai-controls.component').then(\n (m) => m.AiGenerateSectionControl,\n ),\n)\nconst AiRewriteControl = lazyWidget('AiRewriteControl', () =>\n import('./components/besigner-ai-controls.component').then(\n (m) => m.AiRewriteControl,\n ),\n)\nconst AssistPanelOnHost = lazyWidget('AssistPanelOnHost', () =>\n import('./components/ai-permissions-on-host.component').then(\n (m) => m.AssistPanelOnHost,\n ),\n)\nconst AiCreditsCard = lazyWidget('AiCreditsCard', () =>\n import('./components/ai-credits-card.component').then((m) => m.default),\n)\nconst AiJobsTopBarIndicator = lazyWidget('AiJobsTopBarIndicator', () =>\n import('./components/ai-jobs-indicator.component').then((m) => m.default),\n)\nconst AiCollaboratorCreditsCell = lazyWidget('AiCollaboratorCreditsCell', () =>\n import('./components/ai-credits-columns.component').then(\n (m) => m.AiCollaboratorCreditsCell,\n ),\n)\nconst AiCollaboratorCreditsHeader = lazyWidget(\n 'AiCollaboratorCreditsHeader',\n () =>\n import('./components/ai-credits-columns.component').then(\n (m) => m.AiCollaboratorCreditsHeader,\n ),\n)\nconst AiMemberCreditsCell = lazyWidget('AiMemberCreditsCell', () =>\n import('./components/ai-credits-columns.component').then(\n (m) => m.AiMemberCreditsCell,\n ),\n)\nconst AiMemberCreditsHeader = lazyWidget('AiMemberCreditsHeader', () =>\n import('./components/ai-credits-columns.component').then(\n (m) => m.AiMemberCreditsHeader,\n ),\n)\nconst AssistSignalsPage = lazyWidget(\n 'AssistSignalsPage',\n () =>\n import('./components/assist-signals-page.component').then(\n (m) => m.AssistSignalsPage,\n ),\n PAGE_LOADING,\n)\nconst BillingAssistOverageCard = lazyWidget('BillingAssistOverageCard', () =>\n import('./components/billing-assist-overage-card.component').then(\n (m) => m.default,\n ),\n)\nconst AiTopUsersCard = lazyWidget('AiTopUsersCard', () =>\n import('./components/billing-ai-top-users.component').then(\n (m) => m.AiTopUsersCard,\n ),\n)\nconst AiAllotmentsCard = lazyWidget('AiAllotmentsCard', () =>\n import('./components/billing-ai-allotments.component').then(\n (m) => m.AiAllotmentsCard,\n ),\n)\nconst AiCollaboratorAllotmentCell = lazyWidget(\n 'AiCollaboratorAllotmentCell',\n () =>\n import('./components/host-ai-allotments.component').then(\n (m) => m.AiCollaboratorAllotmentCell,\n ),\n)\nconst AiCollaboratorAllotmentHeader = lazyWidget(\n 'AiCollaboratorAllotmentHeader',\n () =>\n import('./components/host-ai-allotments.component').then(\n (m) => m.AiCollaboratorAllotmentHeader,\n ),\n)\nconst AiSiteAllotmentCard = lazyWidget('AiSiteAllotmentCard', () =>\n import('./components/host-ai-allotments.component').then(\n (m) => m.AiSiteAllotmentCard,\n ),\n)\nconst MemberAiAllotmentCard = lazyWidget('MemberAiAllotmentCard', () =>\n import('./components/member-ai-allotment-card.component').then(\n (m) => m.default,\n ),\n)\nconst MemberAiUsageCard = lazyWidget('MemberAiUsageCard', () =>\n import('./components/member-ai-usage-card.component').then((m) => m.default),\n)\nconst AiThemeProposalCard = lazyWidget('AiThemeProposalCard', () =>\n import('./components/ai-theme-proposal-card.component').then(\n (m) => m.default,\n ),\n)\nconst StaffOrgAiCard = lazyWidget('StaffOrgAiCard', () =>\n import('./components/staff-org-ai-card.component').then((m) => m.default),\n)\nconst StaffOrgAiConversations = lazyWidget('StaffOrgAiConversations', () =>\n import('./components/staff-org-ai-conversations.component').then((m) => m.default),\n)\nconst StaffOrgUsageAiCreditsCell = lazyWidget(\n 'StaffOrgUsageAiCreditsCell',\n () =>\n import('./components/staff-org-usage-ai-columns.component').then(\n (m) => m.StaffOrgUsageAiCreditsCell,\n ),\n)\nconst StaffOrgUsageAiOverageCell = lazyWidget(\n 'StaffOrgUsageAiOverageCell',\n () =>\n import('./components/staff-org-usage-ai-columns.component').then(\n (m) => m.StaffOrgUsageAiOverageCell,\n ),\n)\nconst StaffOrgUsageAiPool = lazyWidget('StaffOrgUsageAiPool', () =>\n import('./components/staff-org-usage-ai-columns.component').then(\n (m) => m.StaffOrgUsageAiPool,\n ),\n)\nconst StaffOrgUsageAssistCell = lazyWidget('StaffOrgUsageAssistCell', () =>\n import('./components/staff-org-usage-ai-columns.component').then(\n (m) => m.StaffOrgUsageAssistCell,\n ),\n)\nconst StaffOrgsAiSpendCell = lazyWidget('StaffOrgsAiSpendCell', () =>\n import('./components/staff-orgs-ai-spend-column.component').then(\n (m) => m.StaffOrgsAiSpendCell,\n ),\n)\nconst StaffOrgsAiSpendHeader = lazyWidget('StaffOrgsAiSpendHeader', () =>\n import('./components/staff-orgs-ai-spend-column.component').then(\n (m) => m.StaffOrgsAiSpendHeader,\n ),\n)\nconst StaffUserAiUsageCard = lazyWidget('StaffUserAiUsageCard', () =>\n import('./components/staff-user-ai-usage-card.component').then(\n (m) => m.default,\n ),\n)\nconst AiSeoAuditCard = lazyWidget('AiSeoAuditCard', () =>\n import('./components/ai-seo-audit-card.component').then((m) => m.default),\n)\nconst AiSiteBatchCard = lazyWidget('AiSiteBatchCard', () =>\n import('./components/ai-site-batch-card.component').then((m) => m.default),\n)\nconst AiSiteSeoStartCard = lazyWidget('AiSiteSeoStartCard', () =>\n import('./components/ai-site-seo-start-card.component').then(\n (m) => m.default,\n ),\n)\nconst AiSiteMemoryCard = lazyWidget('AiSiteMemoryCard', () =>\n import('./components/ai-site-memory-card.component').then((m) => m.default),\n)\nconst AiSiteStartCard = lazyWidget('AiSiteStartCard', () =>\n import('./components/ai-site-start-card.component').then((m) => m.default),\n)\nconst AiSeoFieldsCard = lazyWidget('AiSeoFieldsCard', () =>\n import('./components/ai-seo-fields-card.component').then((m) => m.default),\n)\nconst AiDescribeAutomationButton = lazyWidget(\n 'AiDescribeAutomationButton',\n () =>\n import('./components/ai-describe-automation.component').then(\n (m) => m.default,\n ),\n)\nconst AiReviseAutomation = lazyWidget('AiReviseAutomation', () =>\n import('./components/ai-revise-automation.component').then((m) => m.default),\n)\nconst AiDescribeOrgAutomationButton = lazyWidget(\n 'AiDescribeOrgAutomationButton',\n () =>\n import('./components/ai-describe-org-automation.component').then(\n (m) => m.default,\n ),\n)\nconst AiInsightHostCard = lazyWidget('AiInsightHostCard', () =>\n import('./components/ai-insight-card.component').then(\n (m) => m.AiInsightHostCard,\n ),\n)\nconst AiInsightOrgCard = lazyWidget('AiInsightOrgCard', () =>\n import('./components/ai-insight-card.component').then(\n (m) => m.AiInsightOrgCard,\n ),\n)\nconst AiLogicCreateButton = lazyWidget('AiLogicCreateButton', () =>\n import('./components/ai-logic.component').then((m) => m.AiLogicCreateButton),\n)\nconst AiLogicFixReference = lazyWidget('AiLogicFixReference', () =>\n import('./components/ai-logic.component').then((m) => m.AiLogicFixReference),\n)\nconst AiLogicFunctionTools = lazyWidget('AiLogicFunctionTools', () =>\n import('./components/ai-logic.component').then((m) => m.AiLogicFunctionTools),\n)\nconst AiFunnelAskButton = lazyWidget('AiFunnelAskButton', () =>\n import('./components/ai-funnel-zones.component').then(\n (m) => m.AiFunnelAskButton,\n ),\n)\nconst AiFunnelCreateButton = lazyWidget('AiFunnelCreateButton', () =>\n import('./components/ai-funnel-zones.component').then(\n (m) => m.AiFunnelCreateButton,\n ),\n)\nconst AiCrmEmailDraft = lazyWidget('AiCrmEmailDraft', () =>\n import('./components/ai-crm-email-draft.component').then((m) => m.default),\n)\nconst AiCrmImportMapping = lazyWidget('AiCrmImportMapping', () =>\n import('./components/ai-crm-import-mapping.component').then((m) => m.default),\n)\nconst AiCrmRecordCard = lazyWidget('AiCrmRecordCard', () =>\n import('./components/ai-crm-record-card.component').then((m) => m.default),\n)\nconst AiDescribePageButton = lazyWidget('AiDescribePageButton', () =>\n import('./components/ai-describe-page.component').then((m) => m.default),\n)\nconst AiMediaCreateButton = lazyWidget('AiMediaCreateButton', () =>\n import('./components/ai-media-create.component').then((m) => m.default),\n)\nconst AiDescribeComponentButton = lazyWidget('AiDescribeComponentButton', () =>\n import('./components/ai-describe-button.component').then(\n (m) => m.AiDescribeComponentButton,\n ),\n)\nconst AiDescribeFormButton = lazyWidget('AiDescribeFormButton', () =>\n import('./components/ai-describe-button.component').then(\n (m) => m.AiDescribeFormButton,\n ),\n)\nconst AiDescribeLayoutButton = lazyWidget('AiDescribeLayoutButton', () =>\n import('./components/ai-describe-button.component').then(\n (m) => m.AiDescribeLayoutButton,\n ),\n)\nconst AiDescribeTemplateButton = lazyWidget('AiDescribeTemplateButton', () =>\n import('./components/ai-describe-button.component').then(\n (m) => m.AiDescribeTemplateButton,\n ),\n)\nconst AiDescribeEmailButton = lazyWidget('AiDescribeEmailButton', () =>\n import('./components/ai-describe-email.component').then(\n (m) => m.AiDescribeEmailButton,\n ),\n)\nconst AiExperimentResultCard = lazyWidget('AiExperimentResultCard', () =>\n import('./components/ai-experiment-cards.component').then(\n (m) => m.AiExperimentResultCard,\n ),\n)\nconst AiExperimentVariantsCard = lazyWidget('AiExperimentVariantsCard', () =>\n import('./components/ai-experiment-cards.component').then(\n (m) => m.AiExperimentVariantsCard,\n ),\n)\nconst AiExplainAutomation = lazyWidget('AiExplainAutomation', () =>\n import('./components/ai-explain-automation.component').then(\n (m) => m.AiExplainAutomation,\n ),\n)\nconst AiExplainRunFailure = lazyWidget('AiExplainRunFailure', () =>\n import('./components/ai-explain-automation.component').then(\n (m) => m.AiExplainRunFailure,\n ),\n)\nconst AiCreateCampaignButton = lazyWidget('AiCreateCampaignButton', () =>\n import('./components/ai-campaign-create.component').then((m) => m.default),\n)\nconst AiMarketingInsightButton = lazyWidget('AiMarketingInsightButton', () =>\n import('./components/ai-marketing-insight.component').then((m) => m.default),\n)\nconst AiCreateOverlayButton = lazyWidget('AiCreateOverlayButton', () =>\n import('./components/ai-overlay-cards.component').then(\n (m) => m.AiCreateOverlayButton,\n ),\n)\nconst AiOverlayEditorCard = lazyWidget('AiOverlayEditorCard', () =>\n import('./components/ai-overlay-cards.component').then(\n (m) => m.AiOverlayEditorCard,\n ),\n)\nconst AiProductCopyCard = lazyWidget('AiProductCopyCard', () =>\n import('./components/ai-product-copy-card.component').then((m) => m.default),\n)\nconst AiProductImportOption = lazyWidget('AiProductImportOption', () =>\n import('./components/ai-product-import-option.component').then(\n (m) => m.default,\n ),\n)\nconst AiProductsHubCard = lazyWidget('AiProductsHubCard', () =>\n import('./components/ai-products-hub-card.component').then((m) => m.default),\n)\nconst AiCreateProductsButton = lazyWidget('AiCreateProductsButton', () =>\n import('./components/ai-products-create-button.component').then(\n (m) => m.default,\n ),\n)\nconst AiJobsPage = lazyWidget(\n 'AiJobsPage',\n () => import('./components/ai-jobs-page.component').then((m) => m.default),\n PAGE_LOADING,\n)\n\n/**\n * The Aglyn AI plugin's console half (AGL-2939): the assistant dock, the\n * besigner copy assistant's provider, the billing, member and staff cards,\n * the member tables' credit columns and the Assist signal staff page — each\n * mounted through a shell-owned zone (AGL-2940) or the staff area's generic\n * route, so no console page imports this plugin.\n *\n * No `featureFlag` on the extension: the plugin's doors are gated one by\n * one — the dock reads the `release_assist` verdict the shell hands it, the\n * generative doors answer 404 behind `release_ai_generative`, the billing\n * cards render only where the plan sells a band — and a flag here would\n * switch off the released doors with the unreleased ones.\n */\nexport function registerAiConsole(): void {\n registerAiDeclarations()\n registerConsoleExtension({\n pluginId: AI_PLUGIN_ID,\n displayName: 'AI',\n // The besigner copy assistant (AGL-89/419): mounted by the shell around\n // every console page, and opened by this plugin's besigner controls.\n providers: [AiAssistProviderOnHost],\n // The Assist docs-gap and cost board (AGL-1860, AGL-2252), at the staff\n // URL and under the tab it has always had.\n staffPages: [\n {\n id: 'assist-signals',\n label: 'Assist signal',\n header: {\n // The configured brand, not ours (AGL-2153/2260): a white-label\n // deployment and a self-host operator both read this header.\n title: `${PLATFORM_BRAND_NAME} Assist Signal`,\n docsTopic: 'assistSignals',\n },\n Component: AssistSignalsPage,\n },\n ],\n // A site's AI jobs (AGL-3596), an address under the site and no tab:\n // `/ai-jobs` lists them, and `/ai-jobs/{jobId}` is one job's page —\n // \"Building your site\" (AGL-3594), where the guided start lands a person\n // and where a site job's notification opens. The `href` is a literal,\n // `AI_SITE_BUILD_HREF`'s value, because the tab-title manifest is read\n // from this source (`ai-jobs-page.spec.tsx` holds the two equal).\n navItems: [\n {\n label: 'AI jobs',\n href: '/ai-jobs',\n recordTitle: 'Building your site',\n header: { title: 'AI jobs', docsTopic: 'aiJobsAndActivity', docsAnchor: '#the-ai-jobs-page' },\n unlisted: true,\n ownsSubtree: true,\n permission: 'ai.generate',\n Component: AiJobsPage,\n },\n ],\n widgets: [\n {\n slot: 'consoleDock',\n widgetId: 'ai-assist-dock',\n title: 'Assistant',\n Component: AssistPanelOnHost,\n },\n // The AI jobs indicator (AGL-3593), beside the notifications bell on\n // every page: what the workspace's jobs are doing, and the way to them.\n // Gated as the other generative widgets are; it asks the shell for the\n // release flags of the jobs and of the panel it opens.\n {\n slot: 'consoleTopBar',\n widgetId: 'ai-jobs-indicator',\n title: 'AI jobs',\n featureFlag: 'aiGenerative',\n permission: 'ai.generate',\n Component: AiJobsTopBarIndicator,\n },\n {\n slot: 'orgBillingUsage',\n widgetId: 'ai-credits-meter',\n title: 'AI credits',\n Component: AiCreditsCard,\n },\n {\n slot: 'orgBillingUsage',\n widgetId: 'ai-credits-overage',\n title: 'AI credits overage',\n Component: BillingAssistOverageCard,\n },\n // The per-member usage (AGL-2928): who drew the credits the meter\n // counts, on Billing → Usage, on each member's page, on the staff\n // user page, and as a column of both member tables.\n {\n slot: 'orgBillingUsage',\n widgetId: 'ai-usage-by-member',\n title: 'Who is generating what',\n permission: 'billing.view',\n Component: AiTopUsersCard,\n },\n // The collaborators table's AI column (AGL-2927): whether each person\n // may open the AI doors on the site, per site, ahead of the columns\n // that report what they drew.\n {\n slot: 'hostMembers',\n widgetId: 'ai-collaborator-permissions',\n title: 'AI',\n column: { header: 'AI' },\n Component: AiCollaboratorPermissionsCell,\n },\n // The copy assistant's besigner controls (AGL-89, AGL-169): Generate a\n // section on every editor's toolbar, and Rewrite with AI under the\n // selected element's fields. Each opens the provider's dialog, and is\n // drawn only while the reader holds the door's permission.\n {\n slot: 'besignerToolbar',\n widgetId: 'ai-generate-section',\n title: 'Generate a section with AI',\n Component: AiGenerateSectionControl,\n },\n {\n slot: 'besignerInspector',\n widgetId: 'ai-rewrite-copy',\n title: 'Rewrite with AI',\n Component: AiRewriteControl,\n },\n // Save the selection as a reusable component (AGL-2908): the component\n // job's second entry point, which proposes the properties a section\n // should declare and applies them as the manual promote does.\n {\n slot: 'besignerInspector',\n widgetId: 'ai-save-as-component',\n title: 'Make a reusable component with AI',\n permission: 'ai.generate',\n Component: AiSaveAsComponent,\n },\n {\n slot: 'orgMember',\n widgetId: 'ai-member-usage',\n title: 'AI usage',\n Component: MemberAiUsageCard,\n },\n // The allotments (AGL-2942): a member's or a site's monthly share of\n // the pool, set on Billing → Usage, on each member's page and on a\n // site's collaborators card — each card asks the route what its\n // reader may see and change.\n {\n slot: 'orgBillingUsage',\n widgetId: 'ai-allotments',\n title: 'AI allotments',\n permission: 'billing.view',\n Component: AiAllotmentsCard,\n },\n {\n slot: 'orgMember',\n widgetId: 'ai-member-allotment',\n title: 'AI allotment',\n Component: MemberAiAllotmentCard,\n },\n {\n slot: 'hostMembers',\n widgetId: 'ai-collaborator-allotment',\n title: 'AI allotment',\n column: {\n header: 'AI allotment',\n align: 'right',\n Header: AiCollaboratorAllotmentHeader,\n },\n Component: AiCollaboratorAllotmentCell,\n },\n {\n slot: 'hostMembers',\n widgetId: 'ai-site-allotment',\n title: 'Site AI allotment',\n Component: AiSiteAllotmentCard,\n },\n // Themes by AI (AGL-2938): a brief on the site's Theme section, a\n // proposal previewed before and after, and the editor's own Save to\n // keep it. Generation is sold as `aiGenerative` and held by\n // `ai.generate`, so the shell withholds the card from a plan or a\n // member without either; the card itself asks the route about the\n // release flag before it shows anything.\n {\n slot: 'hostTheme',\n widgetId: 'ai-theme-proposal',\n title: 'Theme assistant',\n featureFlag: 'aiGenerative',\n permission: 'ai.generate',\n Component: AiThemeProposalCard,\n },\n {\n slot: 'staffOrg',\n widgetId: 'ai-org-usage',\n title: 'AI usage',\n Component: StaffOrgAiCard,\n },\n {\n slot: 'staffOrg',\n widgetId: 'ai-org-conversations',\n title: `${PLATFORM_BRAND_NAME} AI requests`,\n Component: StaffOrgAiConversations,\n },\n {\n slot: 'staffUser',\n widgetId: 'ai-account-usage',\n title: 'AI usage across organizations',\n Component: StaffUserAiUsageCard,\n },\n // The same card for one account, across every org it asked in\n // (AGL-3660); the slot passes `uid`, which puts it in account mode.\n {\n slot: 'staffUser',\n widgetId: 'ai-account-requests',\n title: `${PLATFORM_BRAND_NAME} AI requests`,\n Component: StaffOrgAiConversations,\n },\n // The staff tables' AI figures (AGL-2984): the Organizations list's\n // spend column, and the usage table's three columns with the credit\n // pool line the org page draws above it.\n {\n slot: 'staffOrgsListColumn',\n widgetId: 'ai-orgs-spend',\n title: 'AI spend (month)',\n column: {\n header: 'AI spend (month)',\n align: 'right',\n Header: StaffOrgsAiSpendHeader,\n },\n Component: StaffOrgsAiSpendCell,\n },\n {\n slot: 'staffOrgUsageColumn',\n widgetId: 'ai-usage-assist-cost',\n title: 'Assist',\n column: { header: 'Assist', align: 'right' },\n Component: StaffOrgUsageAssistCell,\n },\n {\n slot: 'staffOrgUsageColumn',\n widgetId: 'ai-usage-credits',\n title: 'AI credits used',\n column: { header: 'AI credits used', align: 'right' },\n Component: StaffOrgUsageAiCreditsCell,\n },\n {\n slot: 'staffOrgUsageColumn',\n widgetId: 'ai-usage-overage',\n title: 'AI overage billed ($)',\n column: { header: 'AI overage billed ($)', align: 'right' },\n Component: StaffOrgUsageAiOverageCell,\n },\n {\n slot: 'staffOrgUsageColumn',\n widgetId: 'ai-usage-pool',\n title: 'AI credit pool',\n Component: StaffOrgUsageAiPool,\n },\n {\n slot: 'orgMembersListColumn',\n widgetId: 'ai-member-credits',\n title: 'AI credits (month)',\n column: { header: 'AI credits (month)', align: 'right', Header: AiMemberCreditsHeader },\n Component: AiMemberCreditsCell,\n },\n {\n slot: 'hostMembers',\n widgetId: 'ai-collaborator-credits',\n title: 'AI credits (site, month)',\n column: {\n header: 'AI credits (site, month)',\n align: 'right',\n Header: AiCollaboratorCreditsHeader,\n },\n Component: AiCollaboratorCreditsCell,\n },\n // SEO by AI (AGL-2910): \"Write SEO\" inside every search listing editor\n // — a page's SEO card and a product's listing — and the site audit on\n // the site's SEO section. Generation is sold as `aiGenerative` and held\n // by `ai.generate`, so the shell withholds both from a plan or a member\n // without either; each card asks the jobs route about the release flag\n // before it shows anything, and neither ever writes what it proposes.\n {\n slot: 'seoFields',\n widgetId: 'ai-seo-fields',\n title: 'SEO assistant',\n featureFlag: 'aiGenerative',\n permission: 'ai.generate',\n Component: AiSeoFieldsCard,\n },\n {\n slot: 'hostSeo',\n widgetId: 'ai-seo-audit',\n title: 'SEO audit',\n featureFlag: 'aiGenerative',\n permission: 'ai.generate',\n Component: AiSeoAuditCard,\n },\n // A page from a brief (AGL-2907): \"Create with AI\" beside Templates and\n // Create New Screen. Gated as the other generative widgets are.\n // On a plan that could buy the AI add-on and has not, each \"Create with\n // AI\" entry here is mounted anyway (`showWhenNotEntitled`) and opens\n // the add-on's dialog instead of the brief (AGL-3601). The shell holds\n // each behind `release_ai_generative` too, so an entry draws at once\n // and asks the jobs route nothing until its brief is sent.\n {\n slot: 'hostScreens',\n widgetId: 'ai-describe-page',\n title: 'Describe a page',\n featureFlag: 'aiGenerative',\n permission: 'ai.generate',\n showWhenNotEntitled: true,\n releaseFlag: 'release_ai_generative',\n Component: AiDescribePageButton,\n },\n // The same entry for a page template, a layout and a form (AGL-3043),\n // beside the create action of the page that lists each: the same\n // dialog and the same gates.\n {\n slot: 'hostTemplates',\n widgetId: 'ai-describe-template',\n title: 'Describe a page template',\n featureFlag: 'aiGenerative',\n permission: 'ai.generate',\n showWhenNotEntitled: true,\n releaseFlag: 'release_ai_generative',\n Component: AiDescribeTemplateButton,\n },\n {\n slot: 'hostLayouts',\n widgetId: 'ai-describe-layout',\n title: 'Describe a layout',\n featureFlag: 'aiGenerative',\n permission: 'ai.generate',\n showWhenNotEntitled: true,\n releaseFlag: 'release_ai_generative',\n Component: AiDescribeLayoutButton,\n },\n {\n slot: 'hostForms',\n widgetId: 'ai-describe-form',\n title: 'Describe a form',\n featureFlag: 'aiGenerative',\n permission: 'ai.generate',\n showWhenNotEntitled: true,\n releaseFlag: 'release_ai_generative',\n Component: AiDescribeFormButton,\n },\n // And a reusable component from a brief (AGL-3051), beside Templates\n // and Create Component: the component job's first entry point, which\n // had none in the console.\n // Pictures from a description (AGL-3602): \"Create with AI\" beside Upload\n // media in the media library, and in its empty state. Gated as the\n // other generative widgets are, by the shell alone: it asks nothing of\n // a server until someone creates a picture, and the door decides then.\n // Like every Create with AI entry it is mounted without the add-on too\n // and opens its own upsell there (AGL-3601).\n {\n slot: 'mediaLibrary',\n widgetId: 'ai-media-create',\n title: 'Create images with AI',\n featureFlag: 'aiGenerative',\n permission: 'ai.generate',\n showWhenNotEntitled: true,\n releaseFlag: 'release_ai_generative',\n Component: AiMediaCreateButton,\n },\n {\n slot: 'hostComponents',\n widgetId: 'ai-describe-component',\n title: 'Describe a reusable component',\n featureFlag: 'aiGenerative',\n permission: 'ai.generate',\n showWhenNotEntitled: true,\n releaseFlag: 'release_ai_generative',\n Component: AiDescribeComponentButton,\n },\n // An email design from a brief (AGL-3596), beside New template on a\n // site's email templates — the zone the email plugin hosts. Its dialog\n // also offers the draft campaign that would send it; the Campaigns\n // section's own door is `ai-create-campaign`, below.\n {\n slot: 'hostEmailTemplates',\n widgetId: 'ai-describe-email',\n title: 'Describe an email',\n featureFlag: 'aiGenerative',\n permission: 'ai.generate',\n showWhenNotEntitled: true,\n releaseFlag: 'release_ai_generative',\n Component: AiDescribeEmailButton,\n },\n // Automations by AI (AGL-2919), in the zones the workflows plugin hosts\n // on its Automation page: \"Create with AI\" beside Add action and Recipes,\n // \"Explain it\" in the editor of a saved automation, and \"Why did this\n // fail?\" on a failed run. Gated as the other generative widgets are,\n // the release flag included, by the shell alone (AGL-3601): none asks\n // the jobs route anything until it is used, and none of them changes an\n // automation.\n {\n slot: 'hostAutomations',\n widgetId: 'ai-describe-automation',\n title: 'Describe an automation',\n featureFlag: 'aiGenerative',\n permission: 'ai.generate',\n showWhenNotEntitled: true,\n releaseFlag: 'release_ai_generative',\n Component: AiDescribeAutomationButton,\n },\n // Funnels by AI (AGL-3605), in the zones the funnels plugin hosts on\n // its card: a draft from a description, and its results explained.\n {\n slot: 'funnelsCreate',\n widgetId: 'ai-describe-funnel',\n title: 'Describe a funnel',\n featureFlag: 'aiGenerative',\n permission: 'ai.generate',\n showWhenNotEntitled: true,\n releaseFlag: 'release_ai_generative',\n Component: AiFunnelCreateButton,\n },\n {\n slot: 'funnelInsight',\n widgetId: 'ai-explain-funnel',\n title: 'Ask AI about this funnel',\n featureFlag: 'aiGenerative',\n permission: 'ai.generate',\n showWhenNotEntitled: true,\n releaseFlag: 'release_ai_generative',\n Component: AiFunnelAskButton,\n },\n {\n slot: 'automationEditor',\n widgetId: 'ai-explain-automation',\n title: 'Explain this automation',\n featureFlag: 'aiGenerative',\n permission: 'ai.generate',\n releaseFlag: 'release_ai_generative',\n Component: AiExplainAutomation,\n },\n // \"Change with AI\" and \"Fix with AI\" in a saved action's editor\n // (AGL-3603): a changed copy drafted OFF beside it, never the saved\n // action written in place.\n {\n slot: 'automationEditor',\n widgetId: 'ai-revise-automation',\n title: 'Change this automation with AI',\n featureFlag: 'aiGenerative',\n permission: 'ai.generate',\n releaseFlag: 'release_ai_generative',\n Component: AiReviseAutomation,\n },\n // \"Create with AI\" on the workspace's Org automations (AGL-3603): one\n // of the workspace's automations drafted from a description and opened\n // in that section's editor, unsaved and switched off.\n {\n slot: 'orgAutomations',\n widgetId: 'ai-describe-org-automation',\n title: 'Describe an org automation',\n featureFlag: 'aiGenerative',\n permission: 'ai.generate',\n showWhenNotEntitled: true,\n releaseFlag: 'release_ai_generative',\n Component: AiDescribeOrgAutomationButton,\n },\n // \"Ask AI about these numbers\" (AGL-3603): a tile on a site's\n // dashboard and Analytics page, which both draw `hostDashboard`, and on\n // the workspace's sites page. It opens the insight dialog the Assist\n // panel opens, gated as every generative widget is.\n {\n slot: 'hostDashboard',\n widgetId: 'ai-insight-ask',\n title: 'Ask AI about these numbers',\n featureFlag: 'aiGenerative',\n permission: 'ai.generate',\n showWhenNotEntitled: true,\n releaseFlag: 'release_ai_generative',\n Component: AiInsightHostCard,\n },\n {\n slot: 'orgDashboard',\n widgetId: 'ai-insight-ask',\n title: 'Ask AI about these numbers',\n featureFlag: 'aiGenerative',\n permission: 'ai.generate',\n showWhenNotEntitled: true,\n releaseFlag: 'release_ai_generative',\n Component: AiInsightOrgCard,\n },\n // Logic by AI (AGL-3603), in the zones the logic plugin hosts on its\n // Functions & Variables page: Create with AI in the Functions and\n // Variables card headers, Explain / Change / Fix in a saved function's\n // editor, and Fix with AI on a broken reference an automation holds.\n // Each proposal opens unsaved in the logic editor; none is saved here.\n {\n slot: 'hostLogic',\n widgetId: 'ai-describe-logic',\n title: 'Describe a function or variable',\n featureFlag: 'aiGenerative',\n permission: 'ai.generate',\n showWhenNotEntitled: true,\n releaseFlag: 'release_ai_generative',\n Component: AiLogicCreateButton,\n },\n {\n slot: 'logicFunctionEditor',\n widgetId: 'ai-logic-function',\n title: 'This function with AI',\n featureFlag: 'aiGenerative',\n permission: 'ai.generate',\n releaseFlag: 'release_ai_generative',\n Component: AiLogicFunctionTools,\n },\n {\n slot: 'logicReferenceIssue',\n widgetId: 'ai-logic-fix-reference',\n title: 'Fix this reference with AI',\n featureFlag: 'aiGenerative',\n permission: 'ai.generate',\n releaseFlag: 'release_ai_generative',\n Component: AiLogicFixReference,\n },\n {\n slot: 'automationRun',\n widgetId: 'ai-explain-run-failure',\n title: 'Why did this run fail?',\n featureFlag: 'aiGenerative',\n permission: 'ai.generate',\n releaseFlag: 'release_ai_generative',\n Component: AiExplainRunFailure,\n },\n // CRM by AI (AGL-2917): a record's summary and next step on its page,\n // a draft in the one-to-one composer, and an import's column matches.\n // The CRM hosts each zone, so it is drawn only where the CRM is; the\n // shell holds the plan and `ai.generate`, each card asks the jobs route\n // about the release flag before it shows anything, and none writes what\n // it proposes.\n {\n slot: 'recordInsights',\n widgetId: 'ai-crm-record',\n title: 'AI summary',\n featureFlag: 'aiGenerative',\n permission: 'ai.generate',\n Component: AiCrmRecordCard,\n },\n {\n slot: 'recordEmail',\n widgetId: 'ai-crm-email',\n title: 'Draft with AI',\n featureFlag: 'aiGenerative',\n permission: 'ai.generate',\n Component: AiCrmEmailDraft,\n },\n {\n slot: 'importMapping',\n widgetId: 'ai-crm-import-mapping',\n title: 'Match columns with AI',\n featureFlag: 'aiGenerative',\n permission: 'ai.generate',\n Component: AiCrmImportMapping,\n },\n // The guided start (AGL-2918), on the page a newly created site lands\n // on: a few questions that become a site scaffold. Gated as the other\n // generative widgets are, and it asks the jobs route about the release\n // flag before it shows anything — so a workspace the feature is not\n // released to gets the blank page and nothing else. Skipping is the\n // zone's own `startBlank`, which creates nothing.\n {\n slot: 'hostFirstRun',\n widgetId: 'ai-site-start',\n title: 'Start this site with AI',\n featureFlag: 'aiGenerative',\n permission: 'ai.generate',\n Component: AiSiteStartCard,\n },\n // The listing those answers describe (AGL-2918), on the site's SEO\n // section: the site-wide search title and description the guided start\n // implies, offered where they are edited. The same gates as every\n // generative widget, and it stages into the SEO form rather than\n // writing it — a person's Update is the write, as it is for the audit\n // card beside it.\n {\n slot: 'hostSeo',\n widgetId: 'ai-site-seo-start',\n title: 'The listing your answers describe',\n featureFlag: 'aiGenerative',\n permission: 'ai.generate',\n Component: AiSiteSeoStartCard,\n },\n // What Aglyn AI learned from the site's applied edits (AGL-3661), on\n // Setup → Business profile, where the owner reads and forgets it. No\n // generate permission: reading and clearing what the AI keeps about a\n // site is every editor's, and the rules hold the write to the server.\n {\n slot: 'hostBusinessProfile',\n widgetId: 'ai-site-memory',\n title: `What ${aiAddonName()} learned`,\n featureFlag: 'aiGenerative',\n Component: AiSiteMemoryCard,\n },\n // The agency batch (AGL-2911): one brief across many of the org's\n // sites, from the page that lists them. The card asks the jobs route\n // about the release flag before it shows anything, and its own door\n // holds the plan band and the caller's permission on every site it is\n // pointed at.\n {\n slot: 'orgSites',\n widgetId: 'ai-site-batch',\n title: 'Generate sites with AI',\n featureFlag: 'aiGenerative',\n permission: 'ai.generate',\n Component: AiSiteBatchCard,\n },\n // Commerce by AI (AGL-2916): product copy in the product editor, the\n // catalog, categories and discounts on the products hub, and copy for\n // an import as it lands. The commerce plugin hosts the zones and makes\n // every write. The shell holds the release flag; the products hub card\n // reads its recent proposals before it draws its own controls, but\n // offers the \"Create with AI\" door's brief from the moment it mounts.\n {\n slot: 'productEditor',\n widgetId: 'ai-product-copy',\n title: 'Product copy assistant',\n featureFlag: 'aiGenerative',\n permission: 'ai.generate',\n Component: AiProductCopyCard,\n },\n {\n slot: 'productsHub',\n widgetId: 'ai-products-hub',\n title: 'Build your catalog with AI',\n featureFlag: 'aiGenerative',\n permission: 'ai.generate',\n releaseFlag: 'release_ai_generative',\n Component: AiProductsHubCard,\n },\n // \"Create with AI\" beside Add product and in the empty catalog\n // (AGL-3596): a door to the card's Propose products brief, shown only\n // while that card is on the page to take it.\n {\n slot: 'productsCreate',\n widgetId: 'ai-products-create',\n title: 'Propose products',\n featureFlag: 'aiGenerative',\n permission: 'ai.generate',\n showWhenNotEntitled: true,\n releaseFlag: 'release_ai_generative',\n Component: AiCreateProductsButton,\n },\n {\n slot: 'productImport',\n widgetId: 'ai-product-import',\n title: 'Write imported product copy with AI',\n featureFlag: 'aiGenerative',\n permission: 'ai.generate',\n Component: AiProductImportOption,\n },\n // A/B tests by AI (AGL-2914): variants written in the experiment\n // editor, and one test's result read in plain words below its figures.\n // The A/B testing card hosts both zones, so they are drawn only where\n // that card is and only on a site with A/B testing; the shell holds the\n // plan band, `ai.generate` and the release flag, and neither card asks\n // the jobs route anything until it is used (AGL-3601). Neither writes: the\n // experiment editor's Save is the only write, and an explanation has\n // nothing to apply.\n {\n slot: 'experimentVariants',\n widgetId: 'ai-experiment-variants',\n title: 'Write variants with AI',\n featureFlag: 'aiGenerative',\n permission: 'ai.generate',\n releaseFlag: 'release_ai_generative',\n Component: AiExperimentVariantsCard,\n },\n {\n slot: 'experimentResult',\n widgetId: 'ai-experiment-result',\n title: 'Explain this result with AI',\n featureFlag: 'aiGenerative',\n permission: 'ai.generate',\n releaseFlag: 'release_ai_generative',\n Component: AiExperimentResultCard,\n },\n // Overlays by AI (AGL-3603), in the zones the marketing plugin's\n // overlays list hosts: \"Create with AI\" beside New bar and New popup,\n // and \"Write with AI\" among the overlay editor's fields. Both start a\n // `text` job asked for overlay copy; neither writes — the list saves a\n // created overlay switched off, and the editor's Save is the write.\n {\n slot: 'hostOverlays',\n widgetId: 'ai-create-overlay',\n title: 'Create an overlay with AI',\n featureFlag: 'aiGenerative',\n permission: 'ai.generate',\n showWhenNotEntitled: true,\n releaseFlag: 'release_ai_generative',\n Component: AiCreateOverlayButton,\n },\n {\n slot: 'overlayEditor',\n widgetId: 'ai-overlay-copy',\n title: 'Write overlay copy with AI',\n featureFlag: 'aiGenerative',\n permission: 'ai.generate',\n releaseFlag: 'release_ai_generative',\n Component: AiOverlayEditorCard,\n },\n // A campaign from a brief (AGL-3603), beside Create campaign on the\n // Campaigns section the marketing plugin hosts: the `campaign` job's\n // first console door, or the `email` job's where the plan sends no\n // campaign email. Both write drafts that are aimed at nobody and sent\n // by nobody until a member does.\n {\n slot: 'hostCampaigns',\n widgetId: 'ai-create-campaign',\n title: 'Create a campaign with AI',\n featureFlag: 'aiGenerative',\n permission: 'ai.generate',\n showWhenNotEntitled: true,\n releaseFlag: 'release_ai_generative',\n Component: AiCreateCampaignButton,\n },\n // The figures in words (AGL-3603), in the header of the Conversions\n // section and of one campaign's report: the insight dialog the Assist\n // panel opens, on the Marketing surface, for the site the figures are.\n // It reads and cites; it changes nothing.\n {\n slot: 'marketingInsights',\n widgetId: 'ai-marketing-insight',\n title: 'Ask AI about these numbers',\n featureFlag: 'aiGenerative',\n permission: 'ai.generate',\n showWhenNotEntitled: true,\n releaseFlag: 'release_ai_generative',\n Component: AiMarketingInsightButton,\n },\n ],\n })\n}\n"],"names":["PLATFORM_BRAND_NAME","aiAddonName","registerConsoleExtension","LinearProgress","createElement","AiAssistProviderOnHost","AI_PLUGIN_ID","registerAiDeclarations","lazyWidget","PAGE_LOADING","AiCollaboratorPermissionsCell","then","m","AiSaveAsComponent","AiGenerateSectionControl","AiRewriteControl","AssistPanelOnHost","AiCreditsCard","default","AiJobsTopBarIndicator","AiCollaboratorCreditsCell","AiCollaboratorCreditsHeader","AiMemberCreditsCell","AiMemberCreditsHeader","AssistSignalsPage","BillingAssistOverageCard","AiTopUsersCard","AiAllotmentsCard","AiCollaboratorAllotmentCell","AiCollaboratorAllotmentHeader","AiSiteAllotmentCard","MemberAiAllotmentCard","MemberAiUsageCard","AiThemeProposalCard","StaffOrgAiCard","StaffOrgAiConversations","StaffOrgUsageAiCreditsCell","StaffOrgUsageAiOverageCell","StaffOrgUsageAiPool","StaffOrgUsageAssistCell","StaffOrgsAiSpendCell","StaffOrgsAiSpendHeader","StaffUserAiUsageCard","AiSeoAuditCard","AiSiteBatchCard","AiSiteSeoStartCard","AiSiteMemoryCard","AiSiteStartCard","AiSeoFieldsCard","AiDescribeAutomationButton","AiReviseAutomation","AiDescribeOrgAutomationButton","AiInsightHostCard","AiInsightOrgCard","AiLogicCreateButton","AiLogicFixReference","AiLogicFunctionTools","AiFunnelAskButton","AiFunnelCreateButton","AiCrmEmailDraft","AiCrmImportMapping","AiCrmRecordCard","AiDescribePageButton","AiMediaCreateButton","AiDescribeComponentButton","AiDescribeFormButton","AiDescribeLayoutButton","AiDescribeTemplateButton","AiDescribeEmailButton","AiExperimentResultCard","AiExperimentVariantsCard","AiExplainAutomation","AiExplainRunFailure","AiCreateCampaignButton","AiMarketingInsightButton","AiCreateOverlayButton","AiOverlayEditorCard","AiProductCopyCard","AiProductImportOption","AiProductsHubCard","AiCreateProductsButton","AiJobsPage","registerAiConsole","pluginId","displayName","providers","staffPages","id","label","header","title","docsTopic","Component","navItems","href","recordTitle","docsAnchor","unlisted","ownsSubtree","permission","widgets","slot","widgetId","featureFlag","column","align","Header","showWhenNotEntitled","releaseFlag"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../../../../../libs/plugins/ai/src/lib/plugin.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 { PLATFORM_BRAND_NAME, aiAddonName, registerConsoleExtension } from '@aglyn/aglyn'\nimport { LinearProgress } from '@mui/material'\nimport { createElement } from 'react'\nimport { AiAssistProviderOnHost } from './components/ai-assist-provider-on-host.component'\nimport { AI_PLUGIN_ID } from './constants'\nimport { registerAiDeclarations } from './declarations'\nimport { lazyWidget } from './lazy-widget'\n\n/*\n * Every component below is registered by name and loaded the first time the\n * shell draws it (AGL-3649); see `lazyWidget`. The console loads this plugin\n * on every screen, so a static import of a component here is downloaded by\n * every reader of every page, staff cards included.\n */\n\n/** What a page shows while its code arrives. */\nconst PAGE_LOADING = createElement(LinearProgress, { 'aria-label': 'Loading' })\n\nconst AiSaveAsComponent = lazyWidget('AiSaveAsComponent', () =>\n import('./components/ai-save-as-component.component').then(\n (m) => m.AiSaveAsComponent,\n ),\n)\nconst AiGenerateSectionControl = lazyWidget('AiGenerateSectionControl', () =>\n import('./components/besigner-ai-controls.component').then(\n (m) => m.AiGenerateSectionControl,\n ),\n)\nconst AiRewriteControl = lazyWidget('AiRewriteControl', () =>\n import('./components/besigner-ai-controls.component').then(\n (m) => m.AiRewriteControl,\n ),\n)\nconst AssistPanelOnHost = lazyWidget('AssistPanelOnHost', () =>\n import('./components/ai-permissions-on-host.component').then(\n (m) => m.AssistPanelOnHost,\n ),\n)\nconst AiCreditsCard = lazyWidget('AiCreditsCard', () =>\n import('./components/ai-credits-card.component').then((m) => m.default),\n)\nconst AiJobsTopBarIndicator = lazyWidget('AiJobsTopBarIndicator', () =>\n import('./components/ai-jobs-indicator.component').then((m) => m.default),\n)\nconst AiCollaboratorCreditsCell = lazyWidget('AiCollaboratorCreditsCell', () =>\n import('./components/ai-credits-columns.component').then(\n (m) => m.AiCollaboratorCreditsCell,\n ),\n)\nconst AiCollaboratorCreditsHeader = lazyWidget(\n 'AiCollaboratorCreditsHeader',\n () =>\n import('./components/ai-credits-columns.component').then(\n (m) => m.AiCollaboratorCreditsHeader,\n ),\n)\nconst AiMemberCreditsCell = lazyWidget('AiMemberCreditsCell', () =>\n import('./components/ai-credits-columns.component').then(\n (m) => m.AiMemberCreditsCell,\n ),\n)\nconst AiMemberCreditsHeader = lazyWidget('AiMemberCreditsHeader', () =>\n import('./components/ai-credits-columns.component').then(\n (m) => m.AiMemberCreditsHeader,\n ),\n)\nconst AssistSignalsPage = lazyWidget(\n 'AssistSignalsPage',\n () =>\n import('./components/assist-signals-page.component').then(\n (m) => m.AssistSignalsPage,\n ),\n PAGE_LOADING,\n)\nconst BillingAssistOverageCard = lazyWidget('BillingAssistOverageCard', () =>\n import('./components/billing-assist-overage-card.component').then(\n (m) => m.default,\n ),\n)\nconst AiTopUsersCard = lazyWidget('AiTopUsersCard', () =>\n import('./components/billing-ai-top-users.component').then(\n (m) => m.AiTopUsersCard,\n ),\n)\nconst AiAllotmentsCard = lazyWidget('AiAllotmentsCard', () =>\n import('./components/billing-ai-allotments.component').then(\n (m) => m.AiAllotmentsCard,\n ),\n)\nconst AiCollaboratorAllotmentCell = lazyWidget(\n 'AiCollaboratorAllotmentCell',\n () =>\n import('./components/host-ai-allotments.component').then(\n (m) => m.AiCollaboratorAllotmentCell,\n ),\n)\nconst AiCollaboratorAllotmentHeader = lazyWidget(\n 'AiCollaboratorAllotmentHeader',\n () =>\n import('./components/host-ai-allotments.component').then(\n (m) => m.AiCollaboratorAllotmentHeader,\n ),\n)\nconst AiSiteAllotmentCard = lazyWidget('AiSiteAllotmentCard', () =>\n import('./components/host-ai-allotments.component').then(\n (m) => m.AiSiteAllotmentCard,\n ),\n)\nconst MemberAiAllotmentCard = lazyWidget('MemberAiAllotmentCard', () =>\n import('./components/member-ai-allotment-card.component').then(\n (m) => m.default,\n ),\n)\nconst MemberAiUsageCard = lazyWidget('MemberAiUsageCard', () =>\n import('./components/member-ai-usage-card.component').then((m) => m.default),\n)\nconst AiThemeProposalCard = lazyWidget('AiThemeProposalCard', () =>\n import('./components/ai-theme-proposal-card.component').then(\n (m) => m.default,\n ),\n)\nconst StaffOrgAiCard = lazyWidget('StaffOrgAiCard', () =>\n import('./components/staff-org-ai-card.component').then((m) => m.default),\n)\nconst StaffOrgAiConversations = lazyWidget('StaffOrgAiConversations', () =>\n import('./components/staff-org-ai-conversations.component').then((m) => m.default),\n)\nconst StaffOrgUsageAiCreditsCell = lazyWidget(\n 'StaffOrgUsageAiCreditsCell',\n () =>\n import('./components/staff-org-usage-ai-columns.component').then(\n (m) => m.StaffOrgUsageAiCreditsCell,\n ),\n)\nconst StaffOrgUsageAiOverageCell = lazyWidget(\n 'StaffOrgUsageAiOverageCell',\n () =>\n import('./components/staff-org-usage-ai-columns.component').then(\n (m) => m.StaffOrgUsageAiOverageCell,\n ),\n)\nconst StaffOrgUsageAiPool = lazyWidget('StaffOrgUsageAiPool', () =>\n import('./components/staff-org-usage-ai-columns.component').then(\n (m) => m.StaffOrgUsageAiPool,\n ),\n)\nconst StaffOrgUsageAssistCell = lazyWidget('StaffOrgUsageAssistCell', () =>\n import('./components/staff-org-usage-ai-columns.component').then(\n (m) => m.StaffOrgUsageAssistCell,\n ),\n)\nconst StaffOrgsAiSpendCell = lazyWidget('StaffOrgsAiSpendCell', () =>\n import('./components/staff-orgs-ai-spend-column.component').then(\n (m) => m.StaffOrgsAiSpendCell,\n ),\n)\nconst StaffOrgsAiSpendHeader = lazyWidget('StaffOrgsAiSpendHeader', () =>\n import('./components/staff-orgs-ai-spend-column.component').then(\n (m) => m.StaffOrgsAiSpendHeader,\n ),\n)\nconst StaffUserAiUsageCard = lazyWidget('StaffUserAiUsageCard', () =>\n import('./components/staff-user-ai-usage-card.component').then(\n (m) => m.default,\n ),\n)\nconst AiSeoAuditCard = lazyWidget('AiSeoAuditCard', () =>\n import('./components/ai-seo-audit-card.component').then((m) => m.default),\n)\nconst AiSiteBatchCard = lazyWidget('AiSiteBatchCard', () =>\n import('./components/ai-site-batch-card.component').then((m) => m.default),\n)\nconst AiSiteSeoStartCard = lazyWidget('AiSiteSeoStartCard', () =>\n import('./components/ai-site-seo-start-card.component').then(\n (m) => m.default,\n ),\n)\nconst AiSiteMemoryCard = lazyWidget('AiSiteMemoryCard', () =>\n import('./components/ai-site-memory-card.component').then((m) => m.default),\n)\nconst AiSiteStartCard = lazyWidget('AiSiteStartCard', () =>\n import('./components/ai-site-start-card.component').then((m) => m.default),\n)\nconst AiSeoFieldsCard = lazyWidget('AiSeoFieldsCard', () =>\n import('./components/ai-seo-fields-card.component').then((m) => m.default),\n)\nconst AiDescribeAutomationButton = lazyWidget(\n 'AiDescribeAutomationButton',\n () =>\n import('./components/ai-describe-automation.component').then(\n (m) => m.default,\n ),\n)\nconst AiReviseAutomation = lazyWidget('AiReviseAutomation', () =>\n import('./components/ai-revise-automation.component').then((m) => m.default),\n)\nconst AiDescribeOrgAutomationButton = lazyWidget(\n 'AiDescribeOrgAutomationButton',\n () =>\n import('./components/ai-describe-org-automation.component').then(\n (m) => m.default,\n ),\n)\nconst AiInsightHostCard = lazyWidget('AiInsightHostCard', () =>\n import('./components/ai-insight-card.component').then(\n (m) => m.AiInsightHostCard,\n ),\n)\nconst AiInsightOrgCard = lazyWidget('AiInsightOrgCard', () =>\n import('./components/ai-insight-card.component').then(\n (m) => m.AiInsightOrgCard,\n ),\n)\nconst AiLogicCreateButton = lazyWidget('AiLogicCreateButton', () =>\n import('./components/ai-logic.component').then((m) => m.AiLogicCreateButton),\n)\nconst AiLogicFixReference = lazyWidget('AiLogicFixReference', () =>\n import('./components/ai-logic.component').then((m) => m.AiLogicFixReference),\n)\nconst AiLogicFunctionTools = lazyWidget('AiLogicFunctionTools', () =>\n import('./components/ai-logic.component').then((m) => m.AiLogicFunctionTools),\n)\nconst AiFunnelAskButton = lazyWidget('AiFunnelAskButton', () =>\n import('./components/ai-funnel-zones.component').then(\n (m) => m.AiFunnelAskButton,\n ),\n)\nconst AiFunnelCreateButton = lazyWidget('AiFunnelCreateButton', () =>\n import('./components/ai-funnel-zones.component').then(\n (m) => m.AiFunnelCreateButton,\n ),\n)\nconst AiCrmEmailDraft = lazyWidget('AiCrmEmailDraft', () =>\n import('./components/ai-crm-email-draft.component').then((m) => m.default),\n)\nconst AiCrmImportMapping = lazyWidget('AiCrmImportMapping', () =>\n import('./components/ai-crm-import-mapping.component').then((m) => m.default),\n)\nconst AiCrmRecordCard = lazyWidget('AiCrmRecordCard', () =>\n import('./components/ai-crm-record-card.component').then((m) => m.default),\n)\nconst AiDescribePageButton = lazyWidget('AiDescribePageButton', () =>\n import('./components/ai-describe-page.component').then((m) => m.default),\n)\nconst AiMediaCreateButton = lazyWidget('AiMediaCreateButton', () =>\n import('./components/ai-media-create.component').then((m) => m.default),\n)\nconst AiDescribeComponentButton = lazyWidget('AiDescribeComponentButton', () =>\n import('./components/ai-describe-button.component').then(\n (m) => m.AiDescribeComponentButton,\n ),\n)\nconst AiDescribeFormButton = lazyWidget('AiDescribeFormButton', () =>\n import('./components/ai-describe-button.component').then(\n (m) => m.AiDescribeFormButton,\n ),\n)\nconst AiDescribeLayoutButton = lazyWidget('AiDescribeLayoutButton', () =>\n import('./components/ai-describe-button.component').then(\n (m) => m.AiDescribeLayoutButton,\n ),\n)\nconst AiDescribeTemplateButton = lazyWidget('AiDescribeTemplateButton', () =>\n import('./components/ai-describe-button.component').then(\n (m) => m.AiDescribeTemplateButton,\n ),\n)\nconst AiDescribeEmailButton = lazyWidget('AiDescribeEmailButton', () =>\n import('./components/ai-describe-email.component').then(\n (m) => m.AiDescribeEmailButton,\n ),\n)\nconst AiExperimentResultCard = lazyWidget('AiExperimentResultCard', () =>\n import('./components/ai-experiment-cards.component').then(\n (m) => m.AiExperimentResultCard,\n ),\n)\nconst AiExperimentVariantsCard = lazyWidget('AiExperimentVariantsCard', () =>\n import('./components/ai-experiment-cards.component').then(\n (m) => m.AiExperimentVariantsCard,\n ),\n)\nconst AiExplainAutomation = lazyWidget('AiExplainAutomation', () =>\n import('./components/ai-explain-automation.component').then(\n (m) => m.AiExplainAutomation,\n ),\n)\nconst AiExplainRunFailure = lazyWidget('AiExplainRunFailure', () =>\n import('./components/ai-explain-automation.component').then(\n (m) => m.AiExplainRunFailure,\n ),\n)\nconst AiCreateCampaignButton = lazyWidget('AiCreateCampaignButton', () =>\n import('./components/ai-campaign-create.component').then((m) => m.default),\n)\nconst AiMarketingInsightButton = lazyWidget('AiMarketingInsightButton', () =>\n import('./components/ai-marketing-insight.component').then((m) => m.default),\n)\nconst AiCreateOverlayButton = lazyWidget('AiCreateOverlayButton', () =>\n import('./components/ai-overlay-cards.component').then(\n (m) => m.AiCreateOverlayButton,\n ),\n)\nconst AiOverlayEditorCard = lazyWidget('AiOverlayEditorCard', () =>\n import('./components/ai-overlay-cards.component').then(\n (m) => m.AiOverlayEditorCard,\n ),\n)\nconst AiProductCopyCard = lazyWidget('AiProductCopyCard', () =>\n import('./components/ai-product-copy-card.component').then((m) => m.default),\n)\nconst AiProductImportOption = lazyWidget('AiProductImportOption', () =>\n import('./components/ai-product-import-option.component').then(\n (m) => m.default,\n ),\n)\nconst AiProductsHubCard = lazyWidget('AiProductsHubCard', () =>\n import('./components/ai-products-hub-card.component').then((m) => m.default),\n)\nconst AiCreateProductsButton = lazyWidget('AiCreateProductsButton', () =>\n import('./components/ai-products-create-button.component').then(\n (m) => m.default,\n ),\n)\nconst AiJobsPage = lazyWidget(\n 'AiJobsPage',\n () => import('./components/ai-jobs-page.component').then((m) => m.default),\n PAGE_LOADING,\n)\n\n/**\n * The Aglyn AI plugin's console half (AGL-2939): the assistant dock, the\n * besigner copy assistant's provider, the billing, member and staff cards,\n * the member tables' credit columns and the Assist signal staff page — each\n * mounted through a shell-owned zone (AGL-2940) or the staff area's generic\n * route, so no console page imports this plugin.\n *\n * No `featureFlag` on the extension: the plugin's doors are gated one by\n * one — the dock reads the `release_assist` verdict the shell hands it, the\n * generative doors answer 404 behind `release_ai_generative`, the billing\n * cards render only where the plan sells a band — and a flag here would\n * switch off the released doors with the unreleased ones.\n */\nexport function registerAiConsole(): void {\n registerAiDeclarations()\n registerConsoleExtension({\n pluginId: AI_PLUGIN_ID,\n displayName: 'AI',\n // The besigner copy assistant (AGL-89/419): mounted by the shell around\n // every console page, and opened by this plugin's besigner controls.\n providers: [AiAssistProviderOnHost],\n // The Assist docs-gap and cost board (AGL-1860, AGL-2252), at the staff\n // URL and under the tab it has always had.\n staffPages: [\n {\n id: 'assist-signals',\n label: 'Assist signal',\n header: {\n // The configured brand, not ours (AGL-2153/2260): a white-label\n // deployment and a self-host operator both read this header.\n title: `${PLATFORM_BRAND_NAME} Assist Signal`,\n docsTopic: 'assistSignals',\n },\n Component: AssistSignalsPage,\n },\n ],\n // A site's AI jobs (AGL-3596), an address under the site and no tab:\n // `/ai-jobs` lists them, and `/ai-jobs/{jobId}` is one job's page —\n // \"Building your site\" (AGL-3594), where the guided start lands a person\n // and where a site job's notification opens. The `href` is a literal,\n // `AI_SITE_BUILD_HREF`'s value, because the tab-title manifest is read\n // from this source (`ai-jobs-page.spec.tsx` holds the two equal).\n navItems: [\n {\n label: 'AI jobs',\n href: '/ai-jobs',\n recordTitle: 'Building your site',\n header: { title: 'AI jobs', docsTopic: 'aiJobsAndActivity', docsAnchor: '#the-ai-jobs-page' },\n unlisted: true,\n ownsSubtree: true,\n permission: 'ai.generate',\n Component: AiJobsPage,\n },\n ],\n widgets: [\n {\n slot: 'consoleDock',\n widgetId: 'ai-assist-dock',\n title: 'Assistant',\n Component: AssistPanelOnHost,\n },\n // The AI jobs indicator (AGL-3593), beside the notifications bell on\n // every page: what the workspace's jobs are doing, and the way to them.\n // Gated as the other generative widgets are; it asks the shell for the\n // release flags of the jobs and of the panel it opens.\n {\n slot: 'consoleTopBar',\n widgetId: 'ai-jobs-indicator',\n title: 'AI jobs',\n featureFlag: 'aiGenerative',\n permission: 'ai.generate',\n Component: AiJobsTopBarIndicator,\n },\n {\n slot: 'orgBillingUsage',\n widgetId: 'ai-credits-meter',\n title: 'AI credits',\n Component: AiCreditsCard,\n },\n {\n slot: 'orgBillingUsage',\n widgetId: 'ai-credits-overage',\n title: 'AI credits overage',\n Component: BillingAssistOverageCard,\n },\n // The per-member usage (AGL-2928): who drew the credits the meter\n // counts, on Billing → Usage, on each member's page, on the staff\n // user page, and as a column of both member tables.\n {\n slot: 'orgBillingUsage',\n widgetId: 'ai-usage-by-member',\n title: 'Who is generating what',\n permission: 'billing.view',\n Component: AiTopUsersCard,\n },\n // The collaborators table's AI toggles (AGL-2927) are the platform's\n // own per-site Permissions dialog now (AGL-4047), which draws every\n // per-site key, these two included; `/api/ai/host-permissions` stays\n // for the native apps.\n // The copy assistant's besigner controls (AGL-89, AGL-169): Generate a\n // section on every editor's toolbar, and Rewrite with AI under the\n // selected element's fields. Each opens the provider's dialog, and is\n // drawn only while the reader holds the door's permission.\n {\n slot: 'besignerToolbar',\n widgetId: 'ai-generate-section',\n title: 'Generate a section with AI',\n Component: AiGenerateSectionControl,\n },\n {\n slot: 'besignerInspector',\n widgetId: 'ai-rewrite-copy',\n title: 'Rewrite with AI',\n Component: AiRewriteControl,\n },\n // Save the selection as a reusable component (AGL-2908): the component\n // job's second entry point, which proposes the properties a section\n // should declare and applies them as the manual promote does.\n {\n slot: 'besignerInspector',\n widgetId: 'ai-save-as-component',\n title: 'Make a reusable component with AI',\n permission: 'ai.generate',\n Component: AiSaveAsComponent,\n },\n {\n slot: 'orgMember',\n widgetId: 'ai-member-usage',\n title: 'AI usage',\n Component: MemberAiUsageCard,\n },\n // The allotments (AGL-2942): a member's or a site's monthly share of\n // the pool, set on Billing → Usage, on each member's page and on a\n // site's collaborators card — each card asks the route what its\n // reader may see and change.\n {\n slot: 'orgBillingUsage',\n widgetId: 'ai-allotments',\n title: 'AI allotments',\n permission: 'billing.view',\n Component: AiAllotmentsCard,\n },\n {\n slot: 'orgMember',\n widgetId: 'ai-member-allotment',\n title: 'AI allotment',\n Component: MemberAiAllotmentCard,\n },\n {\n slot: 'hostMembers',\n widgetId: 'ai-collaborator-allotment',\n title: 'AI allotment',\n column: {\n header: 'AI allotment',\n align: 'right',\n Header: AiCollaboratorAllotmentHeader,\n },\n Component: AiCollaboratorAllotmentCell,\n },\n {\n slot: 'hostMembers',\n widgetId: 'ai-site-allotment',\n title: 'Site AI allotment',\n Component: AiSiteAllotmentCard,\n },\n // Themes by AI (AGL-2938): a brief on the site's Theme section, a\n // proposal previewed before and after, and the editor's own Save to\n // keep it. Generation is sold as `aiGenerative` and held by\n // `ai.generate`, so the shell withholds the card from a plan or a\n // member without either; the card itself asks the route about the\n // release flag before it shows anything.\n {\n slot: 'hostTheme',\n widgetId: 'ai-theme-proposal',\n title: 'Theme assistant',\n featureFlag: 'aiGenerative',\n permission: 'ai.generate',\n Component: AiThemeProposalCard,\n },\n {\n slot: 'staffOrg',\n widgetId: 'ai-org-usage',\n title: 'AI usage',\n Component: StaffOrgAiCard,\n },\n {\n slot: 'staffOrg',\n widgetId: 'ai-org-conversations',\n title: `${PLATFORM_BRAND_NAME} AI requests`,\n Component: StaffOrgAiConversations,\n },\n {\n slot: 'staffUser',\n widgetId: 'ai-account-usage',\n title: 'AI usage across organizations',\n Component: StaffUserAiUsageCard,\n },\n // The same card for one account, across every org it asked in\n // (AGL-3660); the slot passes `uid`, which puts it in account mode.\n {\n slot: 'staffUser',\n widgetId: 'ai-account-requests',\n title: `${PLATFORM_BRAND_NAME} AI requests`,\n Component: StaffOrgAiConversations,\n },\n // The staff tables' AI figures (AGL-2984): the Organizations list's\n // spend column, and the usage table's three columns with the credit\n // pool line the org page draws above it.\n {\n slot: 'staffOrgsListColumn',\n widgetId: 'ai-orgs-spend',\n title: 'AI spend (month)',\n column: {\n header: 'AI spend (month)',\n align: 'right',\n Header: StaffOrgsAiSpendHeader,\n },\n Component: StaffOrgsAiSpendCell,\n },\n {\n slot: 'staffOrgUsageColumn',\n widgetId: 'ai-usage-assist-cost',\n title: 'Assist',\n column: { header: 'Assist', align: 'right' },\n Component: StaffOrgUsageAssistCell,\n },\n {\n slot: 'staffOrgUsageColumn',\n widgetId: 'ai-usage-credits',\n title: 'AI credits used',\n column: { header: 'AI credits used', align: 'right' },\n Component: StaffOrgUsageAiCreditsCell,\n },\n {\n slot: 'staffOrgUsageColumn',\n widgetId: 'ai-usage-overage',\n title: 'AI overage billed ($)',\n column: { header: 'AI overage billed ($)', align: 'right' },\n Component: StaffOrgUsageAiOverageCell,\n },\n {\n slot: 'staffOrgUsageColumn',\n widgetId: 'ai-usage-pool',\n title: 'AI credit pool',\n Component: StaffOrgUsageAiPool,\n },\n {\n slot: 'orgMembersListColumn',\n widgetId: 'ai-member-credits',\n title: 'AI credits (month)',\n column: { header: 'AI credits (month)', align: 'right', Header: AiMemberCreditsHeader },\n Component: AiMemberCreditsCell,\n },\n {\n slot: 'hostMembers',\n widgetId: 'ai-collaborator-credits',\n title: 'AI credits (site, month)',\n column: {\n header: 'AI credits (site, month)',\n align: 'right',\n Header: AiCollaboratorCreditsHeader,\n },\n Component: AiCollaboratorCreditsCell,\n },\n // SEO by AI (AGL-2910): \"Write SEO\" inside every search listing editor\n // — a page's SEO card and a product's listing — and the site audit on\n // the site's SEO section. Generation is sold as `aiGenerative` and held\n // by `ai.generate`, so the shell withholds both from a plan or a member\n // without either; each card asks the jobs route about the release flag\n // before it shows anything, and neither ever writes what it proposes.\n {\n slot: 'seoFields',\n widgetId: 'ai-seo-fields',\n title: 'SEO assistant',\n featureFlag: 'aiGenerative',\n permission: 'ai.generate',\n Component: AiSeoFieldsCard,\n },\n {\n slot: 'hostSeo',\n widgetId: 'ai-seo-audit',\n title: 'SEO audit',\n featureFlag: 'aiGenerative',\n permission: 'ai.generate',\n Component: AiSeoAuditCard,\n },\n // A page from a brief (AGL-2907): \"Create with AI\" beside Templates and\n // Create New Screen. Gated as the other generative widgets are.\n // On a plan that could buy the AI add-on and has not, each \"Create with\n // AI\" entry here is mounted anyway (`showWhenNotEntitled`) and opens\n // the add-on's dialog instead of the brief (AGL-3601). The shell holds\n // each behind `release_ai_generative` too, so an entry draws at once\n // and asks the jobs route nothing until its brief is sent.\n {\n slot: 'hostScreens',\n widgetId: 'ai-describe-page',\n title: 'Describe a page',\n featureFlag: 'aiGenerative',\n permission: 'ai.generate',\n showWhenNotEntitled: true,\n releaseFlag: 'release_ai_generative',\n Component: AiDescribePageButton,\n },\n // The same entry for a page template, a layout and a form (AGL-3043),\n // beside the create action of the page that lists each: the same\n // dialog and the same gates.\n {\n slot: 'hostTemplates',\n widgetId: 'ai-describe-template',\n title: 'Describe a page template',\n featureFlag: 'aiGenerative',\n permission: 'ai.generate',\n showWhenNotEntitled: true,\n releaseFlag: 'release_ai_generative',\n Component: AiDescribeTemplateButton,\n },\n {\n slot: 'hostLayouts',\n widgetId: 'ai-describe-layout',\n title: 'Describe a layout',\n featureFlag: 'aiGenerative',\n permission: 'ai.generate',\n showWhenNotEntitled: true,\n releaseFlag: 'release_ai_generative',\n Component: AiDescribeLayoutButton,\n },\n {\n slot: 'hostForms',\n widgetId: 'ai-describe-form',\n title: 'Describe a form',\n featureFlag: 'aiGenerative',\n permission: 'ai.generate',\n showWhenNotEntitled: true,\n releaseFlag: 'release_ai_generative',\n Component: AiDescribeFormButton,\n },\n // And a reusable component from a brief (AGL-3051), beside Templates\n // and Create Component: the component job's first entry point, which\n // had none in the console.\n // Pictures from a description (AGL-3602): \"Create with AI\" beside Upload\n // media in the media library, and in its empty state. Gated as the\n // other generative widgets are, by the shell alone: it asks nothing of\n // a server until someone creates a picture, and the door decides then.\n // Like every Create with AI entry it is mounted without the add-on too\n // and opens its own upsell there (AGL-3601).\n {\n slot: 'mediaLibrary',\n widgetId: 'ai-media-create',\n title: 'Create images with AI',\n featureFlag: 'aiGenerative',\n permission: 'ai.generate',\n showWhenNotEntitled: true,\n releaseFlag: 'release_ai_generative',\n Component: AiMediaCreateButton,\n },\n {\n slot: 'hostComponents',\n widgetId: 'ai-describe-component',\n title: 'Describe a reusable component',\n featureFlag: 'aiGenerative',\n permission: 'ai.generate',\n showWhenNotEntitled: true,\n releaseFlag: 'release_ai_generative',\n Component: AiDescribeComponentButton,\n },\n // An email design from a brief (AGL-3596), beside New template on a\n // site's email templates — the zone the email plugin hosts. Its dialog\n // also offers the draft campaign that would send it; the Campaigns\n // section's own door is `ai-create-campaign`, below.\n {\n slot: 'hostEmailTemplates',\n widgetId: 'ai-describe-email',\n title: 'Describe an email',\n featureFlag: 'aiGenerative',\n permission: 'ai.generate',\n showWhenNotEntitled: true,\n releaseFlag: 'release_ai_generative',\n Component: AiDescribeEmailButton,\n },\n // Automations by AI (AGL-2919), in the zones the workflows plugin hosts\n // on its Automation page: \"Create with AI\" beside Add action and Recipes,\n // \"Explain it\" in the editor of a saved automation, and \"Why did this\n // fail?\" on a failed run. Gated as the other generative widgets are,\n // the release flag included, by the shell alone (AGL-3601): none asks\n // the jobs route anything until it is used, and none of them changes an\n // automation.\n {\n slot: 'hostAutomations',\n widgetId: 'ai-describe-automation',\n title: 'Describe an automation',\n featureFlag: 'aiGenerative',\n permission: 'ai.generate',\n showWhenNotEntitled: true,\n releaseFlag: 'release_ai_generative',\n Component: AiDescribeAutomationButton,\n },\n // Funnels by AI (AGL-3605), in the zones the funnels plugin hosts on\n // its card: a draft from a description, and its results explained.\n {\n slot: 'funnelsCreate',\n widgetId: 'ai-describe-funnel',\n title: 'Describe a funnel',\n featureFlag: 'aiGenerative',\n permission: 'ai.generate',\n showWhenNotEntitled: true,\n releaseFlag: 'release_ai_generative',\n Component: AiFunnelCreateButton,\n },\n {\n slot: 'funnelInsight',\n widgetId: 'ai-explain-funnel',\n title: 'Ask AI about this funnel',\n featureFlag: 'aiGenerative',\n permission: 'ai.generate',\n showWhenNotEntitled: true,\n releaseFlag: 'release_ai_generative',\n Component: AiFunnelAskButton,\n },\n {\n slot: 'automationEditor',\n widgetId: 'ai-explain-automation',\n title: 'Explain this automation',\n featureFlag: 'aiGenerative',\n permission: 'ai.generate',\n releaseFlag: 'release_ai_generative',\n Component: AiExplainAutomation,\n },\n // \"Change with AI\" and \"Fix with AI\" in a saved action's editor\n // (AGL-3603): a changed copy drafted OFF beside it, never the saved\n // action written in place.\n {\n slot: 'automationEditor',\n widgetId: 'ai-revise-automation',\n title: 'Change this automation with AI',\n featureFlag: 'aiGenerative',\n permission: 'ai.generate',\n releaseFlag: 'release_ai_generative',\n Component: AiReviseAutomation,\n },\n // \"Create with AI\" on the workspace's Org automations (AGL-3603): one\n // of the workspace's automations drafted from a description and opened\n // in that section's editor, unsaved and switched off.\n {\n slot: 'orgAutomations',\n widgetId: 'ai-describe-org-automation',\n title: 'Describe an org automation',\n featureFlag: 'aiGenerative',\n permission: 'ai.generate',\n showWhenNotEntitled: true,\n releaseFlag: 'release_ai_generative',\n Component: AiDescribeOrgAutomationButton,\n },\n // \"Ask AI about these numbers\" (AGL-3603): a tile on a site's\n // dashboard and Analytics page, which both draw `hostDashboard`, and on\n // the workspace's sites page. It opens the insight dialog the Assist\n // panel opens, gated as every generative widget is.\n {\n slot: 'hostDashboard',\n widgetId: 'ai-insight-ask',\n title: 'Ask AI about these numbers',\n featureFlag: 'aiGenerative',\n permission: 'ai.generate',\n showWhenNotEntitled: true,\n releaseFlag: 'release_ai_generative',\n Component: AiInsightHostCard,\n },\n {\n slot: 'orgDashboard',\n widgetId: 'ai-insight-ask',\n title: 'Ask AI about these numbers',\n featureFlag: 'aiGenerative',\n permission: 'ai.generate',\n showWhenNotEntitled: true,\n releaseFlag: 'release_ai_generative',\n Component: AiInsightOrgCard,\n },\n // Logic by AI (AGL-3603), in the zones the logic plugin hosts on its\n // Functions & Variables page: Create with AI in the Functions and\n // Variables card headers, Explain / Change / Fix in a saved function's\n // editor, and Fix with AI on a broken reference an automation holds.\n // Each proposal opens unsaved in the logic editor; none is saved here.\n {\n slot: 'hostLogic',\n widgetId: 'ai-describe-logic',\n title: 'Describe a function or variable',\n featureFlag: 'aiGenerative',\n permission: 'ai.generate',\n showWhenNotEntitled: true,\n releaseFlag: 'release_ai_generative',\n Component: AiLogicCreateButton,\n },\n {\n slot: 'logicFunctionEditor',\n widgetId: 'ai-logic-function',\n title: 'This function with AI',\n featureFlag: 'aiGenerative',\n permission: 'ai.generate',\n releaseFlag: 'release_ai_generative',\n Component: AiLogicFunctionTools,\n },\n {\n slot: 'logicReferenceIssue',\n widgetId: 'ai-logic-fix-reference',\n title: 'Fix this reference with AI',\n featureFlag: 'aiGenerative',\n permission: 'ai.generate',\n releaseFlag: 'release_ai_generative',\n Component: AiLogicFixReference,\n },\n {\n slot: 'automationRun',\n widgetId: 'ai-explain-run-failure',\n title: 'Why did this run fail?',\n featureFlag: 'aiGenerative',\n permission: 'ai.generate',\n releaseFlag: 'release_ai_generative',\n Component: AiExplainRunFailure,\n },\n // CRM by AI (AGL-2917): a record's summary and next step on its page,\n // a draft in the one-to-one composer, and an import's column matches.\n // The CRM hosts each zone, so it is drawn only where the CRM is; the\n // shell holds the plan and `ai.generate`, each card asks the jobs route\n // about the release flag before it shows anything, and none writes what\n // it proposes.\n {\n slot: 'recordInsights',\n widgetId: 'ai-crm-record',\n title: 'AI summary',\n featureFlag: 'aiGenerative',\n permission: 'ai.generate',\n Component: AiCrmRecordCard,\n },\n {\n slot: 'recordEmail',\n widgetId: 'ai-crm-email',\n title: 'Draft with AI',\n featureFlag: 'aiGenerative',\n permission: 'ai.generate',\n Component: AiCrmEmailDraft,\n },\n {\n slot: 'importMapping',\n widgetId: 'ai-crm-import-mapping',\n title: 'Match columns with AI',\n featureFlag: 'aiGenerative',\n permission: 'ai.generate',\n Component: AiCrmImportMapping,\n },\n // The guided start (AGL-2918), on the page a newly created site lands\n // on: a few questions that become a site scaffold. Gated as the other\n // generative widgets are, and it asks the jobs route about the release\n // flag before it shows anything — so a workspace the feature is not\n // released to gets the blank page and nothing else. Skipping is the\n // zone's own `startBlank`, which creates nothing.\n {\n slot: 'hostFirstRun',\n widgetId: 'ai-site-start',\n title: 'Start this site with AI',\n featureFlag: 'aiGenerative',\n permission: 'ai.generate',\n Component: AiSiteStartCard,\n },\n // The listing those answers describe (AGL-2918), on the site's SEO\n // section: the site-wide search title and description the guided start\n // implies, offered where they are edited. The same gates as every\n // generative widget, and it stages into the SEO form rather than\n // writing it — a person's Update is the write, as it is for the audit\n // card beside it.\n {\n slot: 'hostSeo',\n widgetId: 'ai-site-seo-start',\n title: 'The listing your answers describe',\n featureFlag: 'aiGenerative',\n permission: 'ai.generate',\n Component: AiSiteSeoStartCard,\n },\n // What Aglyn AI learned from the site's applied edits (AGL-3661), on\n // Setup → Business profile, where the owner reads and forgets it. No\n // generate permission: reading and clearing what the AI keeps about a\n // site is every editor's, and the rules hold the write to the server.\n {\n slot: 'hostBusinessProfile',\n widgetId: 'ai-site-memory',\n title: `What ${aiAddonName()} learned`,\n featureFlag: 'aiGenerative',\n Component: AiSiteMemoryCard,\n },\n // The agency batch (AGL-2911): one brief across many of the org's\n // sites, from the page that lists them. The card asks the jobs route\n // about the release flag before it shows anything, and its own door\n // holds the plan band and the caller's permission on every site it is\n // pointed at.\n {\n slot: 'orgSites',\n widgetId: 'ai-site-batch',\n title: 'Generate sites with AI',\n featureFlag: 'aiGenerative',\n permission: 'ai.generate',\n Component: AiSiteBatchCard,\n },\n // Commerce by AI (AGL-2916): product copy in the product editor, the\n // catalog, categories and discounts on the products hub, and copy for\n // an import as it lands. The commerce plugin hosts the zones and makes\n // every write. The shell holds the release flag; the products hub card\n // reads its recent proposals before it draws its own controls, but\n // offers the \"Create with AI\" door's brief from the moment it mounts.\n {\n slot: 'productEditor',\n widgetId: 'ai-product-copy',\n title: 'Product copy assistant',\n featureFlag: 'aiGenerative',\n permission: 'ai.generate',\n Component: AiProductCopyCard,\n },\n {\n slot: 'productsHub',\n widgetId: 'ai-products-hub',\n title: 'Build your catalog with AI',\n featureFlag: 'aiGenerative',\n permission: 'ai.generate',\n releaseFlag: 'release_ai_generative',\n Component: AiProductsHubCard,\n },\n // \"Create with AI\" beside Add product and in the empty catalog\n // (AGL-3596): a door to the card's Propose products brief, shown only\n // while that card is on the page to take it.\n {\n slot: 'productsCreate',\n widgetId: 'ai-products-create',\n title: 'Propose products',\n featureFlag: 'aiGenerative',\n permission: 'ai.generate',\n showWhenNotEntitled: true,\n releaseFlag: 'release_ai_generative',\n Component: AiCreateProductsButton,\n },\n {\n slot: 'productImport',\n widgetId: 'ai-product-import',\n title: 'Write imported product copy with AI',\n featureFlag: 'aiGenerative',\n permission: 'ai.generate',\n Component: AiProductImportOption,\n },\n // A/B tests by AI (AGL-2914): variants written in the experiment\n // editor, and one test's result read in plain words below its figures.\n // The A/B testing card hosts both zones, so they are drawn only where\n // that card is and only on a site with A/B testing; the shell holds the\n // plan band, `ai.generate` and the release flag, and neither card asks\n // the jobs route anything until it is used (AGL-3601). Neither writes: the\n // experiment editor's Save is the only write, and an explanation has\n // nothing to apply.\n {\n slot: 'experimentVariants',\n widgetId: 'ai-experiment-variants',\n title: 'Write variants with AI',\n featureFlag: 'aiGenerative',\n permission: 'ai.generate',\n releaseFlag: 'release_ai_generative',\n Component: AiExperimentVariantsCard,\n },\n {\n slot: 'experimentResult',\n widgetId: 'ai-experiment-result',\n title: 'Explain this result with AI',\n featureFlag: 'aiGenerative',\n permission: 'ai.generate',\n releaseFlag: 'release_ai_generative',\n Component: AiExperimentResultCard,\n },\n // Overlays by AI (AGL-3603), in the zones the marketing plugin's\n // overlays list hosts: \"Create with AI\" beside New bar and New popup,\n // and \"Write with AI\" among the overlay editor's fields. Both start a\n // `text` job asked for overlay copy; neither writes — the list saves a\n // created overlay switched off, and the editor's Save is the write.\n {\n slot: 'hostOverlays',\n widgetId: 'ai-create-overlay',\n title: 'Create an overlay with AI',\n featureFlag: 'aiGenerative',\n permission: 'ai.generate',\n showWhenNotEntitled: true,\n releaseFlag: 'release_ai_generative',\n Component: AiCreateOverlayButton,\n },\n {\n slot: 'overlayEditor',\n widgetId: 'ai-overlay-copy',\n title: 'Write overlay copy with AI',\n featureFlag: 'aiGenerative',\n permission: 'ai.generate',\n releaseFlag: 'release_ai_generative',\n Component: AiOverlayEditorCard,\n },\n // A campaign from a brief (AGL-3603), beside Create campaign on the\n // Campaigns section the marketing plugin hosts: the `campaign` job's\n // first console door, or the `email` job's where the plan sends no\n // campaign email. Both write drafts that are aimed at nobody and sent\n // by nobody until a member does.\n {\n slot: 'hostCampaigns',\n widgetId: 'ai-create-campaign',\n title: 'Create a campaign with AI',\n featureFlag: 'aiGenerative',\n permission: 'ai.generate',\n showWhenNotEntitled: true,\n releaseFlag: 'release_ai_generative',\n Component: AiCreateCampaignButton,\n },\n // The figures in words (AGL-3603), in the header of the Conversions\n // section and of one campaign's report: the insight dialog the Assist\n // panel opens, on the Marketing surface, for the site the figures are.\n // It reads and cites; it changes nothing.\n {\n slot: 'marketingInsights',\n widgetId: 'ai-marketing-insight',\n title: 'Ask AI about these numbers',\n featureFlag: 'aiGenerative',\n permission: 'ai.generate',\n showWhenNotEntitled: true,\n releaseFlag: 'release_ai_generative',\n Component: AiMarketingInsightButton,\n },\n ],\n })\n}\n"],"names":["PLATFORM_BRAND_NAME","aiAddonName","registerConsoleExtension","LinearProgress","createElement","AiAssistProviderOnHost","AI_PLUGIN_ID","registerAiDeclarations","lazyWidget","PAGE_LOADING","AiSaveAsComponent","then","m","AiGenerateSectionControl","AiRewriteControl","AssistPanelOnHost","AiCreditsCard","default","AiJobsTopBarIndicator","AiCollaboratorCreditsCell","AiCollaboratorCreditsHeader","AiMemberCreditsCell","AiMemberCreditsHeader","AssistSignalsPage","BillingAssistOverageCard","AiTopUsersCard","AiAllotmentsCard","AiCollaboratorAllotmentCell","AiCollaboratorAllotmentHeader","AiSiteAllotmentCard","MemberAiAllotmentCard","MemberAiUsageCard","AiThemeProposalCard","StaffOrgAiCard","StaffOrgAiConversations","StaffOrgUsageAiCreditsCell","StaffOrgUsageAiOverageCell","StaffOrgUsageAiPool","StaffOrgUsageAssistCell","StaffOrgsAiSpendCell","StaffOrgsAiSpendHeader","StaffUserAiUsageCard","AiSeoAuditCard","AiSiteBatchCard","AiSiteSeoStartCard","AiSiteMemoryCard","AiSiteStartCard","AiSeoFieldsCard","AiDescribeAutomationButton","AiReviseAutomation","AiDescribeOrgAutomationButton","AiInsightHostCard","AiInsightOrgCard","AiLogicCreateButton","AiLogicFixReference","AiLogicFunctionTools","AiFunnelAskButton","AiFunnelCreateButton","AiCrmEmailDraft","AiCrmImportMapping","AiCrmRecordCard","AiDescribePageButton","AiMediaCreateButton","AiDescribeComponentButton","AiDescribeFormButton","AiDescribeLayoutButton","AiDescribeTemplateButton","AiDescribeEmailButton","AiExperimentResultCard","AiExperimentVariantsCard","AiExplainAutomation","AiExplainRunFailure","AiCreateCampaignButton","AiMarketingInsightButton","AiCreateOverlayButton","AiOverlayEditorCard","AiProductCopyCard","AiProductImportOption","AiProductsHubCard","AiCreateProductsButton","AiJobsPage","registerAiConsole","pluginId","displayName","providers","staffPages","id","label","header","title","docsTopic","Component","navItems","href","recordTitle","docsAnchor","unlisted","ownsSubtree","permission","widgets","slot","widgetId","featureFlag","column","align","Header","showWhenNotEntitled","releaseFlag"],"mappings":"AAAA;;;;;;;;;;;;;;;CAeC,GAED,SAASA,mBAAmB,EAAEC,WAAW,EAAEC,wBAAwB,QAAQ,eAAc;AACzF,SAASC,cAAc,QAAQ,gBAAe;AAC9C,SAASC,aAAa,QAAQ,QAAO;AACrC,SAASC,sBAAsB,QAAQ,uDAAmD;AAC1F,SAASC,YAAY,QAAQ,iBAAa;AAC1C,SAASC,sBAAsB,QAAQ,oBAAgB;AACvD,SAASC,UAAU,QAAQ,mBAAe;AAE1C;;;;;CAKC,GAED,8CAA8C,GAC9C,MAAMC,eAAeL,cAAcD,gBAAgB;IAAE,cAAc;AAAU;AAE7E,MAAMO,oBAAoBF,WAAW,qBAAqB,IACxD,MAAM,CAAC,kDAA+CG,IAAI,CACxD,CAACC,IAAMA,EAAEF,iBAAiB;AAG9B,MAAMG,2BAA2BL,WAAW,4BAA4B,IACtE,MAAM,CAAC,kDAA+CG,IAAI,CACxD,CAACC,IAAMA,EAAEC,wBAAwB;AAGrC,MAAMC,mBAAmBN,WAAW,oBAAoB,IACtD,MAAM,CAAC,kDAA+CG,IAAI,CACxD,CAACC,IAAMA,EAAEE,gBAAgB;AAG7B,MAAMC,oBAAoBP,WAAW,qBAAqB,IACxD,MAAM,CAAC,oDAAiDG,IAAI,CAC1D,CAACC,IAAMA,EAAEG,iBAAiB;AAG9B,MAAMC,gBAAgBR,WAAW,iBAAiB,IAChD,MAAM,CAAC,6CAA0CG,IAAI,CAAC,CAACC,IAAMA,EAAEK,OAAO;AAExE,MAAMC,wBAAwBV,WAAW,yBAAyB,IAChE,MAAM,CAAC,+CAA4CG,IAAI,CAAC,CAACC,IAAMA,EAAEK,OAAO;AAE1E,MAAME,4BAA4BX,WAAW,6BAA6B,IACxE,MAAM,CAAC,gDAA6CG,IAAI,CACtD,CAACC,IAAMA,EAAEO,yBAAyB;AAGtC,MAAMC,8BAA8BZ,WAClC,+BACA,IACE,MAAM,CAAC,gDAA6CG,IAAI,CACtD,CAACC,IAAMA,EAAEQ,2BAA2B;AAG1C,MAAMC,sBAAsBb,WAAW,uBAAuB,IAC5D,MAAM,CAAC,gDAA6CG,IAAI,CACtD,CAACC,IAAMA,EAAES,mBAAmB;AAGhC,MAAMC,wBAAwBd,WAAW,yBAAyB,IAChE,MAAM,CAAC,gDAA6CG,IAAI,CACtD,CAACC,IAAMA,EAAEU,qBAAqB;AAGlC,MAAMC,oBAAoBf,WACxB,qBACA,IACE,MAAM,CAAC,iDAA8CG,IAAI,CACvD,CAACC,IAAMA,EAAEW,iBAAiB,GAE9Bd;AAEF,MAAMe,2BAA2BhB,WAAW,4BAA4B,IACtE,MAAM,CAAC,yDAAsDG,IAAI,CAC/D,CAACC,IAAMA,EAAEK,OAAO;AAGpB,MAAMQ,iBAAiBjB,WAAW,kBAAkB,IAClD,MAAM,CAAC,kDAA+CG,IAAI,CACxD,CAACC,IAAMA,EAAEa,cAAc;AAG3B,MAAMC,mBAAmBlB,WAAW,oBAAoB,IACtD,MAAM,CAAC,mDAAgDG,IAAI,CACzD,CAACC,IAAMA,EAAEc,gBAAgB;AAG7B,MAAMC,8BAA8BnB,WAClC,+BACA,IACE,MAAM,CAAC,gDAA6CG,IAAI,CACtD,CAACC,IAAMA,EAAEe,2BAA2B;AAG1C,MAAMC,gCAAgCpB,WACpC,iCACA,IACE,MAAM,CAAC,gDAA6CG,IAAI,CACtD,CAACC,IAAMA,EAAEgB,6BAA6B;AAG5C,MAAMC,sBAAsBrB,WAAW,uBAAuB,IAC5D,MAAM,CAAC,gDAA6CG,IAAI,CACtD,CAACC,IAAMA,EAAEiB,mBAAmB;AAGhC,MAAMC,wBAAwBtB,WAAW,yBAAyB,IAChE,MAAM,CAAC,sDAAmDG,IAAI,CAC5D,CAACC,IAAMA,EAAEK,OAAO;AAGpB,MAAMc,oBAAoBvB,WAAW,qBAAqB,IACxD,MAAM,CAAC,kDAA+CG,IAAI,CAAC,CAACC,IAAMA,EAAEK,OAAO;AAE7E,MAAMe,sBAAsBxB,WAAW,uBAAuB,IAC5D,MAAM,CAAC,oDAAiDG,IAAI,CAC1D,CAACC,IAAMA,EAAEK,OAAO;AAGpB,MAAMgB,iBAAiBzB,WAAW,kBAAkB,IAClD,MAAM,CAAC,+CAA4CG,IAAI,CAAC,CAACC,IAAMA,EAAEK,OAAO;AAE1E,MAAMiB,0BAA0B1B,WAAW,2BAA2B,IACpE,MAAM,CAAC,wDAAqDG,IAAI,CAAC,CAACC,IAAMA,EAAEK,OAAO;AAEnF,MAAMkB,6BAA6B3B,WACjC,8BACA,IACE,MAAM,CAAC,wDAAqDG,IAAI,CAC9D,CAACC,IAAMA,EAAEuB,0BAA0B;AAGzC,MAAMC,6BAA6B5B,WACjC,8BACA,IACE,MAAM,CAAC,wDAAqDG,IAAI,CAC9D,CAACC,IAAMA,EAAEwB,0BAA0B;AAGzC,MAAMC,sBAAsB7B,WAAW,uBAAuB,IAC5D,MAAM,CAAC,wDAAqDG,IAAI,CAC9D,CAACC,IAAMA,EAAEyB,mBAAmB;AAGhC,MAAMC,0BAA0B9B,WAAW,2BAA2B,IACpE,MAAM,CAAC,wDAAqDG,IAAI,CAC9D,CAACC,IAAMA,EAAE0B,uBAAuB;AAGpC,MAAMC,uBAAuB/B,WAAW,wBAAwB,IAC9D,MAAM,CAAC,wDAAqDG,IAAI,CAC9D,CAACC,IAAMA,EAAE2B,oBAAoB;AAGjC,MAAMC,yBAAyBhC,WAAW,0BAA0B,IAClE,MAAM,CAAC,wDAAqDG,IAAI,CAC9D,CAACC,IAAMA,EAAE4B,sBAAsB;AAGnC,MAAMC,uBAAuBjC,WAAW,wBAAwB,IAC9D,MAAM,CAAC,sDAAmDG,IAAI,CAC5D,CAACC,IAAMA,EAAEK,OAAO;AAGpB,MAAMyB,iBAAiBlC,WAAW,kBAAkB,IAClD,MAAM,CAAC,+CAA4CG,IAAI,CAAC,CAACC,IAAMA,EAAEK,OAAO;AAE1E,MAAM0B,kBAAkBnC,WAAW,mBAAmB,IACpD,MAAM,CAAC,gDAA6CG,IAAI,CAAC,CAACC,IAAMA,EAAEK,OAAO;AAE3E,MAAM2B,qBAAqBpC,WAAW,sBAAsB,IAC1D,MAAM,CAAC,oDAAiDG,IAAI,CAC1D,CAACC,IAAMA,EAAEK,OAAO;AAGpB,MAAM4B,mBAAmBrC,WAAW,oBAAoB,IACtD,MAAM,CAAC,iDAA8CG,IAAI,CAAC,CAACC,IAAMA,EAAEK,OAAO;AAE5E,MAAM6B,kBAAkBtC,WAAW,mBAAmB,IACpD,MAAM,CAAC,gDAA6CG,IAAI,CAAC,CAACC,IAAMA,EAAEK,OAAO;AAE3E,MAAM8B,kBAAkBvC,WAAW,mBAAmB,IACpD,MAAM,CAAC,gDAA6CG,IAAI,CAAC,CAACC,IAAMA,EAAEK,OAAO;AAE3E,MAAM+B,6BAA6BxC,WACjC,8BACA,IACE,MAAM,CAAC,oDAAiDG,IAAI,CAC1D,CAACC,IAAMA,EAAEK,OAAO;AAGtB,MAAMgC,qBAAqBzC,WAAW,sBAAsB,IAC1D,MAAM,CAAC,kDAA+CG,IAAI,CAAC,CAACC,IAAMA,EAAEK,OAAO;AAE7E,MAAMiC,gCAAgC1C,WACpC,iCACA,IACE,MAAM,CAAC,wDAAqDG,IAAI,CAC9D,CAACC,IAAMA,EAAEK,OAAO;AAGtB,MAAMkC,oBAAoB3C,WAAW,qBAAqB,IACxD,MAAM,CAAC,6CAA0CG,IAAI,CACnD,CAACC,IAAMA,EAAEuC,iBAAiB;AAG9B,MAAMC,mBAAmB5C,WAAW,oBAAoB,IACtD,MAAM,CAAC,6CAA0CG,IAAI,CACnD,CAACC,IAAMA,EAAEwC,gBAAgB;AAG7B,MAAMC,sBAAsB7C,WAAW,uBAAuB,IAC5D,MAAM,CAAC,sCAAmCG,IAAI,CAAC,CAACC,IAAMA,EAAEyC,mBAAmB;AAE7E,MAAMC,sBAAsB9C,WAAW,uBAAuB,IAC5D,MAAM,CAAC,sCAAmCG,IAAI,CAAC,CAACC,IAAMA,EAAE0C,mBAAmB;AAE7E,MAAMC,uBAAuB/C,WAAW,wBAAwB,IAC9D,MAAM,CAAC,sCAAmCG,IAAI,CAAC,CAACC,IAAMA,EAAE2C,oBAAoB;AAE9E,MAAMC,oBAAoBhD,WAAW,qBAAqB,IACxD,MAAM,CAAC,6CAA0CG,IAAI,CACnD,CAACC,IAAMA,EAAE4C,iBAAiB;AAG9B,MAAMC,uBAAuBjD,WAAW,wBAAwB,IAC9D,MAAM,CAAC,6CAA0CG,IAAI,CACnD,CAACC,IAAMA,EAAE6C,oBAAoB;AAGjC,MAAMC,kBAAkBlD,WAAW,mBAAmB,IACpD,MAAM,CAAC,gDAA6CG,IAAI,CAAC,CAACC,IAAMA,EAAEK,OAAO;AAE3E,MAAM0C,qBAAqBnD,WAAW,sBAAsB,IAC1D,MAAM,CAAC,mDAAgDG,IAAI,CAAC,CAACC,IAAMA,EAAEK,OAAO;AAE9E,MAAM2C,kBAAkBpD,WAAW,mBAAmB,IACpD,MAAM,CAAC,gDAA6CG,IAAI,CAAC,CAACC,IAAMA,EAAEK,OAAO;AAE3E,MAAM4C,uBAAuBrD,WAAW,wBAAwB,IAC9D,MAAM,CAAC,8CAA2CG,IAAI,CAAC,CAACC,IAAMA,EAAEK,OAAO;AAEzE,MAAM6C,sBAAsBtD,WAAW,uBAAuB,IAC5D,MAAM,CAAC,6CAA0CG,IAAI,CAAC,CAACC,IAAMA,EAAEK,OAAO;AAExE,MAAM8C,4BAA4BvD,WAAW,6BAA6B,IACxE,MAAM,CAAC,gDAA6CG,IAAI,CACtD,CAACC,IAAMA,EAAEmD,yBAAyB;AAGtC,MAAMC,uBAAuBxD,WAAW,wBAAwB,IAC9D,MAAM,CAAC,gDAA6CG,IAAI,CACtD,CAACC,IAAMA,EAAEoD,oBAAoB;AAGjC,MAAMC,yBAAyBzD,WAAW,0BAA0B,IAClE,MAAM,CAAC,gDAA6CG,IAAI,CACtD,CAACC,IAAMA,EAAEqD,sBAAsB;AAGnC,MAAMC,2BAA2B1D,WAAW,4BAA4B,IACtE,MAAM,CAAC,gDAA6CG,IAAI,CACtD,CAACC,IAAMA,EAAEsD,wBAAwB;AAGrC,MAAMC,wBAAwB3D,WAAW,yBAAyB,IAChE,MAAM,CAAC,+CAA4CG,IAAI,CACrD,CAACC,IAAMA,EAAEuD,qBAAqB;AAGlC,MAAMC,yBAAyB5D,WAAW,0BAA0B,IAClE,MAAM,CAAC,iDAA8CG,IAAI,CACvD,CAACC,IAAMA,EAAEwD,sBAAsB;AAGnC,MAAMC,2BAA2B7D,WAAW,4BAA4B,IACtE,MAAM,CAAC,iDAA8CG,IAAI,CACvD,CAACC,IAAMA,EAAEyD,wBAAwB;AAGrC,MAAMC,sBAAsB9D,WAAW,uBAAuB,IAC5D,MAAM,CAAC,mDAAgDG,IAAI,CACzD,CAACC,IAAMA,EAAE0D,mBAAmB;AAGhC,MAAMC,sBAAsB/D,WAAW,uBAAuB,IAC5D,MAAM,CAAC,mDAAgDG,IAAI,CACzD,CAACC,IAAMA,EAAE2D,mBAAmB;AAGhC,MAAMC,yBAAyBhE,WAAW,0BAA0B,IAClE,MAAM,CAAC,gDAA6CG,IAAI,CAAC,CAACC,IAAMA,EAAEK,OAAO;AAE3E,MAAMwD,2BAA2BjE,WAAW,4BAA4B,IACtE,MAAM,CAAC,kDAA+CG,IAAI,CAAC,CAACC,IAAMA,EAAEK,OAAO;AAE7E,MAAMyD,wBAAwBlE,WAAW,yBAAyB,IAChE,MAAM,CAAC,8CAA2CG,IAAI,CACpD,CAACC,IAAMA,EAAE8D,qBAAqB;AAGlC,MAAMC,sBAAsBnE,WAAW,uBAAuB,IAC5D,MAAM,CAAC,8CAA2CG,IAAI,CACpD,CAACC,IAAMA,EAAE+D,mBAAmB;AAGhC,MAAMC,oBAAoBpE,WAAW,qBAAqB,IACxD,MAAM,CAAC,kDAA+CG,IAAI,CAAC,CAACC,IAAMA,EAAEK,OAAO;AAE7E,MAAM4D,wBAAwBrE,WAAW,yBAAyB,IAChE,MAAM,CAAC,sDAAmDG,IAAI,CAC5D,CAACC,IAAMA,EAAEK,OAAO;AAGpB,MAAM6D,oBAAoBtE,WAAW,qBAAqB,IACxD,MAAM,CAAC,kDAA+CG,IAAI,CAAC,CAACC,IAAMA,EAAEK,OAAO;AAE7E,MAAM8D,yBAAyBvE,WAAW,0BAA0B,IAClE,MAAM,CAAC,uDAAoDG,IAAI,CAC7D,CAACC,IAAMA,EAAEK,OAAO;AAGpB,MAAM+D,aAAaxE,WACjB,cACA,IAAM,MAAM,CAAC,0CAAuCG,IAAI,CAAC,CAACC,IAAMA,EAAEK,OAAO,GACzER;AAGF;;;;;;;;;;;;CAYC,GACD,OAAO,SAASwE;IACd1E;IACAL,yBAAyB;QACvBgF,UAAU5E;QACV6E,aAAa;QACb,wEAAwE;QACxE,qEAAqE;QACrEC,WAAW;YAAC/E;SAAuB;QACnC,wEAAwE;QACxE,2CAA2C;QAC3CgF,YAAY;YACV;gBACEC,IAAI;gBACJC,OAAO;gBACPC,QAAQ;oBACN,gEAAgE;oBAChE,6DAA6D;oBAC7DC,OAAO,GAAGzF,oBAAoB,cAAc,CAAC;oBAC7C0F,WAAW;gBACb;gBACAC,WAAWpE;YACb;SACD;QACD,qEAAqE;QACrE,oEAAoE;QACpE,yEAAyE;QACzE,sEAAsE;QACtE,uEAAuE;QACvE,kEAAkE;QAClEqE,UAAU;YACR;gBACEL,OAAO;gBACPM,MAAM;gBACNC,aAAa;gBACbN,QAAQ;oBAAEC,OAAO;oBAAWC,WAAW;oBAAqBK,YAAY;gBAAoB;gBAC5FC,UAAU;gBACVC,aAAa;gBACbC,YAAY;gBACZP,WAAWX;YACb;SACD;QACDmB,SAAS;YACP;gBACEC,MAAM;gBACNC,UAAU;gBACVZ,OAAO;gBACPE,WAAW5E;YACb;YACA,qEAAqE;YACrE,wEAAwE;YACxE,uEAAuE;YACvE,uDAAuD;YACvD;gBACEqF,MAAM;gBACNC,UAAU;gBACVZ,OAAO;gBACPa,aAAa;gBACbJ,YAAY;gBACZP,WAAWzE;YACb;YACA;gBACEkF,MAAM;gBACNC,UAAU;gBACVZ,OAAO;gBACPE,WAAW3E;YACb;YACA;gBACEoF,MAAM;gBACNC,UAAU;gBACVZ,OAAO;gBACPE,WAAWnE;YACb;YACA,kEAAkE;YAClE,kEAAkE;YAClE,oDAAoD;YACpD;gBACE4E,MAAM;gBACNC,UAAU;gBACVZ,OAAO;gBACPS,YAAY;gBACZP,WAAWlE;YACb;YACA,qEAAqE;YACrE,oEAAoE;YACpE,qEAAqE;YACrE,uBAAuB;YACvB,uEAAuE;YACvE,mEAAmE;YACnE,sEAAsE;YACtE,2DAA2D;YAC3D;gBACE2E,MAAM;gBACNC,UAAU;gBACVZ,OAAO;gBACPE,WAAW9E;YACb;YACA;gBACEuF,MAAM;gBACNC,UAAU;gBACVZ,OAAO;gBACPE,WAAW7E;YACb;YACA,uEAAuE;YACvE,oEAAoE;YACpE,8DAA8D;YAC9D;gBACEsF,MAAM;gBACNC,UAAU;gBACVZ,OAAO;gBACPS,YAAY;gBACZP,WAAWjF;YACb;YACA;gBACE0F,MAAM;gBACNC,UAAU;gBACVZ,OAAO;gBACPE,WAAW5D;YACb;YACA,qEAAqE;YACrE,mEAAmE;YACnE,gEAAgE;YAChE,6BAA6B;YAC7B;gBACEqE,MAAM;gBACNC,UAAU;gBACVZ,OAAO;gBACPS,YAAY;gBACZP,WAAWjE;YACb;YACA;gBACE0E,MAAM;gBACNC,UAAU;gBACVZ,OAAO;gBACPE,WAAW7D;YACb;YACA;gBACEsE,MAAM;gBACNC,UAAU;gBACVZ,OAAO;gBACPc,QAAQ;oBACNf,QAAQ;oBACRgB,OAAO;oBACPC,QAAQ7E;gBACV;gBACA+D,WAAWhE;YACb;YACA;gBACEyE,MAAM;gBACNC,UAAU;gBACVZ,OAAO;gBACPE,WAAW9D;YACb;YACA,kEAAkE;YAClE,oEAAoE;YACpE,4DAA4D;YAC5D,kEAAkE;YAClE,kEAAkE;YAClE,yCAAyC;YACzC;gBACEuE,MAAM;gBACNC,UAAU;gBACVZ,OAAO;gBACPa,aAAa;gBACbJ,YAAY;gBACZP,WAAW3D;YACb;YACA;gBACEoE,MAAM;gBACNC,UAAU;gBACVZ,OAAO;gBACPE,WAAW1D;YACb;YACA;gBACEmE,MAAM;gBACNC,UAAU;gBACVZ,OAAO,GAAGzF,oBAAoB,YAAY,CAAC;gBAC3C2F,WAAWzD;YACb;YACA;gBACEkE,MAAM;gBACNC,UAAU;gBACVZ,OAAO;gBACPE,WAAWlD;YACb;YACA,8DAA8D;YAC9D,oEAAoE;YACpE;gBACE2D,MAAM;gBACNC,UAAU;gBACVZ,OAAO,GAAGzF,oBAAoB,YAAY,CAAC;gBAC3C2F,WAAWzD;YACb;YACA,oEAAoE;YACpE,oEAAoE;YACpE,yCAAyC;YACzC;gBACEkE,MAAM;gBACNC,UAAU;gBACVZ,OAAO;gBACPc,QAAQ;oBACNf,QAAQ;oBACRgB,OAAO;oBACPC,QAAQjE;gBACV;gBACAmD,WAAWpD;YACb;YACA;gBACE6D,MAAM;gBACNC,UAAU;gBACVZ,OAAO;gBACPc,QAAQ;oBAAEf,QAAQ;oBAAUgB,OAAO;gBAAQ;gBAC3Cb,WAAWrD;YACb;YACA;gBACE8D,MAAM;gBACNC,UAAU;gBACVZ,OAAO;gBACPc,QAAQ;oBAAEf,QAAQ;oBAAmBgB,OAAO;gBAAQ;gBACpDb,WAAWxD;YACb;YACA;gBACEiE,MAAM;gBACNC,UAAU;gBACVZ,OAAO;gBACPc,QAAQ;oBAAEf,QAAQ;oBAAyBgB,OAAO;gBAAQ;gBAC1Db,WAAWvD;YACb;YACA;gBACEgE,MAAM;gBACNC,UAAU;gBACVZ,OAAO;gBACPE,WAAWtD;YACb;YACA;gBACE+D,MAAM;gBACNC,UAAU;gBACVZ,OAAO;gBACPc,QAAQ;oBAAEf,QAAQ;oBAAsBgB,OAAO;oBAASC,QAAQnF;gBAAsB;gBACtFqE,WAAWtE;YACb;YACA;gBACE+E,MAAM;gBACNC,UAAU;gBACVZ,OAAO;gBACPc,QAAQ;oBACNf,QAAQ;oBACRgB,OAAO;oBACPC,QAAQrF;gBACV;gBACAuE,WAAWxE;YACb;YACA,uEAAuE;YACvE,sEAAsE;YACtE,wEAAwE;YACxE,wEAAwE;YACxE,uEAAuE;YACvE,sEAAsE;YACtE;gBACEiF,MAAM;gBACNC,UAAU;gBACVZ,OAAO;gBACPa,aAAa;gBACbJ,YAAY;gBACZP,WAAW5C;YACb;YACA;gBACEqD,MAAM;gBACNC,UAAU;gBACVZ,OAAO;gBACPa,aAAa;gBACbJ,YAAY;gBACZP,WAAWjD;YACb;YACA,wEAAwE;YACxE,gEAAgE;YAChE,wEAAwE;YACxE,qEAAqE;YACrE,uEAAuE;YACvE,qEAAqE;YACrE,2DAA2D;YAC3D;gBACE0D,MAAM;gBACNC,UAAU;gBACVZ,OAAO;gBACPa,aAAa;gBACbJ,YAAY;gBACZQ,qBAAqB;gBACrBC,aAAa;gBACbhB,WAAW9B;YACb;YACA,sEAAsE;YACtE,iEAAiE;YACjE,6BAA6B;YAC7B;gBACEuC,MAAM;gBACNC,UAAU;gBACVZ,OAAO;gBACPa,aAAa;gBACbJ,YAAY;gBACZQ,qBAAqB;gBACrBC,aAAa;gBACbhB,WAAWzB;YACb;YACA;gBACEkC,MAAM;gBACNC,UAAU;gBACVZ,OAAO;gBACPa,aAAa;gBACbJ,YAAY;gBACZQ,qBAAqB;gBACrBC,aAAa;gBACbhB,WAAW1B;YACb;YACA;gBACEmC,MAAM;gBACNC,UAAU;gBACVZ,OAAO;gBACPa,aAAa;gBACbJ,YAAY;gBACZQ,qBAAqB;gBACrBC,aAAa;gBACbhB,WAAW3B;YACb;YACA,qEAAqE;YACrE,qEAAqE;YACrE,2BAA2B;YAC3B,yEAAyE;YACzE,mEAAmE;YACnE,uEAAuE;YACvE,uEAAuE;YACvE,uEAAuE;YACvE,6CAA6C;YAC7C;gBACEoC,MAAM;gBACNC,UAAU;gBACVZ,OAAO;gBACPa,aAAa;gBACbJ,YAAY;gBACZQ,qBAAqB;gBACrBC,aAAa;gBACbhB,WAAW7B;YACb;YACA;gBACEsC,MAAM;gBACNC,UAAU;gBACVZ,OAAO;gBACPa,aAAa;gBACbJ,YAAY;gBACZQ,qBAAqB;gBACrBC,aAAa;gBACbhB,WAAW5B;YACb;YACA,oEAAoE;YACpE,uEAAuE;YACvE,mEAAmE;YACnE,qDAAqD;YACrD;gBACEqC,MAAM;gBACNC,UAAU;gBACVZ,OAAO;gBACPa,aAAa;gBACbJ,YAAY;gBACZQ,qBAAqB;gBACrBC,aAAa;gBACbhB,WAAWxB;YACb;YACA,wEAAwE;YACxE,0EAA0E;YAC1E,sEAAsE;YACtE,qEAAqE;YACrE,sEAAsE;YACtE,wEAAwE;YACxE,cAAc;YACd;gBACEiC,MAAM;gBACNC,UAAU;gBACVZ,OAAO;gBACPa,aAAa;gBACbJ,YAAY;gBACZQ,qBAAqB;gBACrBC,aAAa;gBACbhB,WAAW3C;YACb;YACA,qEAAqE;YACrE,mEAAmE;YACnE;gBACEoD,MAAM;gBACNC,UAAU;gBACVZ,OAAO;gBACPa,aAAa;gBACbJ,YAAY;gBACZQ,qBAAqB;gBACrBC,aAAa;gBACbhB,WAAWlC;YACb;YACA;gBACE2C,MAAM;gBACNC,UAAU;gBACVZ,OAAO;gBACPa,aAAa;gBACbJ,YAAY;gBACZQ,qBAAqB;gBACrBC,aAAa;gBACbhB,WAAWnC;YACb;YACA;gBACE4C,MAAM;gBACNC,UAAU;gBACVZ,OAAO;gBACPa,aAAa;gBACbJ,YAAY;gBACZS,aAAa;gBACbhB,WAAWrB;YACb;YACA,gEAAgE;YAChE,oEAAoE;YACpE,2BAA2B;YAC3B;gBACE8B,MAAM;gBACNC,UAAU;gBACVZ,OAAO;gBACPa,aAAa;gBACbJ,YAAY;gBACZS,aAAa;gBACbhB,WAAW1C;YACb;YACA,sEAAsE;YACtE,uEAAuE;YACvE,sDAAsD;YACtD;gBACEmD,MAAM;gBACNC,UAAU;gBACVZ,OAAO;gBACPa,aAAa;gBACbJ,YAAY;gBACZQ,qBAAqB;gBACrBC,aAAa;gBACbhB,WAAWzC;YACb;YACA,8DAA8D;YAC9D,wEAAwE;YACxE,qEAAqE;YACrE,oDAAoD;YACpD;gBACEkD,MAAM;gBACNC,UAAU;gBACVZ,OAAO;gBACPa,aAAa;gBACbJ,YAAY;gBACZQ,qBAAqB;gBACrBC,aAAa;gBACbhB,WAAWxC;YACb;YACA;gBACEiD,MAAM;gBACNC,UAAU;gBACVZ,OAAO;gBACPa,aAAa;gBACbJ,YAAY;gBACZQ,qBAAqB;gBACrBC,aAAa;gBACbhB,WAAWvC;YACb;YACA,qEAAqE;YACrE,kEAAkE;YAClE,uEAAuE;YACvE,qEAAqE;YACrE,uEAAuE;YACvE;gBACEgD,MAAM;gBACNC,UAAU;gBACVZ,OAAO;gBACPa,aAAa;gBACbJ,YAAY;gBACZQ,qBAAqB;gBACrBC,aAAa;gBACbhB,WAAWtC;YACb;YACA;gBACE+C,MAAM;gBACNC,UAAU;gBACVZ,OAAO;gBACPa,aAAa;gBACbJ,YAAY;gBACZS,aAAa;gBACbhB,WAAWpC;YACb;YACA;gBACE6C,MAAM;gBACNC,UAAU;gBACVZ,OAAO;gBACPa,aAAa;gBACbJ,YAAY;gBACZS,aAAa;gBACbhB,WAAWrC;YACb;YACA;gBACE8C,MAAM;gBACNC,UAAU;gBACVZ,OAAO;gBACPa,aAAa;gBACbJ,YAAY;gBACZS,aAAa;gBACbhB,WAAWpB;YACb;YACA,sEAAsE;YACtE,sEAAsE;YACtE,qEAAqE;YACrE,wEAAwE;YACxE,wEAAwE;YACxE,eAAe;YACf;gBACE6B,MAAM;gBACNC,UAAU;gBACVZ,OAAO;gBACPa,aAAa;gBACbJ,YAAY;gBACZP,WAAW/B;YACb;YACA;gBACEwC,MAAM;gBACNC,UAAU;gBACVZ,OAAO;gBACPa,aAAa;gBACbJ,YAAY;gBACZP,WAAWjC;YACb;YACA;gBACE0C,MAAM;gBACNC,UAAU;gBACVZ,OAAO;gBACPa,aAAa;gBACbJ,YAAY;gBACZP,WAAWhC;YACb;YACA,sEAAsE;YACtE,sEAAsE;YACtE,uEAAuE;YACvE,oEAAoE;YACpE,oEAAoE;YACpE,kDAAkD;YAClD;gBACEyC,MAAM;gBACNC,UAAU;gBACVZ,OAAO;gBACPa,aAAa;gBACbJ,YAAY;gBACZP,WAAW7C;YACb;YACA,mEAAmE;YACnE,uEAAuE;YACvE,kEAAkE;YAClE,iEAAiE;YACjE,sEAAsE;YACtE,kBAAkB;YAClB;gBACEsD,MAAM;gBACNC,UAAU;gBACVZ,OAAO;gBACPa,aAAa;gBACbJ,YAAY;gBACZP,WAAW/C;YACb;YACA,qEAAqE;YACrE,qEAAqE;YACrE,sEAAsE;YACtE,sEAAsE;YACtE;gBACEwD,MAAM;gBACNC,UAAU;gBACVZ,OAAO,CAAC,KAAK,EAAExF,cAAc,QAAQ,CAAC;gBACtCqG,aAAa;gBACbX,WAAW9C;YACb;YACA,kEAAkE;YAClE,qEAAqE;YACrE,oEAAoE;YACpE,sEAAsE;YACtE,cAAc;YACd;gBACEuD,MAAM;gBACNC,UAAU;gBACVZ,OAAO;gBACPa,aAAa;gBACbJ,YAAY;gBACZP,WAAWhD;YACb;YACA,qEAAqE;YACrE,sEAAsE;YACtE,uEAAuE;YACvE,uEAAuE;YACvE,mEAAmE;YACnE,sEAAsE;YACtE;gBACEyD,MAAM;gBACNC,UAAU;gBACVZ,OAAO;gBACPa,aAAa;gBACbJ,YAAY;gBACZP,WAAWf;YACb;YACA;gBACEwB,MAAM;gBACNC,UAAU;gBACVZ,OAAO;gBACPa,aAAa;gBACbJ,YAAY;gBACZS,aAAa;gBACbhB,WAAWb;YACb;YACA,+DAA+D;YAC/D,sEAAsE;YACtE,6CAA6C;YAC7C;gBACEsB,MAAM;gBACNC,UAAU;gBACVZ,OAAO;gBACPa,aAAa;gBACbJ,YAAY;gBACZQ,qBAAqB;gBACrBC,aAAa;gBACbhB,WAAWZ;YACb;YACA;gBACEqB,MAAM;gBACNC,UAAU;gBACVZ,OAAO;gBACPa,aAAa;gBACbJ,YAAY;gBACZP,WAAWd;YACb;YACA,iEAAiE;YACjE,uEAAuE;YACvE,sEAAsE;YACtE,wEAAwE;YACxE,uEAAuE;YACvE,2EAA2E;YAC3E,qEAAqE;YACrE,oBAAoB;YACpB;gBACEuB,MAAM;gBACNC,UAAU;gBACVZ,OAAO;gBACPa,aAAa;gBACbJ,YAAY;gBACZS,aAAa;gBACbhB,WAAWtB;YACb;YACA;gBACE+B,MAAM;gBACNC,UAAU;gBACVZ,OAAO;gBACPa,aAAa;gBACbJ,YAAY;gBACZS,aAAa;gBACbhB,WAAWvB;YACb;YACA,iEAAiE;YACjE,sEAAsE;YACtE,sEAAsE;YACtE,uEAAuE;YACvE,oEAAoE;YACpE;gBACEgC,MAAM;gBACNC,UAAU;gBACVZ,OAAO;gBACPa,aAAa;gBACbJ,YAAY;gBACZQ,qBAAqB;gBACrBC,aAAa;gBACbhB,WAAWjB;YACb;YACA;gBACE0B,MAAM;gBACNC,UAAU;gBACVZ,OAAO;gBACPa,aAAa;gBACbJ,YAAY;gBACZS,aAAa;gBACbhB,WAAWhB;YACb;YACA,oEAAoE;YACpE,qEAAqE;YACrE,mEAAmE;YACnE,sEAAsE;YACtE,iCAAiC;YACjC;gBACEyB,MAAM;gBACNC,UAAU;gBACVZ,OAAO;gBACPa,aAAa;gBACbJ,YAAY;gBACZQ,qBAAqB;gBACrBC,aAAa;gBACbhB,WAAWnB;YACb;YACA,oEAAoE;YACpE,sEAAsE;YACtE,uEAAuE;YACvE,0CAA0C;YAC1C;gBACE4B,MAAM;gBACNC,UAAU;gBACVZ,OAAO;gBACPa,aAAa;gBACbJ,YAAY;gBACZQ,qBAAqB;gBACrBC,aAAa;gBACbhB,WAAWlB;YACb;SACD;IACH;AACF"}
|