@aglyn/plugins-ai 1.0.0-beta.263 → 1.0.0-beta.266

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 (109) hide show
  1. package/package.json +17 -17
  2. package/src/lib/assets/site-styles/beauty.webp +0 -0
  3. package/src/lib/assets/site-styles/blog.webp +0 -0
  4. package/src/lib/assets/site-styles/business.webp +0 -0
  5. package/src/lib/assets/site-styles/coming-soon.webp +0 -0
  6. package/src/lib/assets/site-styles/education.webp +0 -0
  7. package/src/lib/assets/site-styles/events.webp +0 -0
  8. package/src/lib/assets/site-styles/fitness.webp +0 -0
  9. package/src/lib/assets/site-styles/landing.webp +0 -0
  10. package/src/lib/assets/site-styles/music.webp +0 -0
  11. package/src/lib/assets/site-styles/nonprofit.webp +0 -0
  12. package/src/lib/assets/site-styles/personal.webp +0 -0
  13. package/src/lib/assets/site-styles/photography.webp +0 -0
  14. package/src/lib/assets/site-styles/portfolio.webp +0 -0
  15. package/src/lib/assets/site-styles/professional.webp +0 -0
  16. package/src/lib/assets/site-styles/realestate.webp +0 -0
  17. package/src/lib/assets/site-styles/restaurant.webp +0 -0
  18. package/src/lib/assets/site-styles/store.webp +0 -0
  19. package/src/lib/assets/site-styles/studio.webp +0 -0
  20. package/src/lib/assets/site-styles/trades.webp +0 -0
  21. package/src/lib/assets/site-styles/wellness.webp +0 -0
  22. package/src/lib/assets/site-styles/yoga.webp +0 -0
  23. package/src/lib/components/ai-site-start-card.component.d.ts +12 -0
  24. package/src/lib/components/ai-site-start-card.component.js +256 -236
  25. package/src/lib/components/ai-site-start-card.component.js.map +1 -1
  26. package/src/lib/components/ai-site-start-steps.component.d.ts +108 -0
  27. package/src/lib/components/ai-site-start-steps.component.js +451 -0
  28. package/src/lib/components/ai-site-start-steps.component.js.map +1 -0
  29. package/src/lib/components/ai-site-start-tracking.d.ts +114 -0
  30. package/src/lib/components/ai-site-start-tracking.js +277 -0
  31. package/src/lib/components/ai-site-start-tracking.js.map +1 -0
  32. package/src/lib/components/ai-site-style-previews.d.ts +26 -0
  33. package/src/lib/components/ai-site-style-previews.js +115 -0
  34. package/src/lib/components/ai-site-style-previews.js.map +1 -0
  35. package/src/lib/insights/ai-insight-digest.d.ts +9 -0
  36. package/src/lib/insights/ai-insight-digest.js +35 -11
  37. package/src/lib/insights/ai-insight-digest.js.map +1 -1
  38. package/src/lib/jobs/ai-job-page-language.d.ts +9 -0
  39. package/src/lib/jobs/ai-job-page-language.js +20 -2
  40. package/src/lib/jobs/ai-job-page-language.js.map +1 -1
  41. package/src/lib/jobs/ai-job-page-sections.js +8 -2
  42. package/src/lib/jobs/ai-job-page-sections.js.map +1 -1
  43. package/src/lib/jobs/ai-job-plan-step.d.ts +43 -8
  44. package/src/lib/jobs/ai-job-plan-step.js +99 -18
  45. package/src/lib/jobs/ai-job-plan-step.js.map +1 -1
  46. package/src/lib/jobs/ai-job-site-datasets.d.ts +93 -2
  47. package/src/lib/jobs/ai-job-site-datasets.js +308 -21
  48. package/src/lib/jobs/ai-job-site-datasets.js.map +1 -1
  49. package/src/lib/jobs/ai-layout-stock-photos.d.ts +191 -13
  50. package/src/lib/jobs/ai-layout-stock-photos.js +1709 -69
  51. package/src/lib/jobs/ai-layout-stock-photos.js.map +1 -1
  52. package/src/lib/jobs/fixtures/ai-site-foreign-datasets-recording.d.ts +58 -0
  53. package/src/lib/jobs/fixtures/ai-site-foreign-datasets-recording.js +678 -0
  54. package/src/lib/jobs/fixtures/ai-site-foreign-datasets-recording.js.map +1 -0
  55. package/src/lib/jobs/fixtures/ai-stock-photo-agl3856-beta265-recordings.d.ts +33 -0
  56. package/src/lib/jobs/fixtures/ai-stock-photo-agl3856-beta265-recordings.js +270 -0
  57. package/src/lib/jobs/fixtures/ai-stock-photo-agl3856-beta265-recordings.js.map +1 -0
  58. package/src/lib/jobs/fixtures/ai-stock-photo-agl3856-people-recordings.d.ts +33 -0
  59. package/src/lib/jobs/fixtures/ai-stock-photo-agl3856-people-recordings.js +277 -0
  60. package/src/lib/jobs/fixtures/ai-stock-photo-agl3856-people-recordings.js.map +1 -0
  61. package/src/lib/jobs/fixtures/ai-stock-photo-juniper-records-recordings.d.ts +23 -0
  62. package/src/lib/jobs/fixtures/ai-stock-photo-juniper-records-recordings.js +163 -0
  63. package/src/lib/jobs/fixtures/ai-stock-photo-juniper-records-recordings.js.map +1 -0
  64. package/src/lib/jobs/fixtures/ai-stock-photo-learning-center-recordings.d.ts +23 -0
  65. package/src/lib/jobs/fixtures/ai-stock-photo-learning-center-recordings.js +53 -0
  66. package/src/lib/jobs/fixtures/ai-stock-photo-learning-center-recordings.js.map +1 -0
  67. package/src/lib/jobs/fixtures/ai-stock-photo-synchronicity-recordings.d.ts +21 -0
  68. package/src/lib/jobs/fixtures/ai-stock-photo-synchronicity-recordings.js +119 -0
  69. package/src/lib/jobs/fixtures/ai-stock-photo-synchronicity-recordings.js.map +1 -0
  70. package/src/lib/layout-language/ai-layout-compiler.js +54 -15
  71. package/src/lib/layout-language/ai-layout-compiler.js.map +1 -1
  72. package/src/lib/layout-language/ai-layout-design.d.ts +6 -3
  73. package/src/lib/layout-language/ai-layout-design.js +14 -13
  74. package/src/lib/layout-language/ai-layout-design.js.map +1 -1
  75. package/src/lib/layout-language/ai-layout-listings.d.ts +55 -0
  76. package/src/lib/layout-language/ai-layout-listings.js +103 -5
  77. package/src/lib/layout-language/ai-layout-listings.js.map +1 -1
  78. package/src/lib/layout-language/ai-layout-pictures.d.ts +42 -8
  79. package/src/lib/layout-language/ai-layout-pictures.js +91 -6
  80. package/src/lib/layout-language/ai-layout-pictures.js.map +1 -1
  81. package/src/lib/model/ai-site-home-arcs.d.ts +75 -0
  82. package/src/lib/model/ai-site-home-arcs.js +741 -0
  83. package/src/lib/model/ai-site-home-arcs.js.map +1 -0
  84. package/src/lib/model/ai-site-inventory.d.ts +18 -0
  85. package/src/lib/model/ai-site-inventory.js.map +1 -1
  86. package/src/lib/model/ai-site-job.d.ts +9 -6
  87. package/src/lib/model/ai-site-job.js +8 -5
  88. package/src/lib/model/ai-site-job.js.map +1 -1
  89. package/src/lib/model/ai-site-kinds.js +24 -24
  90. package/src/lib/model/ai-site-kinds.js.map +1 -1
  91. package/src/lib/model/ai-site-start-steps.d.ts +67 -0
  92. package/src/lib/model/ai-site-start-steps.js +127 -0
  93. package/src/lib/model/ai-site-start-steps.js.map +1 -0
  94. package/src/lib/model/ai-site-start.js +4 -1
  95. package/src/lib/model/ai-site-start.js.map +1 -1
  96. package/src/lib/runtime/ai-doctrine-validators.d.ts +32 -0
  97. package/src/lib/runtime/ai-doctrine-validators.js +119 -2
  98. package/src/lib/runtime/ai-doctrine-validators.js.map +1 -1
  99. package/src/lib/runtime/ai-doctrine.d.ts +6 -1
  100. package/src/lib/runtime/ai-doctrine.js +9 -5
  101. package/src/lib/runtime/ai-doctrine.js.map +1 -1
  102. package/src/lib/runtime/ai-palette.generated.js +5 -2
  103. package/src/lib/runtime/ai-palette.generated.js.map +1 -1
  104. package/src/lib/runtime/site-inventory.js +6 -0
  105. package/src/lib/runtime/site-inventory.js.map +1 -1
  106. package/src/lib/server/ai-insight-digest-route.js +2 -2
  107. package/src/lib/server/ai-insight-digest-route.js.map +1 -1
  108. package/src/lib/usage/assist-free-taste.js +3 -0
  109. package/src/lib/usage/assist-free-taste.js.map +1 -1
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../../../../libs/plugins/ai/src/lib/model/ai-site-home-arcs.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 * A site start's HOME ARC (AGL-3899): which sections its home page tells\n * its story with, and in what order, chosen in code by the job's seed among\n * the arcs that suit the site's kind.\n *\n * Why. Told one outline for every home (\"a hero, then services, about or why\n * us, … a closing call to action last\"), the 22 newest production starts of\n * 2026-10-16 were 16 times hero → offer → about → proof → closing call to\n * action, and 19 of them ended on a call to action. Zach: \"almost every AI\n * site seems to look the same … they all have the same sections\". A theme\n * that varies on a fixed outline still reads as one site.\n *\n * So each kind has a few arcs, each a different way a designer would tell\n * that business's story — the work first, the story first, the steps first,\n * a close on the questions people ask, a gallery of the place, a menu or a\n * services list where the kind has one — and the seed picks one. The plan's\n * turn names it in one line; the model still names, writes and designs every\n * section, and the plan rules hold it as they hold any plan.\n *\n * Every arc is a hero and four sections: the home's fewest\n * (`AI_SITE_HOME_MIN_SECTIONS`), which the Free wall pays for beside the\n * other page, and which a paid plan adds to where the brief gives more. A\n * store's arcs are its storefront's parts (`AI_SITE_STORE_HOME_BANDS`) in\n * three orders, the newsletter sign-up always last, as the storefront settle\n * keeps it (`aiStorefrontPlanScreens`). No\n * arc promises what a new site has not got: figures, prices, listings and\n * shows are \"only as the brief gives them\", and none plans what customers\n * say (AGL-3887).\n *\n * Pure data and one reader, safe for the console to import.\n */\n\n/** What a section of an arc is for: what the variety specs compare arcs by. */\nexport type AiSiteHomeRole =\n | 'offer'\n | 'work'\n | 'story'\n | 'steps'\n | 'approach'\n | 'why'\n | 'faq'\n | 'gallery'\n | 'menu'\n | 'people'\n | 'area'\n | 'facts'\n | 'listen'\n | 'writing'\n | 'topics'\n | 'cta'\n | 'products'\n | 'collections'\n | 'reviews'\n | 'signup'\n\n/** One section of an arc: its role, and the words the plan is told. */\nexport interface AiSiteHomeArcSection {\n role: AiSiteHomeRole\n words: string\n}\n\n/** A home arc: an id the job records, and the sections after the hero, in order. */\nexport interface AiSiteHomeArc {\n id: string\n sections: readonly AiSiteHomeArcSection[]\n}\n\nconst s = (role: AiSiteHomeRole, words: string): AiSiteHomeArcSection => ({ role, words })\n\n// The parts arcs share, in the plan's words.\nconst CTA = s('cta', 'a call to action')\nconst FAQ = s('faq', 'the questions people ask, answered')\nconst APPROACH = s('approach', 'what working together is like')\n\n/** The arcs each kind's home may follow; a kind not listed follows `business`'s. */\nconst ARCS: Readonly<Record<string, readonly AiSiteHomeArc[]>> = {\n business: [\n { id: 'offer-first', sections: [s('offer', 'the services'), s('why', 'why choose it'), s('steps', 'how it works, as steps'), CTA] },\n { id: 'story-first', sections: [s('story', 'the story behind the business'), s('offer', 'the services'), APPROACH, CTA] },\n { id: 'steps-first', sections: [s('steps', 'how it works, as steps'), s('offer', 'the services'), APPROACH, FAQ] },\n { id: 'work-first', sections: [s('work', 'the work or results in pictures'), s('offer', 'the services'), s('why', 'why choose it'), FAQ] },\n ],\n trades: [\n { id: 'offer-first', sections: [s('offer', 'the services'), s('area', 'the area served'), s('why', 'why customers can trust it, only as the brief gives it'), CTA] },\n { id: 'trust-first', sections: [s('why', 'why customers can trust it, only as the brief gives it'), s('offer', 'the services'), s('steps', 'how a job goes, as steps'), FAQ] },\n { id: 'work-first', sections: [s('work', 'recent work in pictures'), s('offer', 'the services'), s('area', 'the area served'), CTA] },\n { id: 'steps-first', sections: [s('steps', 'how a job goes, as steps'), s('offer', 'the services'), FAQ, CTA] },\n ],\n professional: [\n { id: 'offer-first', sections: [s('offer', 'the practice areas'), s('steps', 'the approach, as steps'), s('people', 'the people behind the practice'), CTA] },\n { id: 'approach-first', sections: [s('approach', 'the approach and what it means for a client'), s('offer', 'the practice areas'), FAQ, CTA] },\n { id: 'people-first', sections: [s('people', 'the people behind the practice'), s('offer', 'the practice areas'), APPROACH, FAQ] },\n ],\n wellness: [\n { id: 'steps-first', sections: [s('approach', 'who it helps and how'), s('steps', 'what a first visit is like, as steps'), s('offer', 'the services'), FAQ] },\n { id: 'offer-first', sections: [s('offer', 'the services'), s('approach', 'the approach to care'), s('people', 'the people who give it'), CTA] },\n { id: 'story-first', sections: [s('story', 'the story of the practice'), s('offer', 'the services'), s('steps', 'what a first visit is like, as steps'), CTA] },\n ],\n restaurant: [\n { id: 'menu-first', sections: [s('menu', 'the menu highlights'), s('story', 'the story of the place'), s('gallery', 'the room and the food in pictures'), s('facts', 'visiting, with hours and address only as the brief gives them')] },\n { id: 'story-first', sections: [s('story', 'the story of the place'), s('menu', 'the menu highlights'), s('gallery', 'the room and the food in pictures'), CTA] },\n { id: 'gallery-first', sections: [s('gallery', 'the food and the room in pictures'), s('menu', 'the menu highlights'), s('story', 'the story of the place'), FAQ] },\n { id: 'visit-first', sections: [s('facts', 'visiting, with hours and address only as the brief gives them'), s('menu', 'the menu highlights'), s('story', 'the story of the place'), s('gallery', 'the room and the food in pictures')] },\n ],\n store: [\n { id: 'bestsellers-first', sections: [s('products', '\"Bestsellers\"'), s('collections', '\"Shop by collection\"'), s('story', 'the brand story'), s('why', 'why buy here'), s('reviews', '\"Customer reviews\"'), s('signup', '\"Newsletter sign-up\"')] },\n { id: 'collections-first', sections: [s('collections', '\"Shop by collection\"'), s('products', '\"Bestsellers\"'), s('why', 'why buy here'), s('story', 'the brand story'), s('reviews', '\"Customer reviews\"'), s('signup', '\"Newsletter sign-up\"')] },\n { id: 'story-first', sections: [s('products', '\"Bestsellers\"'), s('story', 'the brand story'), s('collections', '\"Shop by collection\"'), s('reviews', '\"Customer reviews\"'), s('why', 'why buy here'), s('signup', '\"Newsletter sign-up\"')] },\n ],\n portfolio: [\n { id: 'work-first', sections: [s('work', 'selected work in pictures'), s('story', 'a short about'), s('offer', 'what the work is available for, such as commissions'), CTA] },\n { id: 'statement-first', sections: [s('story', 'a short statement about the work'), s('work', 'selected work in pictures'), s('steps', 'the process, as steps'), CTA] },\n { id: 'process-led', sections: [s('work', 'selected work in pictures'), s('steps', 'the process, as steps'), FAQ, s('story', 'a short about')] },\n ],\n studio: [\n { id: 'work-first', sections: [s('work', 'selected case studies'), s('offer', 'the services, as a short list'), s('steps', 'how the studio works, as steps'), CTA] },\n { id: 'beliefs-first', sections: [s('story', 'what the studio believes'), s('work', 'selected case studies'), s('offer', 'the services, as a short list'), FAQ] },\n { id: 'offer-first', sections: [s('offer', 'the services'), s('work', 'selected case studies'), s('people', 'the team'), CTA] },\n ],\n photography: [\n { id: 'gallery-first', sections: [s('work', 'galleries by subject'), s('story', 'a short personal about'), s('steps', 'what a session is like, as steps'), CTA] },\n { id: 'about-first', sections: [s('story', 'a short personal about'), s('work', 'galleries by subject'), s('offer', 'the sessions, with packages only as the brief gives them'), FAQ] },\n { id: 'session-first', sections: [s('steps', 'what a session is like, as steps'), s('work', 'galleries by subject'), APPROACH, CTA] },\n ],\n blog: [\n { id: 'writing-first', sections: [s('writing', 'featured writing'), s('topics', 'the topics covered'), s('story', 'about the writer'), CTA] },\n { id: 'writer-first', sections: [s('story', 'about the writer'), s('writing', 'featured writing'), s('topics', 'the topics covered'), FAQ] },\n { id: 'topics-first', sections: [s('topics', 'the topics covered'), s('writing', 'featured writing'), s('steps', 'where a new reader starts, as steps'), s('story', 'about the writer')] },\n ],\n events: [\n { id: 'about-first', sections: [s('story', 'what it is and why to come'), s('steps', 'the schedule, as steps'), FAQ, CTA] },\n { id: 'schedule-first', sections: [s('steps', 'the schedule, as steps'), s('facts', 'the venue and travel, only as the brief gives them'), FAQ, CTA] },\n { id: 'gallery-first', sections: [s('gallery', 'the place in pictures'), s('story', 'what it is and why to come'), s('steps', 'the schedule, as steps'), FAQ] },\n ],\n fitness: [\n { id: 'offer-first', sections: [s('offer', 'the classes or programs'), s('steps', 'how to start, as steps'), s('people', 'the coaches'), CTA] },\n { id: 'why-first', sections: [s('why', 'why train here'), s('offer', 'the classes or programs'), FAQ, CTA] },\n { id: 'steps-first', sections: [s('steps', 'how to start, as steps'), s('offer', 'the classes or programs'), s('gallery', 'the space in pictures'), FAQ] },\n { id: 'people-first', sections: [s('people', 'the coaches'), s('offer', 'the classes or programs'), s('facts', 'memberships, only as the brief gives them'), CTA] },\n ],\n yoga: [\n { id: 'offer-first', sections: [s('offer', 'the classes'), s('steps', 'what a first class is like, as steps'), s('story', 'a gentle about'), CTA] },\n { id: 'story-first', sections: [s('story', 'the story of the studio'), s('offer', 'the classes'), s('gallery', 'the space in pictures'), FAQ] },\n { id: 'steps-first', sections: [s('steps', 'what a first class is like, as steps'), s('offer', 'the classes'), s('people', 'the teachers'), CTA] },\n ],\n beauty: [\n { id: 'menu-first', sections: [s('menu', 'the services menu, with prices only as the brief gives them'), s('gallery', 'the look and feel of the place in pictures'), s('people', 'the team'), CTA] },\n { id: 'gallery-first', sections: [s('gallery', 'the look and feel of the place in pictures'), s('menu', 'the services menu, with prices only as the brief gives them'), s('steps', 'what a visit is like, as steps'), FAQ] },\n { id: 'people-first', sections: [s('people', 'the team'), s('menu', 'the services menu, with prices only as the brief gives them'), s('gallery', 'the place in pictures'), CTA] },\n ],\n realestate: [\n { id: 'area-first', sections: [s('area', 'the areas served'), s('steps', 'how buying or selling works, as steps'), s('work', 'featured listings as picture cards the owner fills in'), CTA] },\n { id: 'people-first', sections: [s('people', 'about the agent or team'), s('area', 'the areas served'), FAQ, CTA] },\n { id: 'listings-first', sections: [s('work', 'featured listings as picture cards the owner fills in'), s('area', 'the areas served'), s('steps', 'how selling works, as steps'), FAQ] },\n ],\n education: [\n { id: 'offer-first', sections: [s('offer', 'the courses or subjects'), s('steps', 'how it works, as steps'), s('people', 'the teachers'), FAQ] },\n { id: 'result-first', sections: [s('why', 'who it is for and what they come away with'), s('offer', 'the courses or subjects'), s('approach', 'what a lesson is like'), CTA] },\n { id: 'people-first', sections: [s('people', 'the teachers'), s('offer', 'the courses or subjects'), s('steps', 'how enrolling works, as steps'), CTA] },\n ],\n nonprofit: [\n { id: 'work-first', sections: [s('offer', 'what the organization does'), s('facts', 'its impact, only as the brief gives it'), s('steps', 'how to help, as steps'), CTA] },\n { id: 'story-first', sections: [s('story', 'the story of the cause'), s('offer', 'the programs'), s('steps', 'how to help, as steps'), FAQ] },\n { id: 'help-first', sections: [s('steps', 'how to help, as steps'), s('offer', 'what the organization does'), s('gallery', 'the people it serves, in pictures'), CTA] },\n ],\n music: [\n { id: 'listen-first', sections: [s('listen', 'a listen section'), s('work', 'releases or shows, only as the brief gives them'), s('story', 'a short bio'), CTA] },\n { id: 'bio-first', sections: [s('story', 'a short bio'), s('listen', 'a listen section'), s('gallery', 'the band live in pictures'), CTA] },\n { id: 'shows-first', sections: [s('work', 'releases or shows, only as the brief gives them'), s('listen', 'a listen section'), s('gallery', 'the band live in pictures'), s('story', 'a short bio')] },\n ],\n personal: [\n { id: 'offer-first', sections: [s('offer', 'what they do'), s('steps', 'experience or highlights, as steps'), s('work', 'selected work, only as the brief names some'), CTA] },\n { id: 'story-first', sections: [s('story', 'a short story'), s('offer', 'what they do'), s('steps', 'experience or highlights, as steps'), CTA] },\n { id: 'questions-led', sections: [s('offer', 'what they do'), s('story', 'a short story'), FAQ, CTA] },\n ],\n landing: [\n { id: 'benefits-first', sections: [s('why', 'the benefits'), s('steps', 'how it works, as steps'), FAQ, s('cta', 'the call to action again')] },\n { id: 'steps-first', sections: [s('steps', 'how it works, as steps'), s('why', 'the benefits'), s('approach', 'who it is for'), s('cta', 'the call to action again')] },\n { id: 'problem-first', sections: [s('story', 'the problem it solves'), s('why', 'the benefits'), FAQ, s('cta', 'the call to action again')] },\n ],\n 'coming-soon': [\n { id: 'promise-first', sections: [s('story', 'what is coming'), s('why', 'two or three reasons to care'), s('people', 'who is behind it'), s('cta', 'a way to hear first')] },\n { id: 'reasons-first', sections: [s('why', 'two or three reasons to care'), s('story', 'what is coming'), FAQ, s('cta', 'a way to hear first')] },\n { id: 'people-first', sections: [s('people', 'who is behind it'), s('story', 'what is coming'), s('why', 'two or three reasons to care'), s('cta', 'a way to hear first')] },\n ],\n}\n\n/** The arcs a kind's home may follow. */\nexport function aiSiteHomeArcsFor(kind: string | null | undefined): readonly AiSiteHomeArc[] {\n return (kind && ARCS[kind]) || (ARCS['business'] as readonly AiSiteHomeArc[])\n}\n\n/** A small deterministic generator over a seed (mulberry32). */\nfunction random(seed: number): () => number {\n let state = seed >>> 0\n return () => {\n state = (state + 0x6d2b79f5) >>> 0\n let t = state\n t = Math.imul(t ^ (t >>> 15), t | 1)\n t ^= t + Math.imul(t ^ (t >>> 7), t | 61)\n return ((t ^ (t >>> 14)) >>> 0) / 4294967296\n }\n}\n\n/**\n * The arc a job's home follows: one of its kind's, picked by the job's seed\n * (`aiSiteSeed` of the job id) under a salt of its own, so the arc is drawn\n * apart from the look and the compiler's choices, which read the same seed.\n */\nexport function aiSiteHomeArc(input: { kind: string | null | undefined; seed: number }): AiSiteHomeArc {\n const arcs = aiSiteHomeArcsFor(input.kind)\n const next = random((input.seed ^ 0x51ed2701) >>> 0)\n return arcs[Math.floor(next() * arcs.length) % arcs.length] as AiSiteHomeArc\n}\n\n/** An arc's sections as one phrase: \"the services, why choose it and a call to action\". */\nfunction listed(sections: readonly AiSiteHomeArcSection[]): string {\n const words = sections.map((section) => section.words)\n if (words.length <= 1) return words.join('')\n return `${words.slice(0, -1).join(', ')} and ${words.at(-1)}`\n}\n\n/**\n * The plan's one line for its arc: the hero first, then the arc's sections in\n * its order, more only where the brief gives them and the plan has room.\n */\nexport function aiSiteHomeArcSentence(arc: AiSiteHomeArc): string {\n return `This site's home tells its story in its own order: the hero first, then ${listed(arc.sections)}. Keep that order, name each section for what this business has to say there, and add a section the brief needs only where the plan has room.`\n}\n"],"names":["s","role","words","CTA","FAQ","APPROACH","ARCS","business","id","sections","trades","professional","wellness","restaurant","store","portfolio","studio","photography","blog","events","fitness","yoga","beauty","realestate","education","nonprofit","music","personal","landing","aiSiteHomeArcsFor","kind","random","seed","state","t","Math","imul","aiSiteHomeArc","input","arcs","next","floor","length","listed","map","section","join","slice","at","aiSiteHomeArcSentence","arc"],"mappings":"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"}
@@ -120,6 +120,24 @@ export interface AiInventoryDataset {
120
120
  * listing's cards by it.
121
121
  */
122
122
  recordBase?: string;
123
+ /**
124
+ * Whether it is shared with this site and no other (AGL-3912): its scope
125
+ * names this site alone, so it was made for this site. Absent where it is
126
+ * the workspace's, shared with every site, or with others besides.
127
+ */
128
+ siteOnly?: true;
129
+ /**
130
+ * How many records it holds (AGL-3912), counted for a site start's plan
131
+ * only (`aiSiteInventoryWithRecordCounts`); absent where nobody counted, or
132
+ * the count failed. Never shown in the prompt.
133
+ */
134
+ records?: number;
135
+ /**
136
+ * Set on a site start's plan only (AGL-3912), where its records are not
137
+ * this site's to show (`aiSiteDatasetIsThisSites`): the plan makes it
138
+ * again rather than reuse it, so a creation of its name is no duplicate.
139
+ */
140
+ foreign?: true;
123
141
  }
