@aglyn/plugins-ai 1.0.0-beta.240 → 1.0.0-beta.241

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (87) hide show
  1. package/package.json +17 -17
  2. package/src/lib/components/ai-job-links.d.ts +17 -0
  3. package/src/lib/components/ai-job-links.js +63 -0
  4. package/src/lib/components/ai-job-links.js.map +1 -1
  5. package/src/lib/components/ai-job-plan.component.js +8 -1
  6. package/src/lib/components/ai-job-plan.component.js.map +1 -1
  7. package/src/lib/components/ai-site-build-page.component.js +7 -1
  8. package/src/lib/components/ai-site-build-page.component.js.map +1 -1
  9. package/src/lib/components/ai-store-finish-card.component.d.ts +28 -0
  10. package/src/lib/components/ai-store-finish-card.component.js +116 -0
  11. package/src/lib/components/ai-store-finish-card.component.js.map +1 -0
  12. package/src/lib/components/assist-build-card.component.js +12 -1
  13. package/src/lib/components/assist-build-card.component.js.map +1 -1
  14. package/src/lib/jobs/ai-job-build-step.d.ts +45 -1
  15. package/src/lib/jobs/ai-job-build-step.js +283 -7
  16. package/src/lib/jobs/ai-job-build-step.js.map +1 -1
  17. package/src/lib/jobs/ai-job-drafts.d.ts +9 -1
  18. package/src/lib/jobs/ai-job-drafts.js +4 -1
  19. package/src/lib/jobs/ai-job-drafts.js.map +1 -1
  20. package/src/lib/jobs/ai-job-layout-language.d.ts +3 -0
  21. package/src/lib/jobs/ai-job-layout-language.js +4 -2
  22. package/src/lib/jobs/ai-job-layout-language.js.map +1 -1
  23. package/src/lib/jobs/ai-job-layout-step.js +3 -1
  24. package/src/lib/jobs/ai-job-layout-step.js.map +1 -1
  25. package/src/lib/jobs/ai-job-page-language.d.ts +2 -1
  26. package/src/lib/jobs/ai-job-page-language.js +19 -7
  27. package/src/lib/jobs/ai-job-page-language.js.map +1 -1
  28. package/src/lib/jobs/ai-job-page-sections.d.ts +11 -0
  29. package/src/lib/jobs/ai-job-page-sections.js +40 -3
  30. package/src/lib/jobs/ai-job-page-sections.js.map +1 -1
  31. package/src/lib/jobs/ai-job-page-step.d.ts +2 -1
  32. package/src/lib/jobs/ai-job-page-step.js +19 -8
  33. package/src/lib/jobs/ai-job-page-step.js.map +1 -1
  34. package/src/lib/jobs/ai-job-plan-step.d.ts +12 -0
  35. package/src/lib/jobs/ai-job-plan-step.js +41 -7
  36. package/src/lib/jobs/ai-job-plan-step.js.map +1 -1
  37. package/src/lib/jobs/ai-job-site-datasets.d.ts +76 -2
  38. package/src/lib/jobs/ai-job-site-datasets.js +206 -13
  39. package/src/lib/jobs/ai-job-site-datasets.js.map +1 -1
  40. package/src/lib/jobs/ai-job-site-step.d.ts +18 -2
  41. package/src/lib/jobs/ai-job-site-step.js +109 -22
  42. package/src/lib/jobs/ai-job-site-step.js.map +1 -1
  43. package/src/lib/jobs/ai-job-site-store-pages.d.ts +75 -0
  44. package/src/lib/jobs/ai-job-site-store-pages.js +195 -0
  45. package/src/lib/jobs/ai-job-site-store-pages.js.map +1 -0
  46. package/src/lib/jobs/ai-job-store-links-layout.d.ts +71 -0
  47. package/src/lib/jobs/ai-job-store-links-layout.js +95 -0
  48. package/src/lib/jobs/ai-job-store-links-layout.js.map +1 -0
  49. package/src/lib/jobs/ai-layout-stock-photos.d.ts +69 -3
  50. package/src/lib/jobs/ai-layout-stock-photos.js +603 -42
  51. package/src/lib/jobs/ai-layout-stock-photos.js.map +1 -1
  52. package/src/lib/jobs/ai-site-publish.d.ts +18 -0
  53. package/src/lib/jobs/ai-site-publish.js +76 -15
  54. package/src/lib/jobs/ai-site-publish.js.map +1 -1
  55. package/src/lib/jobs/fixtures/ai-stock-photo-ember-oak-hits.d.ts +43 -0
  56. package/src/lib/jobs/fixtures/ai-stock-photo-ember-oak-hits.js +61 -0
  57. package/src/lib/jobs/fixtures/ai-stock-photo-ember-oak-hits.js.map +1 -0
  58. package/src/lib/layout-language/ai-layout-compiler.js +25 -2
  59. package/src/lib/layout-language/ai-layout-compiler.js.map +1 -1
  60. package/src/lib/layout-language/ai-layout-frame.d.ts +10 -0
  61. package/src/lib/layout-language/ai-layout-frame.js +58 -4
  62. package/src/lib/layout-language/ai-layout-frame.js.map +1 -1
  63. package/src/lib/layout-language/ai-layout-listings.d.ts +6 -0
  64. package/src/lib/layout-language/ai-layout-listings.js +3 -0
  65. package/src/lib/layout-language/ai-layout-listings.js.map +1 -1
  66. package/src/lib/model/ai-build-job.d.ts +2 -0
  67. package/src/lib/model/ai-build-job.js +23 -3
  68. package/src/lib/model/ai-build-job.js.map +1 -1
  69. package/src/lib/model/ai-build-plan.d.ts +7 -0
  70. package/src/lib/model/ai-build-plan.js.map +1 -1
  71. package/src/lib/model/ai-build-progress.js +3 -1
  72. package/src/lib/model/ai-build-progress.js.map +1 -1
  73. package/src/lib/model/ai-build-store-pages.d.ts +133 -0
  74. package/src/lib/model/ai-build-store-pages.js +209 -0
  75. package/src/lib/model/ai-build-store-pages.js.map +1 -0
  76. package/src/lib/model/ai-layout-store-links.d.ts +64 -0
  77. package/src/lib/model/ai-layout-store-links.js +165 -0
  78. package/src/lib/model/ai-layout-store-links.js.map +1 -0
  79. package/src/lib/model/ai-site-inventory.d.ts +5 -0
  80. package/src/lib/model/ai-site-inventory.js.map +1 -1
  81. package/src/lib/model/ai-site-store-pages.d.ts +192 -0
  82. package/src/lib/model/ai-site-store-pages.js +383 -0
  83. package/src/lib/model/ai-site-store-pages.js.map +1 -0
  84. package/src/lib/runtime/site-inventory.js +8 -3
  85. package/src/lib/runtime/site-inventory.js.map +1 -1
  86. package/src/lib/testing/stand-in-dataset-index.js +8 -4
  87. package/src/lib/testing/stand-in-dataset-index.js.map +1 -1
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aglyn/plugins-ai",
3
- "version": "1.0.0-beta.240",
3
+ "version": "1.0.0-beta.241",
4
4
  "license": "Apache-2.0",
5
5
  "homepage": "https://aglyn.com",
6
6
  "repository": {
@@ -25,22 +25,22 @@
25
25
  "./package.json": "./package.json"
26
26
  },
27
27
  "dependencies": {
28
- "@aglyn/aglyn": "1.0.0-beta.240",
29
- "@aglyn/shared-data-enums": "1.0.0-beta.240",
30
- "@aglyn/shared-data-mdi": "1.0.0-beta.240",
31
- "@aglyn/shared-data-types": "1.0.0-beta.240",
32
- "@aglyn/shared-ui-email-campaigns": "1.0.0-beta.240",
33
- "@aglyn/shared-ui-jsx": "1.0.0-beta.240",
34
- "@aglyn/shared-ui-snackstack": "1.0.0-beta.240",
35
- "@aglyn/shared-ui-theme": "1.0.0-beta.240",
36
- "@aglyn/shared-util-email": "1.0.0-beta.240",
37
- "@aglyn/shared-util-errors": "1.0.0-beta.240",
38
- "@aglyn/shared-util-http": "1.0.0-beta.240",
39
- "@aglyn/shared-util-timestamp": "1.0.0-beta.240",
40
- "@aglyn/shared-util-tools": "1.0.0-beta.240",
41
- "@aglyn/tenant-data-admin": "1.0.0-beta.240",
42
- "@aglyn/tenant-feature-instance": "1.0.0-beta.240",
43
- "@aglyn/tenant-runtime": "1.0.0-beta.240",
28
+ "@aglyn/aglyn": "1.0.0-beta.241",
29
+ "@aglyn/shared-data-enums": "1.0.0-beta.241",
30
+ "@aglyn/shared-data-mdi": "1.0.0-beta.241",
31
+ "@aglyn/shared-data-types": "1.0.0-beta.241",
32
+ "@aglyn/shared-ui-email-campaigns": "1.0.0-beta.241",
33
+ "@aglyn/shared-ui-jsx": "1.0.0-beta.241",
34
+ "@aglyn/shared-ui-snackstack": "1.0.0-beta.241",
35
+ "@aglyn/shared-ui-theme": "1.0.0-beta.241",
36
+ "@aglyn/shared-util-email": "1.0.0-beta.241",
37
+ "@aglyn/shared-util-errors": "1.0.0-beta.241",
38
+ "@aglyn/shared-util-http": "1.0.0-beta.241",
39
+ "@aglyn/shared-util-timestamp": "1.0.0-beta.241",
40
+ "@aglyn/shared-util-tools": "1.0.0-beta.241",
41
+ "@aglyn/tenant-data-admin": "1.0.0-beta.241",
42
+ "@aglyn/tenant-feature-instance": "1.0.0-beta.241",
43
+ "@aglyn/tenant-runtime": "1.0.0-beta.241",
44
44
  "@swc/helpers": "0.5.23"
45
45
  },