124
142
  export interface AiInventoryCollection {
125
143
  id: string;
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../../../libs/plugins/ai/src/lib/model/ai-site-inventory.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 * The site's inventory as a model sees it (AGL-2935): what the site already\n * has, so a plan reuses before it creates (doctrine rule 7).\n *\n * COMPACT by construction (AGL-2937): ids, names, prop shapes and slugs —\n * never a node tree, never a record's content. A component is its name and\n * the props an instance fills in; a form is its field names; a dataset its\n * field names. That is everything a planner needs to decide \"reuse this\"\n * and a generator needs to place a reference, and it is a few hundred\n * tokens where the trees would be tens of thousands.\n *\n * CAPPED three times, and the three are different numbers on purpose\n * (AGL-2937). The reader holds each kind to `AI_SITE_INVENTORY_MAX_PER_KIND`;\n * the prompt block LISTS only `AI_SITE_INVENTORY_LISTED_PER_KIND` of them and\n * is held to `AI_SITE_INVENTORY_MAX_CHARS` besides; and the rest are answered\n * on request, through the lookup tool the generation loop offers beside every\n * door's own (`tools/ai-inventory-lookup-tool.ts`).\n *\n * The listing cap is what a prompt can afford: the block is volatile, so it\n * is billed at full input rate on every request and every re-ask, and a site\n * with two hundred components would spend most of a plan's prompt on rows it\n * will not use. The read cap is what a LOOKUP can answer from, which is a\n * different question — a search for \"pricing card\" is worth nothing if the\n * card was never read. A kind cut by either is named in `truncated`, so the\n * model is told more exist rather than concluding they do not.\n *\n * The shapes live here, apart from the reader (`runtime/site-inventory.ts`),\n * so the prompt block, the validators and their specs can hold an inventory\n * without loading the Admin SDK the reader needs.\n */\n\n/**\n * Rows per kind the reader holds. Above the listing cap on purpose: the rows\n * past it are what the lookup tool searches, and a row never read cannot be\n * found. One projection of a few fields each, so the read is small even at\n * this cap.\n */\nexport const AI_SITE_INVENTORY_MAX_PER_KIND = 200\n\n/** Rows per kind the prompt block lists; the rest are found by lookup. */\nexport const AI_SITE_INVENTORY_LISTED_PER_KIND = 40\n\n/** The rendered block's ceiling: 2,000 tokens at four characters a token. */\nexport const AI_SITE_INVENTORY_MAX_CHARS = 8_000\n\nexport type AiInventoryKind =\n | 'components'\n | 'layouts'\n | 'templates'\n | 'forms'\n | 'datasets'\n | 'collections'\n | 'screens'\n\nexport const AI_INVENTORY_KINDS: readonly AiInventoryKind[] = [\n 'components',\n 'layouts',\n 'templates',\n 'forms',\n 'datasets',\n 'collections',\n 'screens',\n]\n\n/**\n * A reusable component's declared props as an instance may fill them: prop\n * name → its declared type (`text`, `image`, `href`, `number`, `boolean`, …).\n */\nexport type AiComponentPropTypes = Record<string, string>\n\nexport interface AiInventoryComponent {\n id: string\n name: string\n /** The props an instance fills in: name → declared type. */\n props: AiComponentPropTypes\n /**\n * The facts in square brackets each prop's default shows until a page sets\n * its own, by prop name (AGL-3056): what a page placing the component still\n * asks the member to fill. Read for the member's note, never listed in a\n * prompt; absent when no default holds one.\n */\n bracketedDefaults?: Record<string, string[]>\n}\n\nexport interface AiInventoryLayout {\n id: string\n name: string\n /** The layout this one nests inside, when it nests. */\n parentId: string | null\n}\n\nexport interface AiInventoryTemplate {\n id: string\n name: string\n kind: string\n}\n\nexport interface AiInventoryForm {\n id: string\n name: string\n fields: string[]\n}\n\nexport interface AiInventoryDataset {\n id: string\n name: string\n fields: string[]\n /**\n * The same fields' ids, in the same order: what a record template binds as\n * `{{item.<id>}}` (AGL-3475). Absent where the reader did not see them.\n */\n fieldIds?: string[]\n /**\n * The id of the field holding each record's photo, where it has one\n * (AGL-3616): what a record template's Image binds as its `src`.\n */\n imageField?: string\n /**\n * The id of the record's page-address field, where it has one (AGL-3727):\n * what a listing's card links each record's own page by. Where the site\n * already serves record pages for the dataset, the field those pages are\n * served by (AGL-3747).\n */\n addressField?: string\n /**\n * Where this site already serves each record a page of its own (AGL-3747):\n * the base of the dataset's saved record template (AGL-3475), without\n * slashes at either end — `team` for `/team/ada`. Absent where the site\n * keeps no record template for it. Never shown in the prompt: code links a\n * listing's cards by it.\n */\n recordBase?: string\n}\n\nexport interface AiInventoryCollection {\n id: string\n name: string\n slug: string\n}\n\nexport interface AiInventoryScreen {\n id: string\n name: string\n slug: string\n layoutId: string | null\n /** A collection's entry template rather than a page of its own. */\n template: boolean\n /**\n * The platform's starter home page, untouched since the site was created\n * (AGL-3594): the screen `host.defaultHomeScreenId` names, still answering\n * `/`, with no version but the one it was provisioned with. A plan may put\n * its own home page at its address, and publishing that page retires this\n * one (AGL-3408). Absent on every other screen, and on a starter home the\n * owner has edited, which a plan keeps and plans around.\n */\n replaceable?: true\n}\n\n/**\n * The site's one theme, as a planner and the email rule read it: a short\n * description, the light scheme's colors by palette path, and the families\n * the theme loads.\n */\nexport interface AiInventoryTheme {\n summary: string[]\n colors: Record<string, string>\n fonts: string[]\n}\n\nexport interface AiSiteInventory {\n hostId: string\n components: AiInventoryComponent[]\n layouts: AiInventoryLayout[]\n templates: AiInventoryTemplate[]\n forms: AiInventoryForm[]\n datasets: AiInventoryDataset[]\n collections: AiInventoryCollection[]\n screens: AiInventoryScreen[]\n theme: AiInventoryTheme | null\n /** Kinds with more records than are listed. */\n truncated: AiInventoryKind[]\n}\n\n/** One inventory record, whatever kind it is. */\nexport type AiInventoryRow =\n | AiInventoryComponent\n | AiInventoryLayout\n | AiInventoryTemplate\n | AiInventoryForm\n | AiInventoryDataset\n | AiInventoryCollection\n | AiInventoryScreen\n\n/**\n * The rows of one kind. The inventory's fields are named after their kinds,\n * so this is a lookup rather than a switch, and it is the one place that\n * relies on the correspondence: the prompt block, the lookup tool and their\n * specs all read a kind through it.\n */\nexport function aiInventoryRows(\n inventory: AiSiteInventory,\n kind: AiInventoryKind,\n): readonly AiInventoryRow[] {\n return inventory[kind]\n}\n\n/** The heading one kind's lines are listed under, naming its columns in order. */\nexport const AI_INVENTORY_KIND_HEADINGS: Readonly<Record<AiInventoryKind, string>> = {\n components: 'Reusable components (id \\u00b7 name \\u00b7 props an instance fills)',\n layouts: 'Layouts (id \\u00b7 name)',\n templates: 'Templates (id \\u00b7 name \\u00b7 kind)',\n forms: 'Forms (id \\u00b7 name \\u00b7 fields)',\n datasets: 'Datasets (id \\u00b7 name \\u00b7 fields)',\n collections: 'Content collections (id \\u00b7 name \\u00b7 slug)',\n screens: 'Pages (id \\u00b7 name \\u00b7 slug)',\n}\n\n/**\n * One record as a line, in the order its heading names the columns. The one\n * renderer: the prompt block and the lookup tool's answer read alike, so a\n * row found by lookup is the same shape as a row that was listed.\n */\nexport function aiInventoryLine(kind: AiInventoryKind, row: AiInventoryRow): string {\n const head = `${row.id} \\u00b7 ${row.name}`\n switch (kind) {\n case 'components': {\n const props = Object.entries((row as AiInventoryComponent).props)\n .map(([name, type]) => `${name}:${type}`)\n .join(', ')\n return `${head} \\u00b7 ${props || 'no props'}`\n }\n case 'layouts':\n return head\n case 'templates':\n return `${head} \\u00b7 ${(row as AiInventoryTemplate).kind}`\n case 'forms':\n return `${head} \\u00b7 ${(row as AiInventoryForm).fields.join(', ')}`\n case 'datasets':\n return `${head} \\u00b7 ${(row as AiInventoryDataset).fields.join(', ')}`\n case 'collections':\n return `${head} \\u00b7 ${(row as AiInventoryCollection).slug}`\n case 'screens': {\n const screen = row as AiInventoryScreen\n return `${head} \\u00b7 ${screen.slug}${screen.template ? ' \\u00b7 entry template' : ''}${\n screen.replaceable ? ' \\u00b7 starter home, a planned home page at / replaces it' : ''\n }`\n }\n }\n}\n\n/** Every word of a record a lookup searches: its line, which holds them all. */\nexport function aiInventoryHaystack(kind: AiInventoryKind, row: AiInventoryRow): string {\n return aiInventoryLine(kind, row).toLowerCase()\n}\n\n/** The addresses a site's home screen is stored under. */\nconst HOME_SLUGS = new Set(['', 'home', 'index'])\n\n/**\n * The site's home screens, by id (AGL-3056): a screen at the root or at\n * `home`, as a seeded site stores its first screen, or one named Home. A link\n * with nowhere to go is sent there, which is why the doctrine names them.\n */\nexport function aiHomeScreenIds(inventory: AiSiteInventory | null): string[] {\n const homes = (inventory?.screens ?? []).filter(\n (screen) =>\n !screen.template &&\n (HOME_SLUGS.has(screen.slug.trim().replace(/^\\/+|\\/+$/g, '').toLowerCase()) ||\n /^home(?:\\s?page)?$/i.test(screen.name.trim())),\n )\n // A starter home a planned home page replaces (AGL-3594) is retired when\n // that page is published, so a link is sent to the page that replaces it\n // wherever the site already has one.\n const kept = homes.filter((screen) => !screen.replaceable)\n return (kept.length ? kept : homes).map((screen) => screen.id)\n}\n\n/** The titles of the site's home screens ({@link aiHomeScreenIds}): a link under one says home, in the site's own language (AGL-3760). */\nexport function aiHomeScreenNames(inventory: AiSiteInventory | null): string[] {\n const ids = new Set(aiHomeScreenIds(inventory))\n return (inventory?.screens ?? []).filter((screen) => ids.has(screen.id) && screen.name.trim()).map((screen) => screen.name.trim())\n}\n\n/** A site the org does not own; the inventory is never read for it. */\nexport class AiInventoryScopeError extends Error {\n constructor(hostId: string) {\n super(`host ${hostId} is not a site of the workspace that asked`)\n this.name = 'AiInventoryScopeError'\n }\n}\n\nexport function emptyAiSiteInventory(hostId: string): AiSiteInventory {\n return {\n hostId,\n components: [],\n layouts: [],\n templates: [],\n forms: [],\n datasets: [],\n collections: [],\n screens: [],\n theme: null,\n truncated: [],\n }\n}\n"],"names":["AI_SITE_INVENTORY_MAX_PER_KIND","AI_SITE_INVENTORY_LISTED_PER_KIND","AI_SITE_INVENTORY_MAX_CHARS","AI_INVENTORY_KINDS","aiInventoryRows","inventory","kind","AI_INVENTORY_KIND_HEADINGS","components","layouts","templates","forms","datasets","collections","screens","aiInventoryLine","row","head","id","name","props","Object","entries","map","type","join","fields","slug","screen","template","replaceable","aiInventoryHaystack","toLowerCase","HOME_SLUGS","Set","aiHomeScreenIds","homes","filter","has","trim","replace","test","kept","length","aiHomeScreenNames","ids","AiInventoryScopeError","Error","hostId","emptyAiSiteInventory","theme","truncated"],"mappings":"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"}
1
+ {"version":3,"sources":["../../../../../../../libs/plugins/ai/src/lib/model/ai-site-inventory.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 * The site's inventory as a model sees it (AGL-2935): what the site already\n * has, so a plan reuses before it creates (doctrine rule 7).\n *\n * COMPACT by construction (AGL-2937): ids, names, prop shapes and slugs —\n * never a node tree, never a record's content. A component is its name and\n * the props an instance fills in; a form is its field names; a dataset its\n * field names. That is everything a planner needs to decide \"reuse this\"\n * and a generator needs to place a reference, and it is a few hundred\n * tokens where the trees would be tens of thousands.\n *\n * CAPPED three times, and the three are different numbers on purpose\n * (AGL-2937). The reader holds each kind to `AI_SITE_INVENTORY_MAX_PER_KIND`;\n * the prompt block LISTS only `AI_SITE_INVENTORY_LISTED_PER_KIND` of them and\n * is held to `AI_SITE_INVENTORY_MAX_CHARS` besides; and the rest are answered\n * on request, through the lookup tool the generation loop offers beside every\n * door's own (`tools/ai-inventory-lookup-tool.ts`).\n *\n * The listing cap is what a prompt can afford: the block is volatile, so it\n * is billed at full input rate on every request and every re-ask, and a site\n * with two hundred components would spend most of a plan's prompt on rows it\n * will not use. The read cap is what a LOOKUP can answer from, which is a\n * different question — a search for \"pricing card\" is worth nothing if the\n * card was never read. A kind cut by either is named in `truncated`, so the\n * model is told more exist rather than concluding they do not.\n *\n * The shapes live here, apart from the reader (`runtime/site-inventory.ts`),\n * so the prompt block, the validators and their specs can hold an inventory\n * without loading the Admin SDK the reader needs.\n */\n\n/**\n * Rows per kind the reader holds. Above the listing cap on purpose: the rows\n * past it are what the lookup tool searches, and a row never read cannot be\n * found. One projection of a few fields each, so the read is small even at\n * this cap.\n */\nexport const AI_SITE_INVENTORY_MAX_PER_KIND = 200\n\n/** Rows per kind the prompt block lists; the rest are found by lookup. */\nexport const AI_SITE_INVENTORY_LISTED_PER_KIND = 40\n\n/** The rendered block's ceiling: 2,000 tokens at four characters a token. */\nexport const AI_SITE_INVENTORY_MAX_CHARS = 8_000\n\nexport type AiInventoryKind =\n | 'components'\n | 'layouts'\n | 'templates'\n | 'forms'\n | 'datasets'\n | 'collections'\n | 'screens'\n\nexport const AI_INVENTORY_KINDS: readonly AiInventoryKind[] = [\n 'components',\n 'layouts',\n 'templates',\n 'forms',\n 'datasets',\n 'collections',\n 'screens',\n]\n\n/**\n * A reusable component's declared props as an instance may fill them: prop\n * name → its declared type (`text`, `image`, `href`, `number`, `boolean`, …).\n */\nexport type AiComponentPropTypes = Record<string, string>\n\nexport interface AiInventoryComponent {\n id: string\n name: string\n /** The props an instance fills in: name → declared type. */\n props: AiComponentPropTypes\n /**\n * The facts in square brackets each prop's default shows until a page sets\n * its own, by prop name (AGL-3056): what a page placing the component still\n * asks the member to fill. Read for the member's note, never listed in a\n * prompt; absent when no default holds one.\n */\n bracketedDefaults?: Record<string, string[]>\n}\n\nexport interface AiInventoryLayout {\n id: string\n name: string\n /** The layout this one nests inside, when it nests. */\n parentId: string | null\n}\n\nexport interface AiInventoryTemplate {\n id: string\n name: string\n kind: string\n}\n\nexport interface AiInventoryForm {\n id: string\n name: string\n fields: string[]\n}\n\nexport interface AiInventoryDataset {\n id: string\n name: string\n fields: string[]\n /**\n * The same fields' ids, in the same order: what a record template binds as\n * `{{item.<id>}}` (AGL-3475). Absent where the reader did not see them.\n */\n fieldIds?: string[]\n /**\n * The id of the field holding each record's photo, where it has one\n * (AGL-3616): what a record template's Image binds as its `src`.\n */\n imageField?: string\n /**\n * The id of the record's page-address field, where it has one (AGL-3727):\n * what a listing's card links each record's own page by. Where the site\n * already serves record pages for the dataset, the field those pages are\n * served by (AGL-3747).\n */\n addressField?: string\n /**\n * Where this site already serves each record a page of its own (AGL-3747):\n * the base of the dataset's saved record template (AGL-3475), without\n * slashes at either end — `team` for `/team/ada`. Absent where the site\n * keeps no record template for it. Never shown in the prompt: code links a\n * listing's cards by it.\n */\n recordBase?: string\n /**\n * Whether it is shared with this site and no other (AGL-3912): its scope\n * names this site alone, so it was made for this site. Absent where it is\n * the workspace's, shared with every site, or with others besides.\n */\n siteOnly?: true\n /**\n * How many records it holds (AGL-3912), counted for a site start's plan\n * only (`aiSiteInventoryWithRecordCounts`); absent where nobody counted, or\n * the count failed. Never shown in the prompt.\n */\n records?: number\n /**\n * Set on a site start's plan only (AGL-3912), where its records are not\n * this site's to show (`aiSiteDatasetIsThisSites`): the plan makes it\n * again rather than reuse it, so a creation of its name is no duplicate.\n */\n foreign?: true\n}\n\nexport interface AiInventoryCollection {\n id: string\n name: string\n slug: string\n}\n\nexport interface AiInventoryScreen {\n id: string\n name: string\n slug: string\n layoutId: string | null\n /** A collection's entry template rather than a page of its own. */\n template: boolean\n /**\n * The platform's starter home page, untouched since the site was created\n * (AGL-3594): the screen `host.defaultHomeScreenId` names, still answering\n * `/`, with no version but the one it was provisioned with. A plan may put\n * its own home page at its address, and publishing that page retires this\n * one (AGL-3408). Absent on every other screen, and on a starter home the\n * owner has edited, which a plan keeps and plans around.\n */\n replaceable?: true\n}\n\n/**\n * The site's one theme, as a planner and the email rule read it: a short\n * description, the light scheme's colors by palette path, and the families\n * the theme loads.\n */\nexport interface AiInventoryTheme {\n summary: string[]\n colors: Record<string, string>\n fonts: string[]\n}\n\nexport interface AiSiteInventory {\n hostId: string\n components: AiInventoryComponent[]\n layouts: AiInventoryLayout[]\n templates: AiInventoryTemplate[]\n forms: AiInventoryForm[]\n datasets: AiInventoryDataset[]\n collections: AiInventoryCollection[]\n screens: AiInventoryScreen[]\n theme: AiInventoryTheme | null\n /** Kinds with more records than are listed. */\n truncated: AiInventoryKind[]\n}\n\n/** One inventory record, whatever kind it is. */\nexport type AiInventoryRow =\n | AiInventoryComponent\n | AiInventoryLayout\n | AiInventoryTemplate\n | AiInventoryForm\n | AiInventoryDataset\n | AiInventoryCollection\n | AiInventoryScreen\n\n/**\n * The rows of one kind. The inventory's fields are named after their kinds,\n * so this is a lookup rather than a switch, and it is the one place that\n * relies on the correspondence: the prompt block, the lookup tool and their\n * specs all read a kind through it.\n */\nexport function aiInventoryRows(\n inventory: AiSiteInventory,\n kind: AiInventoryKind,\n): readonly AiInventoryRow[] {\n return inventory[kind]\n}\n\n/** The heading one kind's lines are listed under, naming its columns in order. */\nexport const AI_INVENTORY_KIND_HEADINGS: Readonly<Record<AiInventoryKind, string>> = {\n components: 'Reusable components (id \\u00b7 name \\u00b7 props an instance fills)',\n layouts: 'Layouts (id \\u00b7 name)',\n templates: 'Templates (id \\u00b7 name \\u00b7 kind)',\n forms: 'Forms (id \\u00b7 name \\u00b7 fields)',\n datasets: 'Datasets (id \\u00b7 name \\u00b7 fields)',\n collections: 'Content collections (id \\u00b7 name \\u00b7 slug)',\n screens: 'Pages (id \\u00b7 name \\u00b7 slug)',\n}\n\n/**\n * One record as a line, in the order its heading names the columns. The one\n * renderer: the prompt block and the lookup tool's answer read alike, so a\n * row found by lookup is the same shape as a row that was listed.\n */\nexport function aiInventoryLine(kind: AiInventoryKind, row: AiInventoryRow): string {\n const head = `${row.id} \\u00b7 ${row.name}`\n switch (kind) {\n case 'components': {\n const props = Object.entries((row as AiInventoryComponent).props)\n .map(([name, type]) => `${name}:${type}`)\n .join(', ')\n return `${head} \\u00b7 ${props || 'no props'}`\n }\n case 'layouts':\n return head\n case 'templates':\n return `${head} \\u00b7 ${(row as AiInventoryTemplate).kind}`\n case 'forms':\n return `${head} \\u00b7 ${(row as AiInventoryForm).fields.join(', ')}`\n case 'datasets':\n return `${head} \\u00b7 ${(row as AiInventoryDataset).fields.join(', ')}`\n case 'collections':\n return `${head} \\u00b7 ${(row as AiInventoryCollection).slug}`\n case 'screens': {\n const screen = row as AiInventoryScreen\n return `${head} \\u00b7 ${screen.slug}${screen.template ? ' \\u00b7 entry template' : ''}${\n screen.replaceable ? ' \\u00b7 starter home, a planned home page at / replaces it' : ''\n }`\n }\n }\n}\n\n/** Every word of a record a lookup searches: its line, which holds them all. */\nexport function aiInventoryHaystack(kind: AiInventoryKind, row: AiInventoryRow): string {\n return aiInventoryLine(kind, row).toLowerCase()\n}\n\n/** The addresses a site's home screen is stored under. */\nconst HOME_SLUGS = new Set(['', 'home', 'index'])\n\n/**\n * The site's home screens, by id (AGL-3056): a screen at the root or at\n * `home`, as a seeded site stores its first screen, or one named Home. A link\n * with nowhere to go is sent there, which is why the doctrine names them.\n */\nexport function aiHomeScreenIds(inventory: AiSiteInventory | null): string[] {\n const homes = (inventory?.screens ?? []).filter(\n (screen) =>\n !screen.template &&\n (HOME_SLUGS.has(screen.slug.trim().replace(/^\\/+|\\/+$/g, '').toLowerCase()) ||\n /^home(?:\\s?page)?$/i.test(screen.name.trim())),\n )\n // A starter home a planned home page replaces (AGL-3594) is retired when\n // that page is published, so a link is sent to the page that replaces it\n // wherever the site already has one.\n const kept = homes.filter((screen) => !screen.replaceable)\n return (kept.length ? kept : homes).map((screen) => screen.id)\n}\n\n/** The titles of the site's home screens ({@link aiHomeScreenIds}): a link under one says home, in the site's own language (AGL-3760). */\nexport function aiHomeScreenNames(inventory: AiSiteInventory | null): string[] {\n const ids = new Set(aiHomeScreenIds(inventory))\n return (inventory?.screens ?? []).filter((screen) => ids.has(screen.id) && screen.name.trim()).map((screen) => screen.name.trim())\n}\n\n/** A site the org does not own; the inventory is never read for it. */\nexport class AiInventoryScopeError extends Error {\n constructor(hostId: string) {\n super(`host ${hostId} is not a site of the workspace that asked`)\n this.name = 'AiInventoryScopeError'\n }\n}\n\nexport function emptyAiSiteInventory(hostId: string): AiSiteInventory {\n return {\n hostId,\n components: [],\n layouts: [],\n templates: [],\n forms: [],\n datasets: [],\n collections: [],\n screens: [],\n theme: null,\n truncated: [],\n }\n}\n"],"names":["AI_SITE_INVENTORY_MAX_PER_KIND","AI_SITE_INVENTORY_LISTED_PER_KIND","AI_SITE_INVENTORY_MAX_CHARS","AI_INVENTORY_KINDS","aiInventoryRows","inventory","kind","AI_INVENTORY_KIND_HEADINGS","components","layouts","templates","forms","datasets","collections","screens","aiInventoryLine","row","head","id","name","props","Object","entries","map","type","join","fields","slug","screen","template","replaceable","aiInventoryHaystack","toLowerCase","HOME_SLUGS","Set","aiHomeScreenIds","homes","filter","has","trim","replace","test","kept","length","aiHomeScreenNames","ids","AiInventoryScopeError","Error","hostId","emptyAiSiteInventory","theme","truncated"],"mappings":"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"}
@@ -336,12 +336,15 @@ export declare function aiSiteEmptyGalleryViolations(plan: Pick<AiBuildPlan, 'sc
336
336
  export declare const AI_SITE_THIN_HOME_CODE = "plan-thin-home";
337
337
  /**
338
338
  * What a site plan's home is composed of, in the words the plan's turn and its
339
- * re-ask both use. Its trust band is what working together is like, never
340
- * testimonials (AGL-3887): a new site has no customer words to show, and a
341
- * home asked for them planned a "Client feedback placeholder" the build could
342
- * fill only with a promise of words to come.
343
- */
344
- export declare const AI_SITE_HOME_BANDS = "a hero first, then bands such as services or the offer, about or why us, and what working together is like, and a closing call to action or contact band last";
339
+ * re-ask both use: a MENU, never an outline (AGL-3899). The hero comes first;
340
+ * the rest is what this business's story needs, in the order the job's arc
341
+ * gives (`model/ai-site-home-arcs.ts`). Told one outline ending "a closing
342
+ * call to action or contact band last", 16 of the 22 newest production homes
343
+ * were the same five bands in the same order, and 19 ended on the same call.
344
+ * Its trust band is what working together is like, never testimonials
345
+ * (AGL-3887): a new site has no customer words to show.
346
+ */
347
+ export declare const AI_SITE_HOME_BANDS = "a hero first, then the sections this business's story needs, chosen from what it offers, its work, its story, how it works, what working together is like, the questions people ask, where to find it and a call to action, in no fixed order";
345
348
  /**
346
349
  * The fewest sections this site start's home is held to (AGL-3660): five, or
347
350
  * 0 — no minimum — where the Free wall cannot pay for a full home beside the
@@ -341,11 +341,14 @@ export const AI_SITE_GALLERY_MAX_ITEMS = 6;
341
341
  /** The violation a site plan whose home page is under its fewest sections is re-asked under. */ export const AI_SITE_THIN_HOME_CODE = 'plan-thin-home';
342
342
  /**
343
343
  * What a site plan's home is composed of, in the words the plan's turn and its
344
- * re-ask both use. Its trust band is what working together is like, never
345
- * testimonials (AGL-3887): a new site has no customer words to show, and a
346
- * home asked for them planned a "Client feedback placeholder" the build could
347
- * fill only with a promise of words to come.
348
- */ export const AI_SITE_HOME_BANDS = 'a hero first, then bands such as services or the offer, about or why us, and what working together is like, and a closing call to action or contact band last';
344
+ * re-ask both use: a MENU, never an outline (AGL-3899). The hero comes first;
345
+ * the rest is what this business's story needs, in the order the job's arc
346
+ * gives (`model/ai-site-home-arcs.ts`). Told one outline ending "a closing
347
+ * call to action or contact band last", 16 of the 22 newest production homes
348
+ * were the same five bands in the same order, and 19 ended on the same call.
349
+ * Its trust band is what working together is like, never testimonials
350
+ * (AGL-3887): a new site has no customer words to show.
351
+ */ export const AI_SITE_HOME_BANDS = "a hero first, then the sections this business's story needs, chosen from what it offers, its work, its story, how it works, what working together is like, the questions people ask, where to find it and a call to action, in no fixed order";
349
352
  /**
350
353
  * The fewest sections this site start's home is held to (AGL-3660): five, or
351
354
  * 0 — no minimum — where the Free wall cannot pay for a full home beside the