46
46
  "peerDependencies": {
@@ -1,5 +1,6 @@
1
1
  import { AI_SITE_BUILD_HREF } from '../model/ai-job-notice';
2
2
  import type { AiJobOutput, AiJobSummary } from '../model/ai-jobs.types';
3
+ import { type AiStoreFinishStep } from '../model/ai-site-store-pages';
3
4
  /**
4
5
  * Where "open draft" goes, or `null` when the output has no page of its
5
6
  * own — a `text` output carries its copy on the job and is shown inline.
@@ -46,3 +47,19 @@ export declare function aiSiteBuildDoneLinks(job: Pick<AiJobSummary, 'outputs'>,
46
47
  * door the AI credits meter's own upgrade link opens.
47
48
  */
48
49
  export declare function aiCreditsBillingHref(orgSlug: string): string;
50
+ /** One thing left to finish an AI-built store, with where it is done. */
51
+ export interface AiStoreFinishLink extends AiStoreFinishStep {
52
+ /** The console page it is done on; `null` where the owner of that page is not loaded. */
53
+ href: string | null;
54
+ }
55
+ /**
56
+ * What is left to finish a store a site start built (AGL-3676), or `null`
57
+ * where the start built no store's own pages: its account, cart and policy
58
+ * pages are written, so payments, products, shipping and tax, and the
59
+ * policies' brackets are all that remain. Each links the exact console page:
60
+ * the store's settings and its catalog, as the commerce plugin publishes
61
+ * them, and the site's Pages.
62
+ */
63
+ export declare function aiStoreFinishLinks(job: Pick<AiJobSummary, 'kind' | 'status' | 'items' | 'outputs'> & Partial<Pick<AiJobSummary, 'sitePublish'>>, orgSlug: string): AiStoreFinishLink[] | null;
64
+ /** What a build's "Review your products" step says: its products are drafts, priced only where the request said. */
65
+ export declare const AI_BUILD_STORE_PRODUCTS_TEXT = "Your new products are drafts. Set their prices, photos and stock, then make them active so they show in your store.";
@@ -1,3 +1,4 @@
1
+ import { _ as _extends } from "@swc/helpers/_/_extends";
1
2
  /**
2
3
  * @license
3
4
  * Copyright 2026 Aglyn LLC
@@ -16,6 +17,8 @@
16
17
  */ import { buildRoute, Route } from "@aglyn/aglyn/app-utils/console-routes";
17
18
  import { pluginRecordHref, pluginRecordListHref } from "@aglyn/aglyn/plugin-manager/plugin-record-routes";
18
19
  import { AI_JOB_BESIGNER_SEGMENT as BESIGNER_SEGMENT, AI_SITE_BUILD_HREF } from "../model/ai-job-notice.js";
20
+ import { AI_STORE_FINISH_STEPS } from "../model/ai-site-store-pages.js";
21
+ import { AI_BUILD_STORE_LINKS_DRAFT_STEP, AI_BUILD_STORE_LINKS_MISSING_STEP } from "../model/ai-build-store-pages.js";
19
22
  // Where a job's work opens in the console (AGL-2904), shared by the AI jobs
20
23
  // drawer and every dialog that follows the job it started (AGL-3593).
21
24
  /**
@@ -166,5 +169,65 @@ export { AI_SITE_BUILD_HREF };
166
169
  orgSlug
167
170
  })}#plans`;
168
171
  }
172
+ /**
173
+ * What is left to finish a store a site start built (AGL-3676), or `null`
174
+ * where the start built no store's own pages: its account, cart and policy
175
+ * pages are written, so payments, products, shipping and tax, and the
176
+ * policies' brackets are all that remain. Each links the exact console page:
177
+ * the store's settings and its catalog, as the commerce plugin publishes
178
+ * them, and the site's Pages.
179
+ */ export function aiStoreFinishLinks(job, orgSlug) {
180
+ var _job_items;
181
+ var _job_outputs_find, _job_sitePublish;
182
+ // A site start's store, or an Assist build that made the site a store (AGL-3676).
183
+ if (job.kind !== 'site' && job.kind !== 'build' || job.status !== 'done' || !orgSlug) return null;
184
+ const row = ((_job_items = job.items) != null ? _job_items : []).find((one)=>one.slot === 'store');
185
+ if (!row || row.status !== 'succeeded' && row.status !== 'degraded') return null;
186
+ const host = (_job_outputs_find = job.outputs.find((output)=>output.resource === 'screen' && output.hostSubdomain)) == null ? void 0 : _job_outputs_find.hostSubdomain;
187
+ if (!host) return null;
188
+ const context = {
189
+ orgSlug,
190
+ host: String(host)
191
+ };
192
+ // A build's products are drafts with no price unless asked, and it may
193
+ // have written none of the policies (the site had them): its list says so.
194
+ const build = job.kind === 'build';
195
+ const mine = job.outputs.filter((output)=>row.outputs.includes(output.id));
196
+ const written = new Set(mine.map((output)=>{
197
+ var _output_proposal;
198
+ return (_output_proposal = output.proposal) == null ? void 0 : _output_proposal['storePage'];
199
+ }));
200
+ const policies = !build || [
201
+ 'shipping',
202
+ 'privacy',
203
+ 'terms'
204
+ ].some((key)=>written.has(key));
205
+ const steps = AI_STORE_FINISH_STEPS.filter((step)=>step.id !== 'policies' || policies).map((step)=>_extends({}, step, build && step.id === 'products' ? {
206
+ text: AI_BUILD_STORE_PRODUCTS_TEXT
207
+ } : {}, {
208
+ href: step.opens === 'pages' ? buildRoute(Route.HOST_SCREENS, context) : step.opens === 'layouts' || step.opens === 'layout' ? buildRoute(Route.HOST_LAYOUTS, context) : pluginRecordListHref(step.opens, context)
209
+ }));
210
+ if (!build) return steps;
211
+ // The site's own header and footer (AGL-3676): links it had no list for are
212
+ // the owner's to add; links drafted into it wait for its publish.
213
+ if (mine.some((output)=>{
214
+ var _output_proposal;
215
+ return ((_output_proposal = output.proposal) == null ? void 0 : _output_proposal['storeLinks']) === 'missing';
216
+ })) {
217
+ steps.push(_extends({}, AI_BUILD_STORE_LINKS_MISSING_STEP, {
218
+ href: buildRoute(Route.HOST_LAYOUTS, context)
219
+ }));
220
+ }
221
+ const draft = mine.find((output)=>{
222
+ var _output_proposal;
223
+ return output.resource === 'layout' && ((_output_proposal = output.proposal) == null ? void 0 : _output_proposal['storeLinks']) === 'draft';
224
+ });
225
+ const live = draft && ((_job_sitePublish = job.sitePublish) == null ? void 0 : _job_sitePublish.published.length);
226
+ if (draft && !live) steps.push(_extends({}, AI_BUILD_STORE_LINKS_DRAFT_STEP, {
227
+ href: aiJobOutputHref(draft, orgSlug)
228
+ }));
229
+ return steps;
230
+ }
231
+ /** What a build's "Review your products" step says: its products are drafts, priced only where the request said. */ export const AI_BUILD_STORE_PRODUCTS_TEXT = 'Your new products are drafts. Set their prices, photos and stock, then make them active so they show in your store.';
169
232
 
170
233
  //# sourceMappingURL=ai-job-links.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../../../libs/plugins/ai/src/lib/components/ai-job-links.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 */\nimport { buildRoute, Route } from '@aglyn/aglyn/app-utils/console-routes'\nimport {\n pluginRecordHref,\n pluginRecordListHref,\n} from '@aglyn/aglyn/plugin-manager/plugin-record-routes'\nimport { AI_JOB_BESIGNER_SEGMENT as BESIGNER_SEGMENT, AI_SITE_BUILD_HREF } from '../model/ai-job-notice'\nimport type { AiJobOutput, AiJobSummary } from '../model/ai-jobs.types'\n\n// Where a job's work opens in the console (AGL-2904), shared by the AI jobs\n// drawer and every dialog that follows the job it started (AGL-3593).\n\n/**\n * Where \"open draft\" goes, or `null` when the output has no page of its\n * own — a `text` output carries its copy on the job and is shown inline.\n * A versioned resource opens in the besigner on the version the job wrote;\n * one the console lists without a detail page opens its list; a `theme`\n * proposal opens the site's Theme section, where it is put in the editor.\n *\n * A console URL names a site by its SUBDOMAIN: the `[host]` segment resolves\n * through the member's host projection by subdomain, never by document id.\n * So an output that carries no `hostSubdomain` gets no link rather than one\n * that opens no site.\n */\nexport function aiJobOutputHref(output: AiJobOutput, orgSlug: string): string | null {\n const host = output.hostSubdomain\n if (!orgSlug || !host) return null\n const segment = BESIGNER_SEGMENT[output.resource]\n if (segment) {\n const base = `/${orgSlug}/hosts/${host}/${segment}/${output.id}`\n return output.versionId ? `${base}/versions/${output.versionId}/besigner` : base\n }\n if (output.resource === 'product') {\n // The catalog a drafted product lands in: the commerce plugin's address\n // for it (AGL-3080), or no link where commerce is not loaded.\n return pluginRecordListHref('product', { orgSlug, host })\n }\n if (output.resource === 'workflow') {\n // A drafted automation is an action (AGL-2919), listed switched off on\n // the workflows plugin's list of actions, or no link where it is not loaded.\n return pluginRecordListHref('action', { orgSlug, host })\n }\n if (output.resource === 'entry') {\n // A post a guided start wrote (AGL-3676) opens in its blog's list in Content.\n const collectionSlug = output.proposal?.['collectionSlug']\n return typeof collectionSlug === 'string' && collectionSlug\n ? buildRoute(Route.HOST_CONTENT_COLLECTION, { orgSlug, host, collectionSlug })\n : buildRoute(Route.HOST_CONTENT, { orgSlug, host })\n }\n if (output.resource === 'theme') {\n return buildRoute(Route.HOST_SETUP_THEME, { orgSlug, host })\n }\n if (output.resource === 'draft' && output.draftResource) {\n // A draft another plugin wrote — a dataset a site start or a build made\n // (AGL-3616) — opens where its owner lists it, or nowhere it is not loaded.\n return pluginRecordListHref(output.draftResource, { orgSlug, host })\n }\n if (output.resource === 'form') {\n // A new form has no version for the besigner to open: its own page — the\n // forms plugin's address for it — mints the first one, and holds the\n // routing and consent it declares.\n return pluginRecordHref('form', { orgSlug, host }, output.id)\n }\n if (output.resource === 'campaign') {\n // A campaign's page is the marketing plugin's, under the site: its\n // address for the campaign (AGL-3080), or no link where it is not loaded.\n return pluginRecordHref('campaign', { orgSlug, host }, output.id)\n }\n return null\n}\n\n/**\n * The ONE action a finished job's row, its notification and the dialog that\n * started it lead with (AGL-3593): what the job built. Several pages from one\n * job — a site's — open the site's Pages list, where they wait as drafts; one\n * output with a page of its own opens that page; anything else has no single\n * place to go, and the row's own links stand. `null` until the job is done.\n */\nexport function aiJobPrimaryLink(\n job: Pick<AiJobSummary, 'status' | 'outputs'>,\n orgSlug: string,\n): { href: string; label: string } | null {\n if (job.status !== 'done' || !orgSlug) return null\n const screens = job.outputs.filter(\n (output) => output.resource === 'screen' && output.hostSubdomain,\n )\n if (screens.length > 1) {\n return {\n href: buildRoute(Route.HOST_SCREENS, { orgSlug, host: String(screens[0].hostSubdomain) }),\n label: 'Open your draft pages',\n }\n }\n for (const output of job.outputs) {\n const href = aiJobOutputHref(output, orgSlug)\n if (href) {\n return {\n href,\n label: output.resource === 'screen' ? 'Open the draft page' : `Open ${output.label}`,\n }\n }\n }\n return null\n}\n\nexport { AI_SITE_BUILD_HREF }\n\n/**\n * The \"Building your site\" page for one site job (AGL-3594): linkable, so the\n * guided start lands on it, a reload keeps it and a notification opens it.\n * `null` without the org slug or the site's subdomain a console URL needs.\n */\nexport function aiSiteBuildHref(\n orgSlug: string | null | undefined,\n hostSubdomain: string | null | undefined,\n jobId: string,\n): string | null {\n if (!orgSlug || !hostSubdomain || !jobId) return null\n return `/${orgSlug}/hosts/${hostSubdomain}${AI_SITE_BUILD_HREF}/${encodeURIComponent(jobId)}`\n}\n\n/**\n * A finished site's two ways in (AGL-3594): its first page's draft, opened in\n * the console's preview of that version, and the Pages list every draft waits\n * in. Either is `null` where the job reported nothing to open.\n */\nexport function aiSiteBuildDoneLinks(\n job: Pick<AiJobSummary, 'outputs'>,\n orgSlug: string,\n): { view: string | null; pages: string | null } {\n const screens = job.outputs.filter((output) => output.resource === 'screen' && output.hostSubdomain)\n const first = screens[0]\n if (!first || !orgSlug) return { view: null, pages: null }\n const host = String(first.hostSubdomain)\n return {\n view: first.versionId\n ? `/${orgSlug}/hosts/${host}/screens/${first.id}/versions/${first.versionId}/view`\n : null,\n pages: buildRoute(Route.HOST_SCREENS, { orgSlug, host }),\n }\n}\n\n/**\n * Where a person gets more AI credits (AGL-3660): the workspace's Billing\n * page at its plans, where an upgrade and the AI add-on are both sold — the\n * door the AI credits meter's own upgrade link opens.\n */\nexport function aiCreditsBillingHref(orgSlug: string): string {\n return `${buildRoute(Route.MANAGE_BILLING, { orgSlug })}#plans`\n}\n"],"names":["buildRoute","Route","pluginRecordHref","pluginRecordListHref","AI_JOB_BESIGNER_SEGMENT","BESIGNER_SEGMENT","AI_SITE_BUILD_HREF","aiJobOutputHref","output","orgSlug","host","hostSubdomain","segment","resource","base","id","versionId","collectionSlug","proposal","HOST_CONTENT_COLLECTION","HOST_CONTENT","HOST_SETUP_THEME","draftResource","aiJobPrimaryLink","job","status","screens","outputs","filter","length","href","HOST_SCREENS","String","label","aiSiteBuildHref","jobId","encodeURIComponent","aiSiteBuildDoneLinks","first","view","pages","aiCreditsBillingHref","MANAGE_BILLING"],"mappings":"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"}
1
+ {"version":3,"sources":["../../../../../../../libs/plugins/ai/src/lib/components/ai-job-links.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 */\nimport { buildRoute, Route } from '@aglyn/aglyn/app-utils/console-routes'\nimport {\n pluginRecordHref,\n pluginRecordListHref,\n} from '@aglyn/aglyn/plugin-manager/plugin-record-routes'\nimport { AI_JOB_BESIGNER_SEGMENT as BESIGNER_SEGMENT, AI_SITE_BUILD_HREF } from '../model/ai-job-notice'\nimport type { AiJobOutput, AiJobSummary } from '../model/ai-jobs.types'\nimport { AI_STORE_FINISH_STEPS, type AiStoreFinishStep } from '../model/ai-site-store-pages'\nimport { AI_BUILD_STORE_LINKS_DRAFT_STEP, AI_BUILD_STORE_LINKS_MISSING_STEP } from '../model/ai-build-store-pages'\n\n// Where a job's work opens in the console (AGL-2904), shared by the AI jobs\n// drawer and every dialog that follows the job it started (AGL-3593).\n\n/**\n * Where \"open draft\" goes, or `null` when the output has no page of its\n * own — a `text` output carries its copy on the job and is shown inline.\n * A versioned resource opens in the besigner on the version the job wrote;\n * one the console lists without a detail page opens its list; a `theme`\n * proposal opens the site's Theme section, where it is put in the editor.\n *\n * A console URL names a site by its SUBDOMAIN: the `[host]` segment resolves\n * through the member's host projection by subdomain, never by document id.\n * So an output that carries no `hostSubdomain` gets no link rather than one\n * that opens no site.\n */\nexport function aiJobOutputHref(output: AiJobOutput, orgSlug: string): string | null {\n const host = output.hostSubdomain\n if (!orgSlug || !host) return null\n const segment = BESIGNER_SEGMENT[output.resource]\n if (segment) {\n const base = `/${orgSlug}/hosts/${host}/${segment}/${output.id}`\n return output.versionId ? `${base}/versions/${output.versionId}/besigner` : base\n }\n if (output.resource === 'product') {\n // The catalog a drafted product lands in: the commerce plugin's address\n // for it (AGL-3080), or no link where commerce is not loaded.\n return pluginRecordListHref('product', { orgSlug, host })\n }\n if (output.resource === 'workflow') {\n // A drafted automation is an action (AGL-2919), listed switched off on\n // the workflows plugin's list of actions, or no link where it is not loaded.\n return pluginRecordListHref('action', { orgSlug, host })\n }\n if (output.resource === 'entry') {\n // A post a guided start wrote (AGL-3676) opens in its blog's list in Content.\n const collectionSlug = output.proposal?.['collectionSlug']\n return typeof collectionSlug === 'string' && collectionSlug\n ? buildRoute(Route.HOST_CONTENT_COLLECTION, { orgSlug, host, collectionSlug })\n : buildRoute(Route.HOST_CONTENT, { orgSlug, host })\n }\n if (output.resource === 'theme') {\n return buildRoute(Route.HOST_SETUP_THEME, { orgSlug, host })\n }\n if (output.resource === 'draft' && output.draftResource) {\n // A draft another plugin wrote — a dataset a site start or a build made\n // (AGL-3616) — opens where its owner lists it, or nowhere it is not loaded.\n return pluginRecordListHref(output.draftResource, { orgSlug, host })\n }\n if (output.resource === 'form') {\n // A new form has no version for the besigner to open: its own page — the\n // forms plugin's address for it — mints the first one, and holds the\n // routing and consent it declares.\n return pluginRecordHref('form', { orgSlug, host }, output.id)\n }\n if (output.resource === 'campaign') {\n // A campaign's page is the marketing plugin's, under the site: its\n // address for the campaign (AGL-3080), or no link where it is not loaded.\n return pluginRecordHref('campaign', { orgSlug, host }, output.id)\n }\n return null\n}\n\n/**\n * The ONE action a finished job's row, its notification and the dialog that\n * started it lead with (AGL-3593): what the job built. Several pages from one\n * job — a site's — open the site's Pages list, where they wait as drafts; one\n * output with a page of its own opens that page; anything else has no single\n * place to go, and the row's own links stand. `null` until the job is done.\n */\nexport function aiJobPrimaryLink(\n job: Pick<AiJobSummary, 'status' | 'outputs'>,\n orgSlug: string,\n): { href: string; label: string } | null {\n if (job.status !== 'done' || !orgSlug) return null\n const screens = job.outputs.filter(\n (output) => output.resource === 'screen' && output.hostSubdomain,\n )\n if (screens.length > 1) {\n return {\n href: buildRoute(Route.HOST_SCREENS, { orgSlug, host: String(screens[0].hostSubdomain) }),\n label: 'Open your draft pages',\n }\n }\n for (const output of job.outputs) {\n const href = aiJobOutputHref(output, orgSlug)\n if (href) {\n return {\n href,\n label: output.resource === 'screen' ? 'Open the draft page' : `Open ${output.label}`,\n }\n }\n }\n return null\n}\n\nexport { AI_SITE_BUILD_HREF }\n\n/**\n * The \"Building your site\" page for one site job (AGL-3594): linkable, so the\n * guided start lands on it, a reload keeps it and a notification opens it.\n * `null` without the org slug or the site's subdomain a console URL needs.\n */\nexport function aiSiteBuildHref(\n orgSlug: string | null | undefined,\n hostSubdomain: string | null | undefined,\n jobId: string,\n): string | null {\n if (!orgSlug || !hostSubdomain || !jobId) return null\n return `/${orgSlug}/hosts/${hostSubdomain}${AI_SITE_BUILD_HREF}/${encodeURIComponent(jobId)}`\n}\n\n/**\n * A finished site's two ways in (AGL-3594): its first page's draft, opened in\n * the console's preview of that version, and the Pages list every draft waits\n * in. Either is `null` where the job reported nothing to open.\n */\nexport function aiSiteBuildDoneLinks(\n job: Pick<AiJobSummary, 'outputs'>,\n orgSlug: string,\n): { view: string | null; pages: string | null } {\n const screens = job.outputs.filter((output) => output.resource === 'screen' && output.hostSubdomain)\n const first = screens[0]\n if (!first || !orgSlug) return { view: null, pages: null }\n const host = String(first.hostSubdomain)\n return {\n view: first.versionId\n ? `/${orgSlug}/hosts/${host}/screens/${first.id}/versions/${first.versionId}/view`\n : null,\n pages: buildRoute(Route.HOST_SCREENS, { orgSlug, host }),\n }\n}\n\n/**\n * Where a person gets more AI credits (AGL-3660): the workspace's Billing\n * page at its plans, where an upgrade and the AI add-on are both sold — the\n * door the AI credits meter's own upgrade link opens.\n */\nexport function aiCreditsBillingHref(orgSlug: string): string {\n return `${buildRoute(Route.MANAGE_BILLING, { orgSlug })}#plans`\n}\n\n/** One thing left to finish an AI-built store, with where it is done. */\nexport interface AiStoreFinishLink extends AiStoreFinishStep {\n /** The console page it is done on; `null` where the owner of that page is not loaded. */\n href: string | null\n}\n\n/**\n * What is left to finish a store a site start built (AGL-3676), or `null`\n * where the start built no store's own pages: its account, cart and policy\n * pages are written, so payments, products, shipping and tax, and the\n * policies' brackets are all that remain. Each links the exact console page:\n * the store's settings and its catalog, as the commerce plugin publishes\n * them, and the site's Pages.\n */\nexport function aiStoreFinishLinks(\n job: Pick<AiJobSummary, 'kind' | 'status' | 'items' | 'outputs'> & Partial<Pick<AiJobSummary, 'sitePublish'>>,\n orgSlug: string,\n): AiStoreFinishLink[] | null {\n // A site start's store, or an Assist build that made the site a store (AGL-3676).\n if ((job.kind !== 'site' && job.kind !== 'build') || job.status !== 'done' || !orgSlug) return null\n const row = (job.items ?? []).find((one) => one.slot === 'store')\n if (!row || (row.status !== 'succeeded' && row.status !== 'degraded')) return null\n const host = job.outputs.find((output) => output.resource === 'screen' && output.hostSubdomain)?.hostSubdomain\n if (!host) return null\n const context = { orgSlug, host: String(host) }\n // A build's products are drafts with no price unless asked, and it may\n // have written none of the policies (the site had them): its list says so.\n const build = job.kind === 'build'\n const mine = job.outputs.filter((output) => row.outputs.includes(output.id))\n const written = new Set(mine.map((output) => output.proposal?.['storePage']))\n const policies = !build || ['shipping', 'privacy', 'terms'].some((key) => written.has(key))\n const steps: AiStoreFinishLink[] = AI_STORE_FINISH_STEPS.filter((step) => step.id !== 'policies' || policies).map((step) => ({\n ...step,\n ...(build && step.id === 'products' ? { text: AI_BUILD_STORE_PRODUCTS_TEXT } : {}),\n href:\n step.opens === 'pages'\n ? buildRoute(Route.HOST_SCREENS, context)\n : step.opens === 'layouts' || step.opens === 'layout'\n ? buildRoute(Route.HOST_LAYOUTS, context)\n : pluginRecordListHref(step.opens, context),\n }))\n if (!build) return steps\n // The site's own header and footer (AGL-3676): links it had no list for are\n // the owner's to add; links drafted into it wait for its publish.\n if (mine.some((output) => output.proposal?.['storeLinks'] === 'missing')) {\n steps.push({ ...AI_BUILD_STORE_LINKS_MISSING_STEP, href: buildRoute(Route.HOST_LAYOUTS, context) })\n }\n const draft = mine.find((output) => output.resource === 'layout' && output.proposal?.['storeLinks'] === 'draft')\n const live = draft && job.sitePublish?.published.length\n if (draft && !live) steps.push({ ...AI_BUILD_STORE_LINKS_DRAFT_STEP, href: aiJobOutputHref(draft, orgSlug) })\n return steps\n}\n\n/** What a build's \"Review your products\" step says: its products are drafts, priced only where the request said. */\nexport const AI_BUILD_STORE_PRODUCTS_TEXT =\n 'Your new products are drafts. Set their prices, photos and stock, then make them active so they show in your store.'\n"],"names":["buildRoute","Route","pluginRecordHref","pluginRecordListHref","AI_JOB_BESIGNER_SEGMENT","BESIGNER_SEGMENT","AI_SITE_BUILD_HREF","AI_STORE_FINISH_STEPS","AI_BUILD_STORE_LINKS_DRAFT_STEP","AI_BUILD_STORE_LINKS_MISSING_STEP","aiJobOutputHref","output","orgSlug","host","hostSubdomain","segment","resource","base","id","versionId","collectionSlug","proposal","HOST_CONTENT_COLLECTION","HOST_CONTENT","HOST_SETUP_THEME","draftResource","aiJobPrimaryLink","job","status","screens","outputs","filter","length","href","HOST_SCREENS","String","label","aiSiteBuildHref","jobId","encodeURIComponent","aiSiteBuildDoneLinks","first","view","pages","aiCreditsBillingHref","MANAGE_BILLING","aiStoreFinishLinks","kind","row","items","find","one","slot","context","build","mine","includes","written","Set","map","policies","some","key","has","steps","step","text","AI_BUILD_STORE_PRODUCTS_TEXT","opens","HOST_LAYOUTS","push","draft","live","sitePublish","published"],"mappings":"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"}
@@ -21,6 +21,7 @@ import { aiCreditRangeText, aiCreditsPromptFor } from "../model/ai-credit-estima
21
21
  import { aiFreeCreditsResetLabel } from "../model/ai-site-job.js";
22
22
  import { AiCreditsPromptNotice } from "./ai-credits-prompt.component.js";
23
23
  import { aiBuildOpNoun } from "../model/ai-build-progress.js";
24
+ import { aiBuildStorePagesAdded } from "../model/ai-build-store-pages.js";
24
25
  import { aiJobConfirmingOwnPlan } from "../model/ai-job-activity.js";
25
26
  import { aiSiteStarterFallbackOffered } from "../model/ai-job-failure-copy.js";
26
27
  import { AiSiteStarterFallback } from "./ai-site-starter-fallback.component.js";
@@ -165,7 +166,13 @@ export function AiJobPlan({ job, onResume, busy = false, staff = false, user, or
165
166
  variant: "body2",
166
167
  role: "listitem",
167
168
  children: aiPlanEmbedLine(embed, named)
168
- }, `embed-${index}`))
169
+ }, `embed-${index}`)),
170
+ aiBuildStorePagesAdded(plan).map((page)=>/*#__PURE__*/ _jsx(Typography, {
171
+ variant: "body2",
172
+ role: "listitem",
173
+ "data-platform-added": "true",
174
+ children: `Adds the page ${page.title} at ${page.href} — added for your store automatically, uses no AI credits`
175
+ }, `store-${page.key}`))
169
176
  ]
170
177
  }),
171
178
  staff && (review == null ? void 0 : review.detail) && /*#__PURE__*/ _jsx(Typography, {
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../../../libs/plugins/ai/src/lib/components/ai-job-plan.component.tsx"],"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 {\n AI_BUILD_PLAN_CREATION_NOUNS,\n AI_BUILD_PLAN_EMBED_HOST_NAMES,\n isAiPlanNewRef,\n type AiBuildPlanEmbed,\n} from '../model/ai-build-plan'\nimport type { AiJobReview, AiJobSummary } from '../model/ai-jobs.types'\nimport { aiBuildFreePageCapNote, aiBuildSmaller, aiJobCreditRange } from '../model/ai-build-job'\nimport { aiCreditRangeText, aiCreditsPromptFor } from '../model/ai-credit-estimate'\nimport { aiFreeCreditsResetLabel } from '../model/ai-site-job'\nimport { AiCreditsPromptNotice } from './ai-credits-prompt.component'\nimport type { AiJobResumeOptions } from './ai-job-requests'\nimport { aiBuildOpNoun } from '../model/ai-build-progress'\nimport { aiJobConfirmingOwnPlan } from '../model/ai-job-activity'\nimport { aiSiteStarterFallbackOffered } from '../model/ai-job-failure-copy'\nimport { AiSiteStarterFallback } from './ai-site-starter-fallback.component'\nimport { Box, Button, Checkbox, Collapse, FormControlLabel, Stack, Typography } from '@mui/material'\nimport { useState } from 'react'\n\n/**\n * A job's plan and what it waits for (AGL-2935), inside the AI jobs drawer\n * and the dialog that started the job (AGL-3593): what the job reuses from\n * the site, what it creates and why, the screens it builds — and, while the\n * job waits for a person, the one button that confirms the plan or tries a\n * refused step again. Both send the same request (`resumeAiJobRequest`);\n * this renders.\n */\nexport interface AiJobPlanProps {\n job: AiJobSummary\n /**\n * Confirms the plan, or tries the refused step again. A build whose request\n * asked to publish confirms with `publish` when its box is ticked (AGL-3616).\n */\n onResume: (job: AiJobSummary, options?: AiJobResumeOptions) => void\n /** A resume for this job is in flight. */\n busy?: boolean\n /**\n * The viewer is staff (AGL-3078), who can open where a refused answer broke\n * its rules and the outline of those parts, to tell a shape the rules should\n * allow from an answer that ignored its re-ask. A member reads the findings.\n */\n staff?: boolean\n /**\n * The signed-in user, for \"Use the starter site instead\" on a guided start\n * that did not work out (AGL-3594); the action is drawn only when given.\n */\n user?: Parameters<typeof AiSiteStarterFallback>[0]['user']\n /** The workspace's path slug, for the Upgrade a Free build past what is left offers (AGL-3722). */\n orgSlug?: string | null\n}\n\n/**\n * Where a refused answer broke its rules, and the outline of those parts, as\n * lines staff read (AGL-3078): each finding with the nodes or plan entries it\n * names, then each outlined node indented by its depth, with its element, a\n * Grid's layout as written, and the names of what it sets and holds.\n */\nexport function aiJobReviewDetails(review: AiJobReview | null): string[] {\n if (review?.reason !== 'doctrine') return []\n const lines = review.findings.flatMap((finding) => {\n const where = finding.nodeIds?.length\n ? `nodes ${finding.nodeIds.join(', ')}`\n : finding.paths?.length\n ? `at ${finding.paths.join(', ')}`\n : null\n return where ? [`${finding.rule === null ? '' : `Rule ${finding.rule} `}${finding.code}: ${where}`] : []\n })\n for (const node of review.outline ?? []) {\n lines.push(\n [\n `${' '.repeat(node.depth)}${node.id} ${node.componentId}`,\n ...Object.entries(node.grid ?? {}).map(([name, value]) => `${name}=${JSON.stringify(value)}`),\n ...(node.props.length ? [`props ${node.props.join(', ')}`] : []),\n ...(node.sx?.length ? [`sx ${node.sx.join(', ')}`] : []),\n ...(node.children.length ? [`holds ${node.children.join(', ')}`] : []),\n ].join(' · '),\n )\n }\n return lines\n}\n\n/**\n * A third-party player the plan lists, with what it costs the page, read\n * before the member confirms it (rule 16, AGL-3433). The cost is the\n * platform's sentence, never the model's: the player is framed lazily, so its\n * host's code loads when a visitor reaches it, whether or not they press play.\n */\nexport function aiPlanEmbedLine(\n embed: AiBuildPlanEmbed,\n named: (ref: string) => string,\n): string {\n const host = AI_BUILD_PLAN_EMBED_HOST_NAMES[embed.host]\n const where = isAiPlanNewRef(embed.where) ? `the component ${named(embed.where)}` : embed.where\n const link = embed.url ? ` playing ${embed.url}` : ', its link left for you to paste'\n return `Embeds a ${host} player on ${where}${link}, as you asked (“${embed.asked}”). It loads ${host}’s own code when a visitor reaches it, whether or not they press play.`\n}\n\nexport function AiJobPlan({\n job,\n onResume,\n busy = false,\n staff = false,\n user,\n orgSlug,\n}: AiJobPlanProps): JSX.Element | null {\n const [detailsOpen, setDetailsOpen] = useState(false)\n // Unticked until the person ticks it: a build publishes only when its\n // request asked AND they confirm it here (AGL-3616).\n const [publish, setPublish] = useState(false)\n const { plan, review } = job\n if (!plan && !review) return null\n const details = staff ? aiJobReviewDetails(review) : []\n /** A reference as a person reads it: the record's name, or what the plan creates. */\n const named = (ref: string | null): string =>\n !ref\n ? ''\n : isAiPlanNewRef(ref)\n ? ref.slice('new:'.length)\n : (plan?.labels[ref] ?? ref)\n // A plan the machine is confirming itself is not one to confirm (AGL-3596).\n const waiting = job.status === 'needs_review' && review !== null && !aiJobConfirmingOwnPlan(job)\n // The guard rail (AGL-2911): what the plan is estimated to cost is read\n // before it is confirmed, not after it has been spent. An estimate, and\n // said to be one: what it is likely to cost — what builds like it measured\n // — and its ceiling, every pass at its reserve (AGL-3722). A page job\n // counts the creations it builds before its page (AGL-3031).\n const range = plan && waiting && review.reason === 'plan' ? aiJobCreditRange(job.kind, plan) : null\n // A Free build past what is left asks first (AGL-3722): build what fits,\n // the home page first, or upgrade — never a refusal with no way on.\n const freeCredits = review?.freeCredits ?? null\n const prompt =\n plan && range && job.kind === 'build' ? aiCreditsPromptFor(range, freeCredits, aiBuildSmaller(plan)) : null\n // A Free build at its page cap says so (AGL-3722): pages past it were left for a later request.\n const pageCapNote =\n plan && waiting && review.reason === 'plan' && job.kind === 'build'\n ? aiBuildFreePageCapNote(plan, Boolean(freeCredits))\n : null\n const offersPublish = job.kind === 'build' && job.publishAsked === true && waiting && review.reason === 'plan'\n const publishing = offersPublish && publish ? { publish: true } : {}\n return (\n <Box sx={{ mt: 1 }}>\n {plan && (\n <Stack spacing={0.5} role=\"list\" aria-label=\"Plan\">\n <Typography variant=\"caption\" color=\"text.secondary\">\n {plan.status === 'confirmed' ? 'Confirmed plan' : 'Proposed plan'}\n </Typography>\n {plan.reuse.map((entry, index) => (\n <Typography key={`reuse-${index}`} variant=\"body2\" role=\"listitem\">\n Reuses the {entry.kind === 'screen' ? 'page' : entry.kind} {named(entry.id)} — {entry.purpose}\n </Typography>\n ))}\n {plan.create.map((entry, index) => (\n <Typography key={`create-${index}`} variant=\"body2\" role=\"listitem\">\n Creates the {AI_BUILD_PLAN_CREATION_NOUNS[entry.kind].noun} {entry.name}\n {entry.duplicateOf\n ? `, from a copy of ${named(entry.duplicateOf)}`\n : ''}{' '}\n — {entry.why}\n </Typography>\n ))}\n {plan.screens.map((screen, index) => (\n <Typography key={`screen-${index}`} variant=\"body2\" role=\"listitem\">\n {screen.record\n ? `Builds the record template ${screen.title}, a page per record of ${named(screen.record.dataset)} at /${screen.record.base}/…`\n : `Builds the page ${screen.title} at ${screen.slug}`}\n {screen.duplicateOf\n ? `, from a copy of ${named(screen.duplicateOf)}`\n : ''}\n {screen.layout ? ` in ${named(screen.layout)}` : ''}\n {screen.sections.length\n ? `: ${screen.sections.map((section) => section.name).join(', ')}`\n : ''}\n </Typography>\n ))}\n {(plan.items ?? []).map((item) => (\n <Typography key={`item-${item.slot}`} variant=\"body2\" role=\"listitem\">\n {`Makes the ${aiBuildOpNoun(item.op).toLowerCase()} ${item.name}`}\n {item.why ? ` — ${item.why}` : ''}\n </Typography>\n ))}\n {(plan.embeds ?? []).map((embed, index) => (\n <Typography key={`embed-${index}`} variant=\"body2\" role=\"listitem\">\n {aiPlanEmbedLine(embed, named)}\n </Typography>\n ))}\n </Stack>\n )}\n {/*\n A review written for the member (AGL-3594) carries the checks' own\n sentence as `detail`: its findings are then staff reading too, and the\n member reads the job's one sentence alone.\n */}\n {staff && review?.detail && (\n <Typography variant=\"caption\" color=\"text.secondary\" component=\"div\" sx={{ mt: 0.5 }}>\n {review.detail}\n </Typography>\n )}\n {review?.reason === 'doctrine' && review.findings.length > 0 && (staff || !review.detail) && (\n <Box\n component=\"ul\"\n sx={{ my: 0.5, pl: 2.5 }}\n aria-label=\"Building rules broken\"\n >\n {review.findings.map((finding, index) => (\n <Typography\n key={`finding-${index}`}\n component=\"li\"\n variant=\"caption\"\n >\n {finding.message}\n </Typography>\n ))}\n </Box>\n )}\n {details.length > 0 && (\n <Box sx={{ mt: 0.5 }}>\n <Button\n size=\"small\"\n aria-expanded={detailsOpen}\n onClick={() => setDetailsOpen((prior) => !prior)}\n >\n {detailsOpen ? 'Hide what was refused' : 'Show what was refused'}\n </Button>\n <Collapse in={detailsOpen} unmountOnExit>\n <Typography\n variant=\"caption\"\n component=\"pre\"\n aria-label=\"What was refused\"\n sx={{ m: 0, fontFamily: 'monospace', whiteSpace: 'pre', overflowX: 'auto' }}\n >\n {details.join('\\n')}\n </Typography>\n </Collapse>\n </Box>\n )}\n {range && range.ceiling > 0 && (\n <Typography\n variant=\"caption\"\n color=\"text.secondary\"\n sx={{ display: 'block', mt: 1 }}\n >\n {`Estimated cost: ${aiCreditRangeText(range)}. What it costs is what its steps spend.`}\n {freeCredits && !prompt\n ? ` You have ${freeCredits.left.toLocaleString('en-US')} of your free AI credits left this month, until ${aiFreeCreditsResetLabel(freeCredits.resetsOn)}.`\n : ''}\n </Typography>\n )}\n {pageCapNote && (\n <Typography variant=\"caption\" color=\"text.secondary\" sx={{ display: 'block', mt: 0.5 }}>\n {pageCapNote}\n </Typography>\n )}\n {waiting && review.retryRefusal && review.reason !== 'plan' && (\n <Typography variant=\"caption\" color=\"text.secondary\" component=\"div\" sx={{ mt: 1 }}>\n {review.retryRefusal}\n </Typography>\n )}\n {offersPublish && (\n <FormControlLabel\n sx={{ display: 'flex', mt: 1 }}\n control={<Checkbox size=\"small\" checked={publish} onChange={(event) => setPublish(event.target.checked)} />}\n label={<Typography variant=\"body2\">{'Publish the new pages when they are built'}</Typography>}\n />\n )}\n {waiting && prompt && (\n <AiCreditsPromptNotice\n prompt={prompt}\n noun=\"build\"\n orgSlug={orgSlug}\n busy={busy}\n onBuildWhatFits={() => onResume(job, { ...publishing, creditsConfirmed: true })}\n onSmaller={() => onResume(job, { ...publishing, creditsConfirmed: true, reduce: 'first-page' })}\n />\n )}\n {waiting && !prompt && (\n <Button\n size=\"small\"\n variant=\"contained\"\n // Disabled with its reason above when the Free allowance left\n // cannot pay for another try (AGL-3594).\n disabled={busy || (review.reason !== 'plan' && Boolean(review.retryRefusal))}\n onClick={() => onResume(job, offersPublish && publish ? publishing : undefined)}\n sx={{ mt: 1 }}\n >\n {review.reason === 'plan' ? 'Confirm plan' : 'Try again'}\n </Button>\n )}\n {/* A guided start that did not work out can take the starter instead (AGL-3594). */}\n {waiting && user && aiSiteStarterFallbackOffered(job) && <AiSiteStarterFallback job={job} user={user} />}\n </Box>\n )\n}\n\nexport default AiJobPlan\n"],"names":["AI_BUILD_PLAN_CREATION_NOUNS","AI_BUILD_PLAN_EMBED_HOST_NAMES","isAiPlanNewRef","aiBuildFreePageCapNote","aiBuildSmaller","aiJobCreditRange","aiCreditRangeText","aiCreditsPromptFor","aiFreeCreditsResetLabel","AiCreditsPromptNotice","aiBuildOpNoun","aiJobConfirmingOwnPlan","aiSiteStarterFallbackOffered","AiSiteStarterFallback","Box","Button","Checkbox","Collapse","FormControlLabel","Stack","Typography","useState","aiJobReviewDetails","review","reason","lines","findings","flatMap","finding","where","nodeIds","length","join","paths","rule","code","node","outline","push","repeat","depth","id","componentId","Object","entries","grid","map","name","value","JSON","stringify","props","sx","children","aiPlanEmbedLine","embed","named","host","link","url","asked","AiJobPlan","job","onResume","busy","staff","user","orgSlug","plan","detailsOpen","setDetailsOpen","publish","setPublish","details","ref","slice","labels","waiting","status","range","kind","freeCredits","prompt","pageCapNote","Boolean","offersPublish","publishAsked","publishing","mt","spacing","role","aria-label","variant","color","reuse","entry","index","purpose","create","noun","duplicateOf","why","screens","screen","record","title","dataset","base","slug","layout","sections","section","items","item","op","toLowerCase","slot","embeds","detail","component","my","pl","message","size","aria-expanded","onClick","prior","in","unmountOnExit","m","fontFamily","whiteSpace","overflowX","ceiling","display","left","toLocaleString","resetsOn","retryRefusal","control","checked","onChange","event","target","label","onBuildWhatFits","creditsConfirmed","onSmaller","reduce","disabled","undefined"],"mappings":"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"}
1
+ {"version":3,"sources":["../../../../../../../libs/plugins/ai/src/lib/components/ai-job-plan.component.tsx"],"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 {\n AI_BUILD_PLAN_CREATION_NOUNS,\n AI_BUILD_PLAN_EMBED_HOST_NAMES,\n isAiPlanNewRef,\n type AiBuildPlanEmbed,\n} from '../model/ai-build-plan'\nimport type { AiJobReview, AiJobSummary } from '../model/ai-jobs.types'\nimport { aiBuildFreePageCapNote, aiBuildSmaller, aiJobCreditRange } from '../model/ai-build-job'\nimport { aiCreditRangeText, aiCreditsPromptFor } from '../model/ai-credit-estimate'\nimport { aiFreeCreditsResetLabel } from '../model/ai-site-job'\nimport { AiCreditsPromptNotice } from './ai-credits-prompt.component'\nimport type { AiJobResumeOptions } from './ai-job-requests'\nimport { aiBuildOpNoun } from '../model/ai-build-progress'\nimport { aiBuildStorePagesAdded } from '../model/ai-build-store-pages'\nimport { aiJobConfirmingOwnPlan } from '../model/ai-job-activity'\nimport { aiSiteStarterFallbackOffered } from '../model/ai-job-failure-copy'\nimport { AiSiteStarterFallback } from './ai-site-starter-fallback.component'\nimport { Box, Button, Checkbox, Collapse, FormControlLabel, Stack, Typography } from '@mui/material'\nimport { useState } from 'react'\n\n/**\n * A job's plan and what it waits for (AGL-2935), inside the AI jobs drawer\n * and the dialog that started the job (AGL-3593): what the job reuses from\n * the site, what it creates and why, the screens it builds — and, while the\n * job waits for a person, the one button that confirms the plan or tries a\n * refused step again. Both send the same request (`resumeAiJobRequest`);\n * this renders.\n */\nexport interface AiJobPlanProps {\n job: AiJobSummary\n /**\n * Confirms the plan, or tries the refused step again. A build whose request\n * asked to publish confirms with `publish` when its box is ticked (AGL-3616).\n */\n onResume: (job: AiJobSummary, options?: AiJobResumeOptions) => void\n /** A resume for this job is in flight. */\n busy?: boolean\n /**\n * The viewer is staff (AGL-3078), who can open where a refused answer broke\n * its rules and the outline of those parts, to tell a shape the rules should\n * allow from an answer that ignored its re-ask. A member reads the findings.\n */\n staff?: boolean\n /**\n * The signed-in user, for \"Use the starter site instead\" on a guided start\n * that did not work out (AGL-3594); the action is drawn only when given.\n */\n user?: Parameters<typeof AiSiteStarterFallback>[0]['user']\n /** The workspace's path slug, for the Upgrade a Free build past what is left offers (AGL-3722). */\n orgSlug?: string | null\n}\n\n/**\n * Where a refused answer broke its rules, and the outline of those parts, as\n * lines staff read (AGL-3078): each finding with the nodes or plan entries it\n * names, then each outlined node indented by its depth, with its element, a\n * Grid's layout as written, and the names of what it sets and holds.\n */\nexport function aiJobReviewDetails(review: AiJobReview | null): string[] {\n if (review?.reason !== 'doctrine') return []\n const lines = review.findings.flatMap((finding) => {\n const where = finding.nodeIds?.length\n ? `nodes ${finding.nodeIds.join(', ')}`\n : finding.paths?.length\n ? `at ${finding.paths.join(', ')}`\n : null\n return where ? [`${finding.rule === null ? '' : `Rule ${finding.rule} `}${finding.code}: ${where}`] : []\n })\n for (const node of review.outline ?? []) {\n lines.push(\n [\n `${' '.repeat(node.depth)}${node.id} ${node.componentId}`,\n ...Object.entries(node.grid ?? {}).map(([name, value]) => `${name}=${JSON.stringify(value)}`),\n ...(node.props.length ? [`props ${node.props.join(', ')}`] : []),\n ...(node.sx?.length ? [`sx ${node.sx.join(', ')}`] : []),\n ...(node.children.length ? [`holds ${node.children.join(', ')}`] : []),\n ].join(' · '),\n )\n }\n return lines\n}\n\n/**\n * A third-party player the plan lists, with what it costs the page, read\n * before the member confirms it (rule 16, AGL-3433). The cost is the\n * platform's sentence, never the model's: the player is framed lazily, so its\n * host's code loads when a visitor reaches it, whether or not they press play.\n */\nexport function aiPlanEmbedLine(\n embed: AiBuildPlanEmbed,\n named: (ref: string) => string,\n): string {\n const host = AI_BUILD_PLAN_EMBED_HOST_NAMES[embed.host]\n const where = isAiPlanNewRef(embed.where) ? `the component ${named(embed.where)}` : embed.where\n const link = embed.url ? ` playing ${embed.url}` : ', its link left for you to paste'\n return `Embeds a ${host} player on ${where}${link}, as you asked (“${embed.asked}”). It loads ${host}’s own code when a visitor reaches it, whether or not they press play.`\n}\n\nexport function AiJobPlan({\n job,\n onResume,\n busy = false,\n staff = false,\n user,\n orgSlug,\n}: AiJobPlanProps): JSX.Element | null {\n const [detailsOpen, setDetailsOpen] = useState(false)\n // Unticked until the person ticks it: a build publishes only when its\n // request asked AND they confirm it here (AGL-3616).\n const [publish, setPublish] = useState(false)\n const { plan, review } = job\n if (!plan && !review) return null\n const details = staff ? aiJobReviewDetails(review) : []\n /** A reference as a person reads it: the record's name, or what the plan creates. */\n const named = (ref: string | null): string =>\n !ref\n ? ''\n : isAiPlanNewRef(ref)\n ? ref.slice('new:'.length)\n : (plan?.labels[ref] ?? ref)\n // A plan the machine is confirming itself is not one to confirm (AGL-3596).\n const waiting = job.status === 'needs_review' && review !== null && !aiJobConfirmingOwnPlan(job)\n // The guard rail (AGL-2911): what the plan is estimated to cost is read\n // before it is confirmed, not after it has been spent. An estimate, and\n // said to be one: what it is likely to cost — what builds like it measured\n // — and its ceiling, every pass at its reserve (AGL-3722). A page job\n // counts the creations it builds before its page (AGL-3031).\n const range = plan && waiting && review.reason === 'plan' ? aiJobCreditRange(job.kind, plan) : null\n // A Free build past what is left asks first (AGL-3722): build what fits,\n // the home page first, or upgrade — never a refusal with no way on.\n const freeCredits = review?.freeCredits ?? null\n const prompt =\n plan && range && job.kind === 'build' ? aiCreditsPromptFor(range, freeCredits, aiBuildSmaller(plan)) : null\n // A Free build at its page cap says so (AGL-3722): pages past it were left for a later request.\n const pageCapNote =\n plan && waiting && review.reason === 'plan' && job.kind === 'build'\n ? aiBuildFreePageCapNote(plan, Boolean(freeCredits))\n : null\n const offersPublish = job.kind === 'build' && job.publishAsked === true && waiting && review.reason === 'plan'\n const publishing = offersPublish && publish ? { publish: true } : {}\n return (\n <Box sx={{ mt: 1 }}>\n {plan && (\n <Stack spacing={0.5} role=\"list\" aria-label=\"Plan\">\n <Typography variant=\"caption\" color=\"text.secondary\">\n {plan.status === 'confirmed' ? 'Confirmed plan' : 'Proposed plan'}\n </Typography>\n {plan.reuse.map((entry, index) => (\n <Typography key={`reuse-${index}`} variant=\"body2\" role=\"listitem\">\n Reuses the {entry.kind === 'screen' ? 'page' : entry.kind} {named(entry.id)} — {entry.purpose}\n </Typography>\n ))}\n {plan.create.map((entry, index) => (\n <Typography key={`create-${index}`} variant=\"body2\" role=\"listitem\">\n Creates the {AI_BUILD_PLAN_CREATION_NOUNS[entry.kind].noun} {entry.name}\n {entry.duplicateOf\n ? `, from a copy of ${named(entry.duplicateOf)}`\n : ''}{' '}\n — {entry.why}\n </Typography>\n ))}\n {plan.screens.map((screen, index) => (\n <Typography key={`screen-${index}`} variant=\"body2\" role=\"listitem\">\n {screen.record\n ? `Builds the record template ${screen.title}, a page per record of ${named(screen.record.dataset)} at /${screen.record.base}/…`\n : `Builds the page ${screen.title} at ${screen.slug}`}\n {screen.duplicateOf\n ? `, from a copy of ${named(screen.duplicateOf)}`\n : ''}\n {screen.layout ? ` in ${named(screen.layout)}` : ''}\n {screen.sections.length\n ? `: ${screen.sections.map((section) => section.name).join(', ')}`\n : ''}\n </Typography>\n ))}\n {(plan.items ?? []).map((item) => (\n <Typography key={`item-${item.slot}`} variant=\"body2\" role=\"listitem\">\n {`Makes the ${aiBuildOpNoun(item.op).toLowerCase()} ${item.name}`}\n {item.why ? ` — ${item.why}` : ''}\n </Typography>\n ))}\n {(plan.embeds ?? []).map((embed, index) => (\n <Typography key={`embed-${index}`} variant=\"body2\" role=\"listitem\">\n {aiPlanEmbedLine(embed, named)}\n </Typography>\n ))}\n {/* A store's own pages (AGL-3676): added by the platform, written by code, no credits. */}\n {aiBuildStorePagesAdded(plan).map((page) => (\n <Typography key={`store-${page.key}`} variant=\"body2\" role=\"listitem\" data-platform-added=\"true\">\n {`Adds the page ${page.title} at ${page.href} — added for your store automatically, uses no AI credits`}\n </Typography>\n ))}\n </Stack>\n )}\n {/*\n A review written for the member (AGL-3594) carries the checks' own\n sentence as `detail`: its findings are then staff reading too, and the\n member reads the job's one sentence alone.\n */}\n {staff && review?.detail && (\n <Typography variant=\"caption\" color=\"text.secondary\" component=\"div\" sx={{ mt: 0.5 }}>\n {review.detail}\n </Typography>\n )}\n {review?.reason === 'doctrine' && review.findings.length > 0 && (staff || !review.detail) && (\n <Box\n component=\"ul\"\n sx={{ my: 0.5, pl: 2.5 }}\n aria-label=\"Building rules broken\"\n >\n {review.findings.map((finding, index) => (\n <Typography\n key={`finding-${index}`}\n component=\"li\"\n variant=\"caption\"\n >\n {finding.message}\n </Typography>\n ))}\n </Box>\n )}\n {details.length > 0 && (\n <Box sx={{ mt: 0.5 }}>\n <Button\n size=\"small\"\n aria-expanded={detailsOpen}\n onClick={() => setDetailsOpen((prior) => !prior)}\n >\n {detailsOpen ? 'Hide what was refused' : 'Show what was refused'}\n </Button>\n <Collapse in={detailsOpen} unmountOnExit>\n <Typography\n variant=\"caption\"\n component=\"pre\"\n aria-label=\"What was refused\"\n sx={{ m: 0, fontFamily: 'monospace', whiteSpace: 'pre', overflowX: 'auto' }}\n >\n {details.join('\\n')}\n </Typography>\n </Collapse>\n </Box>\n )}\n {range && range.ceiling > 0 && (\n <Typography\n variant=\"caption\"\n color=\"text.secondary\"\n sx={{ display: 'block', mt: 1 }}\n >\n {`Estimated cost: ${aiCreditRangeText(range)}. What it costs is what its steps spend.`}\n {freeCredits && !prompt\n ? ` You have ${freeCredits.left.toLocaleString('en-US')} of your free AI credits left this month, until ${aiFreeCreditsResetLabel(freeCredits.resetsOn)}.`\n : ''}\n </Typography>\n )}\n {pageCapNote && (\n <Typography variant=\"caption\" color=\"text.secondary\" sx={{ display: 'block', mt: 0.5 }}>\n {pageCapNote}\n </Typography>\n )}\n {waiting && review.retryRefusal && review.reason !== 'plan' && (\n <Typography variant=\"caption\" color=\"text.secondary\" component=\"div\" sx={{ mt: 1 }}>\n {review.retryRefusal}\n </Typography>\n )}\n {offersPublish && (\n <FormControlLabel\n sx={{ display: 'flex', mt: 1 }}\n control={<Checkbox size=\"small\" checked={publish} onChange={(event) => setPublish(event.target.checked)} />}\n label={<Typography variant=\"body2\">{'Publish the new pages when they are built'}</Typography>}\n />\n )}\n {waiting && prompt && (\n <AiCreditsPromptNotice\n prompt={prompt}\n noun=\"build\"\n orgSlug={orgSlug}\n busy={busy}\n onBuildWhatFits={() => onResume(job, { ...publishing, creditsConfirmed: true })}\n onSmaller={() => onResume(job, { ...publishing, creditsConfirmed: true, reduce: 'first-page' })}\n />\n )}\n {waiting && !prompt && (\n <Button\n size=\"small\"\n variant=\"contained\"\n // Disabled with its reason above when the Free allowance left\n // cannot pay for another try (AGL-3594).\n disabled={busy || (review.reason !== 'plan' && Boolean(review.retryRefusal))}\n onClick={() => onResume(job, offersPublish && publish ? publishing : undefined)}\n sx={{ mt: 1 }}\n >\n {review.reason === 'plan' ? 'Confirm plan' : 'Try again'}\n </Button>\n )}\n {/* A guided start that did not work out can take the starter instead (AGL-3594). */}\n {waiting && user && aiSiteStarterFallbackOffered(job) && <AiSiteStarterFallback job={job} user={user} />}\n </Box>\n )\n}\n\nexport default AiJobPlan\n"],"names":["AI_BUILD_PLAN_CREATION_NOUNS","AI_BUILD_PLAN_EMBED_HOST_NAMES","isAiPlanNewRef","aiBuildFreePageCapNote","aiBuildSmaller","aiJobCreditRange","aiCreditRangeText","aiCreditsPromptFor","aiFreeCreditsResetLabel","AiCreditsPromptNotice","aiBuildOpNoun","aiBuildStorePagesAdded","aiJobConfirmingOwnPlan","aiSiteStarterFallbackOffered","AiSiteStarterFallback","Box","Button","Checkbox","Collapse","FormControlLabel","Stack","Typography","useState","aiJobReviewDetails","review","reason","lines","findings","flatMap","finding","where","nodeIds","length","join","paths","rule","code","node","outline","push","repeat","depth","id","componentId","Object","entries","grid","map","name","value","JSON","stringify","props","sx","children","aiPlanEmbedLine","embed","named","host","link","url","asked","AiJobPlan","job","onResume","busy","staff","user","orgSlug","plan","detailsOpen","setDetailsOpen","publish","setPublish","details","ref","slice","labels","waiting","status","range","kind","freeCredits","prompt","pageCapNote","Boolean","offersPublish","publishAsked","publishing","mt","spacing","role","aria-label","variant","color","reuse","entry","index","purpose","create","noun","duplicateOf","why","screens","screen","record","title","dataset","base","slug","layout","sections","section","items","item","op","toLowerCase","slot","embeds","page","data-platform-added","href","key","detail","component","my","pl","message","size","aria-expanded","onClick","prior","in","unmountOnExit","m","fontFamily","whiteSpace","overflowX","ceiling","display","left","toLocaleString","resetsOn","retryRefusal","control","checked","onChange","event","target","label","onBuildWhatFits","creditsConfirmed","onSmaller","reduce","disabled","undefined"],"mappings":"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"}
@@ -31,7 +31,8 @@ import { aiSiteStartAnswersFromInputs } from "../model/ai-site-start.js";
31
31
  import { AiSiteStartCard } from "./ai-site-start-card.component.js";
32
32
  import { AI_JOB_TERMINAL_STATUSES } from "../model/ai-jobs.types.js";
33
33
  import { followAiJobEvents } from "./ai-job-events.js";
34
- import { aiCreditsBillingHref, aiSiteBuildDoneLinks } from "./ai-job-links.js";
34
+ import { aiCreditsBillingHref, aiSiteBuildDoneLinks, aiStoreFinishLinks } from "./ai-job-links.js";
35
+ import { AiStoreFinishCard } from "./ai-store-finish-card.component.js";
35
36
  import { AiJobPlan } from "./ai-job-plan.component.js";
36
37
  import { aiBuildCanRetry, aiBuildRetryCreditRange } from "../model/ai-build-progress.js";
37
38
  import { resumeAiJobRequest } from "./ai-job-requests.js";
@@ -357,6 +358,8 @@ export function AiSiteBuildPage({ hostId, segments, basePath }) {
357
358
  };
358
359
  const sitePublish = ready.kind === 'site' && phase === 'done' ? (_ready_sitePublish = ready.sitePublish) != null ? _ready_sitePublish : null : null;
359
360
  const liveUrl = sitePublish && sitePublish.published.length > 0 ? sitePublish.liveUrl : null;
361
+ // A store start's last steps (AGL-3676): only payments, products, shipping and tax, and the policies.
362
+ const storeFinish = phase === 'done' ? aiStoreFinishLinks(ready, orgSlug) : null;
360
363
  // Paused by the meter (AGL-3660): out of credits or at a cap, carried on by Resume.
361
364
  const paused = ready.status === 'needs_input';
362
365
  const retryRefusal = (_ready_review = ready.review) == null ? void 0 : _ready_review.retryRefusal;
@@ -610,6 +613,9 @@ export function AiSiteBuildPage({ hostId, segments, basePath }) {
610
613
  })
611
614
  ]
612
615
  }),
616
+ storeFinish && /*#__PURE__*/ _jsx(AiStoreFinishCard, {
617
+ steps: storeFinish
618
+ }),
613
619
  paused && // Paused by the meter (AGL-3660): the way to more credits — the
614
620
  // workspace's own Billing page, where plans and the AI add-on are
615
621
  // sold — and Resume, which carries on this same job from its paused