@wix/agent-skills 1.14.0 → 1.15.1

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 (268) hide show
  1. package/README.md +12 -1
  2. package/package.json +1 -1
  3. package/skills/README.md +23 -0
  4. package/skills/wix-app/SKILL.md +10 -2
  5. package/skills/wix-app/references/AUTO_PATTERNS_DASHBOARD.md +326 -0
  6. package/skills/wix-app/references/CODE_QUALITY.md +1 -0
  7. package/skills/wix-app/references/CUSTOM_ELEMENT_WIDGET.md +124 -115
  8. package/skills/wix-app/references/DASHBOARD_PAGE.md +3 -0
  9. package/skills/wix-app/references/DATA_COLLECTION.md +5 -3
  10. package/skills/wix-app/references/EDITOR_REACT_COMPONENT.md +25 -9
  11. package/skills/wix-app/references/SITE_PLUGIN.md +1 -1
  12. package/skills/wix-app/references/STORES_VERSIONING.md +9 -211
  13. package/skills/wix-app/references/auto-patterns-dashboard/action-cell.md +115 -0
  14. package/skills/wix-app/references/auto-patterns-dashboard/app-config-structure.md +264 -0
  15. package/skills/wix-app/references/auto-patterns-dashboard/app-context.md +37 -0
  16. package/skills/wix-app/references/auto-patterns-dashboard/bulk-actions.md +86 -0
  17. package/skills/wix-app/references/auto-patterns-dashboard/collection-page-actions.md +119 -0
  18. package/skills/wix-app/references/auto-patterns-dashboard/collection-page.md +103 -0
  19. package/skills/wix-app/references/auto-patterns-dashboard/custom-actions-override.md +76 -0
  20. package/skills/wix-app/references/auto-patterns-dashboard/custom-columns-override.md +82 -0
  21. package/skills/wix-app/references/auto-patterns-dashboard/custom-components-override.md +89 -0
  22. package/skills/wix-app/references/auto-patterns-dashboard/custom-header-override.md +124 -0
  23. package/skills/wix-app/references/auto-patterns-dashboard/custom-sections-override.md +91 -0
  24. package/skills/wix-app/references/auto-patterns-dashboard/custom-slots-override.md +71 -0
  25. package/skills/wix-app/references/auto-patterns-dashboard/entity-page-actions.md +70 -0
  26. package/skills/wix-app/references/auto-patterns-dashboard/entity-page-view-actions.md +73 -0
  27. package/skills/wix-app/references/auto-patterns-dashboard/entity-page.md +98 -0
  28. package/skills/wix-app/references/auto-patterns-dashboard/example-patterns.json +278 -0
  29. package/skills/wix-app/references/auto-patterns-dashboard/pages-configuration.md +94 -0
  30. package/skills/wix-app/references/auto-patterns-dashboard/resolved-action.md +43 -0
  31. package/skills/wix-app/references/auto-patterns-dashboard/sdk-utilities.md +66 -0
  32. package/skills/wix-app/references/auto-patterns-dashboard/views.md +76 -0
  33. package/skills/wix-app/references/backend-event/COMMON-EVENTS.md +5 -0
  34. package/skills/wix-app/references/editor-react-component/ACCESSIBILITY.md +1 -14
  35. package/skills/wix-app/references/editor-react-component/ANIMATED-COMPONENTS.md +151 -0
  36. package/skills/wix-app/references/editor-react-component/COMPONENT-API.md +54 -29
  37. package/skills/wix-app/references/editor-react-component/COMPONENT-CONFIGURATION.md +2 -2
  38. package/skills/wix-app/references/editor-react-component/COMPONENT-PREVIEW.md +57 -0
  39. package/skills/wix-app/references/editor-react-component/CSS-GUIDELINES.md +23 -105
  40. package/skills/wix-app/references/editor-react-component/DESIGN-STATES.md +127 -0
  41. package/skills/wix-app/references/editor-react-component/PARTS.md +2 -1
  42. package/skills/wix-app/references/editor-react-component/REACT-GUIDELINES.md +18 -16
  43. package/skills/wix-app/references/editor-react-component/REACT-PATTERNS.md +25 -53
  44. package/skills/wix-app/references/stores/CATEGORIES.md +22 -0
  45. package/skills/wix-app/references/stores/GET_PRODUCT.md +99 -0
  46. package/skills/wix-app/references/stores/INVENTORY.md +37 -0
  47. package/skills/wix-app/references/stores/QUERY.md +87 -0
  48. package/skills/wix-app/references/stores/WRITE.md +55 -0
  49. package/skills/wix-app/scripts/generate-auto-patterns.js +510 -0
  50. package/skills/wix-auth/SKILL.md +12 -0
  51. package/skills/wix-auth/references/device-flow.md +140 -0
  52. package/skills/wix-docs/SKILL.md +188 -0
  53. package/skills/wix-docs/references/API_SPEC_SEARCH.md +213 -0
  54. package/skills/wix-docs/references/EXTRACTING.md +120 -0
  55. package/skills/wix-headless/SKILL.md +89 -130
  56. package/skills/wix-headless/entry/bootstrap.mjs +93 -0
  57. package/skills/wix-headless/entry/skill.md +76 -0
  58. package/skills/wix-headless/references/AI_FEATURES.md +178 -0
  59. package/skills/wix-headless/references/CAPABILITIES.md +86 -0
  60. package/skills/wix-headless/references/DISCOVERY.md +34 -56
  61. package/skills/wix-headless/references/DOC_DISCOVERY.md +37 -0
  62. package/skills/wix-headless/references/FEEDBACK.md +129 -0
  63. package/skills/wix-headless/references/IMAGE_GENERATION.md +69 -0
  64. package/skills/wix-headless/references/SDK_HANDOFF.md +99 -0
  65. package/skills/wix-headless/references/SEED.md +45 -187
  66. package/skills/wix-headless/references/SETUP.md +32 -103
  67. package/skills/wix-headless/references/astro.md +98 -0
  68. package/skills/wix-headless/references/inline-recipes/how-to-code-a-blog.md +196 -0
  69. package/skills/wix-headless/references/inline-recipes/how-to-code-a-store.md +236 -0
  70. package/skills/wix-headless/references/inline-recipes/how-to-code-bookings.md +279 -0
  71. package/skills/wix-headless/references/inline-recipes/how-to-code-cms.md +163 -0
  72. package/skills/wix-headless/references/inline-recipes/how-to-code-events.md +203 -0
  73. package/skills/wix-headless/references/inline-recipes/how-to-code-forms.md +222 -0
  74. package/skills/wix-headless/references/inline-recipes/how-to-code-members-astro.md +124 -0
  75. package/skills/wix-headless/references/inline-recipes/how-to-code-members-custom-login.md +160 -0
  76. package/skills/wix-headless/references/inline-recipes/how-to-code-members-non-astro.md +118 -0
  77. package/skills/wix-headless/references/inline-recipes/how-to-code-portfolio.md +132 -0
  78. package/skills/wix-headless/references/inline-recipes/how-to-code-pricing-plans.md +124 -0
  79. package/skills/wix-headless/references/inline-recipes/how-to-code-restaurant-orders.md +188 -0
  80. package/skills/wix-headless/references/inline-recipes/how-to-code-restaurant-reservations.md +213 -0
  81. package/skills/wix-headless/references/inline-recipes/how-to-code-restaurants.md +161 -0
  82. package/skills/wix-headless/references/inline-recipes/setup-blog.md +175 -0
  83. package/skills/wix-headless/references/inline-recipes/setup-bookings.md +232 -0
  84. package/skills/wix-headless/references/inline-recipes/setup-cms.md +200 -0
  85. package/skills/wix-headless/references/inline-recipes/setup-events.md +196 -0
  86. package/skills/wix-headless/references/inline-recipes/setup-forms.md +174 -0
  87. package/skills/wix-headless/references/inline-recipes/setup-online-store.md +192 -0
  88. package/skills/wix-headless/references/inline-recipes/setup-portfolio.md +155 -0
  89. package/skills/wix-headless/references/inline-recipes/setup-pricing-plans.md +229 -0
  90. package/skills/wix-headless/references/inline-recipes/setup-restaurant-experiences.md +73 -0
  91. package/skills/wix-headless/references/inline-recipes/setup-restaurant-orders.md +197 -0
  92. package/skills/wix-headless/references/inline-recipes/setup-restaurant-reservations.md +136 -0
  93. package/skills/wix-headless/references/inline-recipes/setup-restaurants.md +152 -0
  94. package/skills/wix-headless/references/managed/AUTHENTICATION.md +57 -0
  95. package/skills/wix-headless/references/managed/CONNECT.md +74 -0
  96. package/skills/wix-headless/references/managed/CREATE.md +130 -0
  97. package/skills/wix-headless/references/managed/DEPLOYMENT.md +79 -0
  98. package/skills/wix-headless/references/non-astro.md +59 -0
  99. package/skills/wix-headless/references/self-managed/AUTHENTICATION.md +22 -0
  100. package/skills/wix-headless/references/self-managed/DEPLOYMENT.md +15 -0
  101. package/skills/wix-headless/references/stripe/AUTHENTICATION.md +55 -0
  102. package/skills/wix-headless/references/stripe/DEPLOYMENT.md +71 -0
  103. package/skills/wix-manage/SKILL.md +29 -3
  104. package/skills/wix-manage/references/analytics/query-site-analytics.md +298 -0
  105. package/skills/wix-manage/references/app-installation/install-wix-apps.md +3 -0
  106. package/skills/wix-manage/references/bookings/create-and-update-booking-services.md +1 -1
  107. package/skills/wix-manage/references/bookings/create-booking-service-from-prompt.md +6 -5
  108. package/skills/wix-manage/references/bookings/create-course-service.md +30 -5
  109. package/skills/wix-manage/references/bookings/diagnose-availability-issues.md +299 -0
  110. package/skills/wix-manage/references/cms/cms-schema-management.md +6 -0
  111. package/skills/wix-manage/references/get-paid/how-to-setup-wix-payments.md +30 -7
  112. package/skills/wix-manage/references/marketing/create-and-publish-social-post.md +517 -0
  113. package/skills/wix-manage/references/marketing/generate-and-publish-marketing-plan.md +218 -0
  114. package/skills/wix-manage/references/rich-content/author-ricos-rich-content.md +249 -0
  115. package/skills/wix-manage/references/sites/site-import.md +270 -0
  116. package/skills/wix-manage/references/stores/create-product-from-image.md +8 -6
  117. package/skills/wix-manage/references/stores/create-product-with-options-catalog-v3.md +57 -0
  118. package/skills/wix-vibe-headless/SKILL.md +142 -0
  119. package/skills/wix-vibe-headless/platforms/README.md +22 -0
  120. package/skills/wix-vibe-headless/platforms/base44.md +142 -0
  121. package/skills/wix-vibe-headless/platforms/generic.md +87 -0
  122. package/skills/wix-vibe-headless/references/blog/INSTRUCTIONS.md +128 -0
  123. package/skills/wix-vibe-headless/references/blog/wix-blog.js +217 -0
  124. package/skills/wix-vibe-headless/references/bookings/INSTRUCTIONS.md +157 -0
  125. package/skills/wix-vibe-headless/references/bookings/wix-bookings-checkout.js +147 -0
  126. package/skills/wix-vibe-headless/references/bookings/wix-bookings-services.js +217 -0
  127. package/skills/wix-vibe-headless/references/cms/INSTRUCTIONS.md +154 -0
  128. package/skills/wix-vibe-headless/references/cms/wix-cms.js +186 -0
  129. package/skills/wix-vibe-headless/references/events/INSTRUCTIONS.md +142 -0
  130. package/skills/wix-vibe-headless/references/events/wix-events-browse.js +136 -0
  131. package/skills/wix-vibe-headless/references/events/wix-events-registration.js +187 -0
  132. package/skills/wix-vibe-headless/references/members/INSTRUCTIONS.md +211 -0
  133. package/skills/wix-vibe-headless/references/members/wix-members-auth.js +387 -0
  134. package/skills/wix-vibe-headless/references/portfolio/INSTRUCTIONS.md +111 -0
  135. package/skills/wix-vibe-headless/references/portfolio/wix-portfolio.js +223 -0
  136. package/skills/wix-vibe-headless/references/pricing-plans/INSTRUCTIONS.md +127 -0
  137. package/skills/wix-vibe-headless/references/pricing-plans/wix-pricing-plans.js +157 -0
  138. package/skills/wix-vibe-headless/references/restaurants/INSTRUCTIONS.md +138 -0
  139. package/skills/wix-vibe-headless/references/restaurants/wix-restaurants-menu.js +224 -0
  140. package/skills/wix-vibe-headless/references/restaurants/wix-restaurants-ordering.js +156 -0
  141. package/skills/wix-vibe-headless/references/restaurants/wix-restaurants-reservations.js +107 -0
  142. package/skills/wix-vibe-headless/references/shared/wix-client.js +186 -0
  143. package/skills/wix-vibe-headless/references/storefront/INSTRUCTIONS.md +164 -0
  144. package/skills/wix-vibe-headless/references/storefront/wix-store-cart.js +147 -0
  145. package/skills/wix-vibe-headless/references/storefront/wix-store-catalog.js +146 -0
  146. package/skills/wix-headless/references/BUILD-astro.md +0 -253
  147. package/skills/wix-headless/references/BUILD-own-build.md +0 -167
  148. package/skills/wix-headless/references/BUILD.md +0 -105
  149. package/skills/wix-headless/references/DESIGN_SYSTEM.md +0 -165
  150. package/skills/wix-headless/references/DISCOVERY-connect.md +0 -55
  151. package/skills/wix-headless/references/DISCOVERY-create.md +0 -238
  152. package/skills/wix-headless/references/PLAN-connect.md +0 -19
  153. package/skills/wix-headless/references/PLAN-create.md +0 -17
  154. package/skills/wix-headless/references/PLAN.md +0 -92
  155. package/skills/wix-headless/references/astro/blog/BLOG_PAGES.md +0 -300
  156. package/skills/wix-headless/references/astro/blog/BLOG_SETUP.md +0 -218
  157. package/skills/wix-headless/references/astro/bookings/COMPONENTS.md +0 -45
  158. package/skills/wix-headless/references/astro/bookings/SERVICES_PAGES.md +0 -77
  159. package/skills/wix-headless/references/astro/cms/CMS_FOUNDATIONS.md +0 -214
  160. package/skills/wix-headless/references/astro/cms/FAQ_KNOWLEDGE_BASE.md +0 -231
  161. package/skills/wix-headless/references/astro/cms/PORTFOLIO.md +0 -453
  162. package/skills/wix-headless/references/astro/cms/RESOURCE_LIBRARY.md +0 -354
  163. package/skills/wix-headless/references/astro/cms/TEAM_DIRECTORY.md +0 -299
  164. package/skills/wix-headless/references/astro/designer/INSTRUCTIONS.md +0 -351
  165. package/skills/wix-headless/references/astro/ecom/CART_PAGES.md +0 -119
  166. package/skills/wix-headless/references/astro/ecom/CART_WIRING.md +0 -103
  167. package/skills/wix-headless/references/astro/ecom/COMPONENTS_CSS.md +0 -132
  168. package/skills/wix-headless/references/astro/forms/CONTACT_FORM.md +0 -463
  169. package/skills/wix-headless/references/astro/gift-cards/COMPONENTS.md +0 -119
  170. package/skills/wix-headless/references/astro/gift-cards/PAGES.md +0 -129
  171. package/skills/wix-headless/references/astro/stores/BACK_IN_STOCK.md +0 -178
  172. package/skills/wix-headless/references/astro/stores/CATEGORY_PAGES.md +0 -85
  173. package/skills/wix-headless/references/astro/stores/COMPONENTS_CSS.md +0 -129
  174. package/skills/wix-headless/references/astro/stores/HOME_AND_NAV.md +0 -229
  175. package/skills/wix-headless/references/astro/stores/PRODUCT_PAGES.md +0 -215
  176. package/skills/wix-headless/references/astro/stores/SHARED_WIRING.md +0 -165
  177. package/skills/wix-headless/references/astro/templates/Layout.astro +0 -132
  178. package/skills/wix-headless/references/astro/templates/astro.config.mjs +0 -41
  179. package/skills/wix-headless/references/astro/templates/bookings/AvailabilityCalendar.tsx +0 -374
  180. package/skills/wix-headless/references/astro/templates/bookings/BookingForm.tsx +0 -136
  181. package/skills/wix-headless/references/astro/templates/bookings/SeoTags.astro +0 -25
  182. package/skills/wix-headless/references/astro/templates/bookings/ServiceBookingFlow.tsx +0 -71
  183. package/skills/wix-headless/references/astro/templates/bookings/ServiceCard.astro +0 -54
  184. package/skills/wix-headless/references/astro/templates/bookings/booking-confirmation.astro +0 -49
  185. package/skills/wix-headless/references/astro/templates/bookings/bookingDriver.ts +0 -245
  186. package/skills/wix-headless/references/astro/templates/bookings/components-bookings.css +0 -424
  187. package/skills/wix-headless/references/astro/templates/bookings/services/[slug].astro +0 -176
  188. package/skills/wix-headless/references/astro/templates/bookings/services/index.astro +0 -181
  189. package/skills/wix-headless/references/astro/templates/ecom/CartBadge.tsx +0 -84
  190. package/skills/wix-headless/references/astro/templates/ecom/CartView.tsx +0 -543
  191. package/skills/wix-headless/references/astro/templates/ecom/cart.astro +0 -13
  192. package/skills/wix-headless/references/astro/templates/ecom/components-ecom.css +0 -302
  193. package/skills/wix-headless/references/astro/templates/ecom/discounts.ts +0 -71
  194. package/skills/wix-headless/references/astro/templates/ecom/thank-you.astro +0 -24
  195. package/skills/wix-headless/references/astro/templates/gift-cards/GiftCardPurchase.tsx +0 -172
  196. package/skills/wix-headless/references/astro/templates/gift-cards/_home-teaser-snippet.astro +0 -42
  197. package/skills/wix-headless/references/astro/templates/gift-cards/_nav-snippet.astro +0 -11
  198. package/skills/wix-headless/references/astro/templates/gift-cards/components-gift-cards.css +0 -220
  199. package/skills/wix-headless/references/astro/templates/gift-cards/gift-cards.astro +0 -51
  200. package/skills/wix-headless/references/astro/templates/gift-cards/gift-cards.ts +0 -75
  201. package/skills/wix-headless/references/astro/templates/global.css +0 -288
  202. package/skills/wix-headless/references/astro/templates/stores/AddToCartButton.tsx +0 -77
  203. package/skills/wix-headless/references/astro/templates/stores/BackInStockForm.tsx +0 -176
  204. package/skills/wix-headless/references/astro/templates/stores/CategoryRail.astro +0 -69
  205. package/skills/wix-headless/references/astro/templates/stores/ProductCard.astro +0 -79
  206. package/skills/wix-headless/references/astro/templates/stores/ProductPurchase.tsx +0 -397
  207. package/skills/wix-headless/references/astro/templates/stores/SeoTags.astro +0 -21
  208. package/skills/wix-headless/references/astro/templates/stores/back-in-stock.ts +0 -67
  209. package/skills/wix-headless/references/astro/templates/stores/categories.ts +0 -155
  210. package/skills/wix-headless/references/astro/templates/stores/category/[slug].astro +0 -130
  211. package/skills/wix-headless/references/astro/templates/stores/components-stores.css +0 -400
  212. package/skills/wix-headless/references/astro/templates/stores/products/[slug].astro +0 -128
  213. package/skills/wix-headless/references/astro/templates/stores/products/index.astro +0 -101
  214. package/skills/wix-headless/references/blog/BLOG_CONTENT.md +0 -161
  215. package/skills/wix-headless/references/blog/INSTRUCTIONS.md +0 -32
  216. package/skills/wix-headless/references/bookings/FLOW.md +0 -246
  217. package/skills/wix-headless/references/bookings/INSTRUCTIONS.md +0 -95
  218. package/skills/wix-headless/references/bookings/SERVICES_DATA.md +0 -355
  219. package/skills/wix-headless/references/cms/CMS_FOUNDATIONS.md +0 -176
  220. package/skills/wix-headless/references/cms/INSTRUCTIONS.md +0 -71
  221. package/skills/wix-headless/references/commands/known-apps.json +0 -6
  222. package/skills/wix-headless/references/custom/CONNECTION_PLAN.md +0 -142
  223. package/skills/wix-headless/references/custom/INSTRUCTIONS.md +0 -88
  224. package/skills/wix-headless/references/custom/blog/WIRING.md +0 -52
  225. package/skills/wix-headless/references/custom/bookings/WIRING.md +0 -197
  226. package/skills/wix-headless/references/custom/cms/WIRING.md +0 -97
  227. package/skills/wix-headless/references/custom/ecom/WIRING.md +0 -67
  228. package/skills/wix-headless/references/custom/forms/WIRING.md +0 -101
  229. package/skills/wix-headless/references/custom/stores/WIRING.md +0 -80
  230. package/skills/wix-headless/references/ecom/INSTRUCTIONS.md +0 -59
  231. package/skills/wix-headless/references/forms/INSTRUCTIONS.md +0 -43
  232. package/skills/wix-headless/references/gift-cards/INSTRUCTIONS.md +0 -51
  233. package/skills/wix-headless/references/images/INSTRUCTIONS.md +0 -357
  234. package/skills/wix-headless/references/seed-recipes.md +0 -49
  235. package/skills/wix-headless/references/shared/AGENTS_MD.md +0 -47
  236. package/skills/wix-headless/references/shared/AUTHENTICATION.md +0 -108
  237. package/skills/wix-headless/references/shared/BUILD_NOISE.md +0 -8
  238. package/skills/wix-headless/references/shared/DESIGN_MD.md +0 -84
  239. package/skills/wix-headless/references/shared/DOCS_SEARCH.md +0 -41
  240. package/skills/wix-headless/references/shared/IMAGE_GENERATION.md +0 -186
  241. package/skills/wix-headless/references/shared/IMPLEMENTER.md +0 -206
  242. package/skills/wix-headless/references/shared/PRODUCTION_SHARP_EDGES.md +0 -97
  243. package/skills/wix-headless/references/shared/RETURN_CONTRACT.md +0 -143
  244. package/skills/wix-headless/references/shared/STYLING.md +0 -140
  245. package/skills/wix-headless/references/stores/INSTRUCTIONS.md +0 -126
  246. package/skills/wix-headless/references/stores/PRODUCT_CATALOG_DATA.md +0 -252
  247. package/skills/wix-headless/references/verticals/_schema.json +0 -74
  248. package/skills/wix-headless/references/verticals/_schema.md +0 -95
  249. package/skills/wix-headless/references/verticals/blog.md +0 -31
  250. package/skills/wix-headless/references/verticals/bookings.md +0 -41
  251. package/skills/wix-headless/references/verticals/cms.md +0 -30
  252. package/skills/wix-headless/references/verticals/ecom.md +0 -25
  253. package/skills/wix-headless/references/verticals/forms.md +0 -26
  254. package/skills/wix-headless/references/verticals/gift-cards.md +0 -24
  255. package/skills/wix-headless/references/verticals/stores.md +0 -33
  256. package/skills/wix-headless/scripts/check-manifest.mjs +0 -335
  257. package/skills/wix-headless/scripts/compose.mjs +0 -520
  258. package/skills/wix-headless/scripts/emit-design-tokens.mjs +0 -157
  259. package/skills/wix-headless/scripts/flatten.sh +0 -61
  260. package/skills/wix-headless/scripts/generate-images.mjs +0 -242
  261. package/skills/wix-headless/scripts/patch-decorative-slots.mjs +0 -154
  262. package/skills/wix-headless/scripts/plan-entity-image-waves.mjs +0 -190
  263. package/skills/wix-headless/scripts/scaffold.sh +0 -139
  264. package/skills/wix-headless/scripts/seed-utilities.sh +0 -93
  265. package/skills/wix-headless/scripts/write-decorative-json.mjs +0 -62
  266. package/skills/wix-headless/shared-utilities/analytics.ts +0 -40
  267. package/skills/wix-headless/shared-utilities/ricos.ts +0 -179
  268. package/skills/wix-headless/shared-utilities/wix-image.ts +0 -72
@@ -1,520 +0,0 @@
1
- #!/usr/bin/env node
2
- // ── compose.mjs — the deterministic Composer (astro design-system phase) ──────
3
- //
4
- // Replaces the former `design-system-composer` LLM subagent (this script is now
5
- // the sole spec). The Composer's job is MECHANICAL: take the Designer's framework-
6
- // agnostic spec + the application inputs and SUBSTITUTE them into six pinned
7
- // skeletons at references/astro/templates/. There is no judgment in re-emitting
8
- // the fixed bulk (View-Transitions script, @utility btn family, view-transition
9
- // CSS), so an LLM is pure cost + run-to-run variance. This script does it in
10
- // sub-second, byte-reproducibly.
11
- //
12
- // It is a sibling of emit-design-tokens.mjs / patch-decorative-slots.mjs and,
13
- // like them, reads its input as a JSON object on stdin and takes the project
14
- // dir as argv[2]. It locates the skeletons relative to its own path (no
15
- // SKILL_ROOT needed).
16
- //
17
- // Usage:
18
- // node compose.mjs <project-dir> <<'JSON'
19
- // { "shell": {...}, "brand": {...}, "navLinks": [...],
20
- // "loadedPacks": [...], "packsWithComponents": [...], "disabledPacks": [...] }
21
- // JSON
22
- //
23
- // Tokens come from DESIGN.md — the single design format (no inline token JSON).
24
- // compose reads `<project-dir>/DESIGN.md` (or `designMdPath`), parses its
25
- // FRONTMATTER ONLY (the markdown body is documentation, never read), and applies
26
- // a role-translation table (references/shared/DESIGN_MD.md) so a DESIGN.md
27
- // authored with standard roles (primary/surface/on-surface/…) maps onto the wix
28
- // `--color-*` vocabulary; wix-native keys pass through losslessly. `rounded` →
29
- // radii; a custom `containers` group + a `googleFontsHref` key are honored.
30
- // The Designer authors that DESIGN.md directly; emit-design-tokens.mjs projects
31
- // the token CSS/types from it. DESIGN.md exists on disk before compose runs.
32
- //
33
- // stdin JSON (the application inputs — NOT the design tokens, which live in DESIGN.md):
34
- // - designMdPath — optional path to the DESIGN.md (default <project-dir>/DESIGN.md).
35
- // - shell — { heroHeadline, heroSub, footerTagline, navBrandMark }.
36
- // - brand — { name, description }.
37
- // - navLinks — [ { href, label } ]; labels used VERBATIM.
38
- // - loadedPacks — string[] of loaded vertical packs.
39
- // - packsWithComponents — string[]; one components-<pack>.css import per entry,
40
- // in order (COMPOSE § Layout.astro).
41
- // - disabledPacks — string[]; dormant packs still get their home/nav markers,
42
- // never a visible entry point.
43
- //
44
- // What it writes (the 6 design-system files), by substituting {{…}} slots into
45
- // the pinned skeletons — the fixed bulk is copied byte-for-byte:
46
- // 1. src/styles/global.css — {{theme}} ← @theme palette
47
- // 2. astro.config.mjs — MERGE (anchored codemod, not clobber)
48
- // 3. src/layouts/Layout.astro — imports, fonts href, brand title
49
- // 4. src/components/Navigation.astro — brand mark, nav links
50
- // 5. src/components/Footer.astro — brand, tagline, nav links
51
- // 6. src/pages/index.astro — hero copy, brand, home markers
52
- //
53
- // Token contract: guarantees the required-token set (STYLING.md § "Required
54
- // tokens — the component-CSS template contract") resolves in @theme. Missing
55
- // roles are DERIVED as a fail-safe (the Designer is expected to emit a complete
56
- // set + a googleFontsHref; derivation is a safety net, not the hot path).
57
- //
58
- // Output: a single manifest JSON object on stdout (the orchestrator parses it
59
- // the same way it parsed the subagent's return — same { status, phase, data,
60
- // files } shape). Diagnostics go to stderr. Exit 0 on complete, 1 on a hard
61
- // failure (missing scaffold / unrecoverable token gap / missing config anchor).
62
- //
63
- // astro only. Custom (non-astro) frontends never reach the Composer — the
64
- // orchestrator only invokes this when frontend === "astro".
65
-
66
- import { readFileSync, writeFileSync, existsSync, mkdirSync } from "node:fs";
67
- import { join, dirname, resolve, isAbsolute } from "node:path";
68
- import { fileURLToPath } from "node:url";
69
- import { execSync } from "node:child_process";
70
-
71
- const SCRIPT_DIR = dirname(fileURLToPath(import.meta.url));
72
- const TEMPLATES = resolve(SCRIPT_DIR, "..", "references", "astro", "templates");
73
-
74
- const projectDir = process.argv[2] ?? process.cwd();
75
-
76
- function die(code, message) {
77
- // Emit a structured failure manifest on stdout so the orchestrator parses a
78
- // return either way, plus a human line on stderr. Hard-fail with exit 1.
79
- console.error(`compose: ${message}`);
80
- console.log(JSON.stringify({ status: "failed", phase: "compose", data: {}, files: [], errors: [{ code, message }] }, null, 2));
81
- process.exit(1);
82
- }
83
-
84
- // ── read + validate input ─────────────────────────────────────────────────────
85
- if (process.stdin.isTTY) die("NO_INPUT", "expected the compose input JSON on stdin");
86
- let input;
87
- try {
88
- const raw = readFileSync(0, "utf8").trim();
89
- if (!raw) die("EMPTY_INPUT", "stdin was empty — pass the compose input JSON object");
90
- input = JSON.parse(raw);
91
- } catch (e) {
92
- die("BAD_JSON", `stdin is not valid JSON (${e.message})`);
93
- }
94
-
95
- // ── token source: DESIGN.md frontmatter (portable) ───────────────────────────
96
- // Minimal frontmatter parser for the restricted DESIGN.md shape (groups of
97
- // `key: scalar`, plus typography tokens with an indented `fontFamily:`). Not a
98
- // general YAML parser — the body is never read. Color values are quoted in the
99
- // emitted DESIGN.md because an unquoted `#hex` after `: ` is a YAML comment.
100
- function unquote(v) {
101
- v = v.trim();
102
- const qc = v[0];
103
- if (qc === '"' || qc === "'") {
104
- // Return the quoted content up to the closing quote (handles a trailing
105
- // ` # comment` after the closing quote, and \" / \\ escapes in "…").
106
- let out = "";
107
- for (let i = 1; i < v.length; i++) {
108
- const c = v[i];
109
- if (qc === '"' && c === "\\" && i + 1 < v.length) { out += v[++i]; continue; }
110
- if (c === qc) break;
111
- out += c;
112
- }
113
- return out;
114
- }
115
- const hash = v.search(/\s#/); // strip trailing inline comment on bare scalars
116
- if (hash !== -1) v = v.slice(0, hash).trim();
117
- return v;
118
- }
119
- // Parse a flow-style inline object — `{ fontFamily: "X", fontWeight: 600 }` —
120
- // splitting top-level commas while respecting quotes (so `"Helvetica, Arial"`
121
- // stays one value). Used for typography tokens authored in flow style.
122
- function parseInlineObject(s) {
123
- const inner = s.trim().replace(/^\{/, "").replace(/\}$/, "");
124
- const obj = {};
125
- let buf = "", inq = null;
126
- const parts = [];
127
- for (const ch of inner) {
128
- if (inq) { if (ch === inq) inq = null; buf += ch; continue; }
129
- if (ch === '"' || ch === "'") { inq = ch; buf += ch; continue; }
130
- if (ch === ",") { parts.push(buf); buf = ""; continue; }
131
- buf += ch;
132
- }
133
- if (buf.trim()) parts.push(buf);
134
- for (const p of parts) {
135
- const ci = p.indexOf(":");
136
- if (ci === -1) continue;
137
- obj[p.slice(0, ci).trim()] = unquote(p.slice(ci + 1));
138
- }
139
- return obj;
140
- }
141
- function parseFrontmatter(text) {
142
- const m = text.match(/^---\r?\n([\s\S]*?)\r?\n---/);
143
- if (!m) return null;
144
- const root = {};
145
- let group = null, sub = null;
146
- for (const raw of m[1].split(/\r?\n/)) {
147
- if (!raw.trim() || /^\s*#/.test(raw)) continue;
148
- const indent = raw.match(/^ */)[0].length;
149
- const ci = raw.indexOf(":");
150
- if (ci === -1) continue;
151
- const key = raw.slice(0, ci).trim();
152
- const rest = raw.slice(ci + 1).trim();
153
- if (indent === 0) {
154
- if (rest === "") { root[key] = {}; group = key; sub = null; }
155
- else if (rest.startsWith("{")) { root[key] = parseInlineObject(rest); group = null; sub = null; }
156
- else { root[key] = unquote(rest); group = null; sub = null; }
157
- } else if (indent === 2 && group) {
158
- if (rest === "") { root[group][key] = {}; sub = key; }
159
- else if (rest.startsWith("{")) { root[group][key] = parseInlineObject(rest); sub = null; }
160
- else { root[group][key] = unquote(rest); sub = null; }
161
- } else if (indent >= 4 && group && sub) {
162
- if (typeof root[group][sub] !== "object") root[group][sub] = {};
163
- root[group][sub][key] = unquote(rest);
164
- }
165
- }
166
- return root;
167
- }
168
- // Standard DESIGN.md color roles → wix editorial `--color-*` names. wix-native
169
- // keys (paper/ink/accent/…) are NOT in this table and pass through unchanged,
170
- // winning on any conflict — so our own emission is lossless.
171
- const COLOR_ROLE_TABLE = {
172
- primary: "accent", secondary: "paper-warm", tertiary: "ink-soft", neutral: "mute",
173
- surface: "paper", "on-surface": "ink", background: "paper", "on-background": "ink",
174
- outline: "rule", error: "error",
175
- };
176
- function designMdToTokens(fm) {
177
- // Single pass preserving source key order: each key maps via the role table
178
- // (standard DESIGN.md role → wix name) or passes through unchanged (wix-native
179
- // keys aren't in the table). Order-preserving so our own round-trip is
180
- // byte-identical to the JSON path. (A file mixing a standard role and its wix
181
- // synonym — e.g. both `surface` and `paper` — is pathological; last wins.)
182
- const colors = {};
183
- for (const [k, v] of Object.entries(fm.colors ?? {})) colors[COLOR_ROLE_TABLE[k] ?? k] = v;
184
- const typ = fm.typography ?? {};
185
- const famOf = (...keys) => { for (const key of keys) if (typ[key] && typ[key].fontFamily) return typ[key].fontFamily; return undefined; };
186
- const fonts = {};
187
- const disp = famOf("display", "h1", "heading", "title");
188
- const body = famOf("body", "p", "text", "base", "paragraph");
189
- if (disp) fonts.display = disp;
190
- if (body) fonts.body = body;
191
- if (typ.mono && typ.mono.fontFamily) fonts.mono = typ.mono.fontFamily;
192
- return {
193
- colors,
194
- fonts,
195
- radii: fm.rounded ?? {}, // DESIGN.md calls corner radii `rounded`
196
- containers: fm.containers ?? {}, // custom group
197
- ...(typeof fm.googleFontsHref === "string" ? { googleFontsHref: fm.googleFontsHref } : {}),
198
- };
199
- }
200
-
201
- // DESIGN.md is the single token source — read it, parse frontmatter only.
202
- const designMdRel = input.designMdPath ?? "DESIGN.md";
203
- const designMdPath = isAbsolute(designMdRel) ? designMdRel : join(projectDir, designMdRel);
204
- if (!existsSync(designMdPath)) die("DESIGN_MD_MISSING", `no DESIGN.md at ${designMdPath} — the Designer must author it first`);
205
- const fm = parseFrontmatter(readFileSync(designMdPath, "utf8"));
206
- if (!fm) die("DESIGN_MD_BAD", `could not parse YAML frontmatter from ${designMdPath}`);
207
- const designTokens = designMdToTokens(fm);
208
- const shell = input.shell ?? {};
209
- const brand = input.brand ?? {};
210
- const navLinks = Array.isArray(input.navLinks) ? input.navLinks : [];
211
- const loadedPacks = Array.isArray(input.loadedPacks) ? input.loadedPacks : [];
212
- const packsWithComponents = Array.isArray(input.packsWithComponents) ? input.packsWithComponents : [];
213
- const disabledPacks = Array.isArray(input.disabledPacks) ? input.disabledPacks : [];
214
-
215
- // Full-page LLM generation (this branch): the LLM authors the entire visible
216
- // page — header (Navigation.astro), footer (Footer.astro), and home page
217
- // (index.astro). compose writes each verbatim; there are no templates for them.
218
- const resolveIn = (p) => { const s = typeof p === "string" ? p.trim() : ""; return s ? (isAbsolute(s) ? s : join(projectDir, s)) : null; };
219
- const navPath = resolveIn(input.navPath);
220
- const footerPath = resolveIn(input.footerPath);
221
- const homePath = resolveIn(input.homePath);
222
-
223
- const brandName = brand.name ?? "Brand";
224
-
225
- // ── small color helper (derivation fail-safe only) ────────────────────────────
226
- function parseHex(hex) {
227
- if (typeof hex !== "string") return null;
228
- let h = hex.trim().replace(/^#/, "");
229
- if (h.length === 3) h = h.split("").map((c) => c + c).join("");
230
- if (!/^[0-9a-fA-F]{6}$/.test(h)) return null;
231
- return [0, 2, 4].map((i) => parseInt(h.slice(i, i + 2), 16));
232
- }
233
- function toHex([r, g, b]) {
234
- return "#" + [r, g, b].map((v) => Math.max(0, Math.min(255, Math.round(v))).toString(16).padStart(2, "0")).join("");
235
- }
236
- // mix `a` toward `b` by weight w (0..1). Falls back to `a` if either unparseable.
237
- function mix(a, b, w) {
238
- const ca = parseHex(a), cb = parseHex(b);
239
- if (!ca || !cb) return a ?? b ?? "#000000";
240
- return toHex(ca.map((v, i) => v + (cb[i] - v) * w));
241
- }
242
-
243
- // ── build the @theme palette + guarantee the required-token contract ──────────
244
- const SYSTEM_FONTS = new Set([
245
- "system-ui", "-apple-system", "blinkmacsystemfont", "segoe ui", "sans-serif",
246
- "serif", "monospace", "ui-sans-serif", "ui-serif", "ui-monospace", "inherit",
247
- ]);
248
-
249
- const colors = { ...(designTokens.colors ?? {}) };
250
- const fonts = { ...(designTokens.fonts ?? {}) };
251
- const radii = { ...(designTokens.radii ?? {}) };
252
- const containers = { ...(designTokens.containers ?? {}) };
253
-
254
- const derived = [];
255
- function ensure(group, key, value, prefix) {
256
- if (group[key] === undefined || group[key] === null || group[key] === "") {
257
- group[key] = value;
258
- derived.push(`${prefix}${key}`);
259
- }
260
- }
261
-
262
- // Colors — required core first (sane neutral defaults if the Designer omitted a
263
- // core role), then warm/soft derivations described in COMPOSE § Token contract.
264
- ensure(colors, "paper", "#ffffff", "--color-");
265
- ensure(colors, "ink", "#1a1a1a", "--color-");
266
- ensure(colors, "accent", colors.ink, "--color-");
267
- ensure(colors, "mute", mix(colors.ink, colors.paper, 0.45), "--color-");
268
- ensure(colors, "rule", mix(colors.ink, colors.paper, 0.85), "--color-");
269
- ensure(colors, "paper-warm", mix(colors.paper, colors.accent, 0.06), "--color-"); // paper warmed
270
- ensure(colors, "ink-soft", mix(colors.ink, colors.paper, 0.25), "--color-"); // ink lightened
271
- // NOTE: cream is derived but not in REQUIRED; gift-cards CSS expects
272
- // --color-cream-deep (undeclared) and relies on the var() fallback — reconcile
273
- // with STYLING.md token contract.
274
- ensure(colors, "cream", mix(colors.paper, "#fbf3e0", 0.5), "--color-");
275
- ensure(colors, "error", "#c0392b", "--color-");
276
-
277
- // Fonts — display + body required.
278
- ensure(fonts, "display", "Georgia, serif", "--font-");
279
- ensure(fonts, "body", "system-ui, sans-serif", "--font-");
280
-
281
- // Spacing is NOT a named scale — Tailwind v4's built-in numeric spacing
282
- // (`--spacing` base → gap-4, py-24, …) is used directly. Emitting named
283
- // --spacing-<t-shirt> tokens collided with the width utilities (max-w-3xl etc.
284
- // drew from --spacing-3xl), so the named scale was removed (CODEAI-696).
285
-
286
- // Radii — sm + md required.
287
- ensure(radii, "sm", "0.25rem", "--radius-");
288
- ensure(radii, "md", "0.5rem", "--radius-");
289
-
290
- // Containers — content widths, a separate axis from spacing.
291
- const CONTAINER_DEFAULTS = { prose: "42rem", md: "48rem", "3xl": "60rem", "6xl": "72rem" };
292
- for (const [k, v] of Object.entries(CONTAINER_DEFAULTS)) ensure(containers, k, v, "--container-");
293
-
294
- // Assemble the @theme block, grouped + ordered for readability.
295
- const themeLines = [];
296
- const emitGroup = (prefix, obj) => {
297
- for (const [k, v] of Object.entries(obj)) themeLines.push(` ${prefix}${k}: ${v};`);
298
- };
299
- emitGroup("--color-", colors);
300
- themeLines.push("");
301
- emitGroup("--font-", fonts);
302
- themeLines.push("");
303
- emitGroup("--radius-", radii);
304
- themeLines.push("");
305
- emitGroup("--container-", containers);
306
- const themeBlock = themeLines.join("\n");
307
-
308
- // ── self-checks (assertions) ──────────────────────────────────────────────────
309
- const errors = [];
310
-
311
- // Required-token coverage (after derivation, every required role must resolve).
312
- const REQUIRED = [
313
- ...["paper", "paper-warm", "ink", "mute", "rule", "accent"].map((k) => `--color-${k}`),
314
- "--font-display", "--font-body",
315
- "--radius-sm", "--radius-md",
316
- ...["prose", "md", "3xl", "6xl"].map((k) => `--container-${k}`),
317
- ];
318
- const present = new Set([
319
- ...Object.keys(colors).map((k) => `--color-${k}`),
320
- ...Object.keys(fonts).map((k) => `--font-${k}`),
321
- ...Object.keys(radii).map((k) => `--radius-${k}`),
322
- ...Object.keys(containers).map((k) => `--container-${k}`),
323
- ]);
324
- for (const tok of REQUIRED) {
325
- if (!present.has(tok)) errors.push({ code: "MISSING_REQUIRED_TOKEN", token: tok });
326
- }
327
-
328
- // ── skeleton load + substitution helpers ──────────────────────────────────────
329
- function readTemplate(name) {
330
- const p = join(TEMPLATES, name);
331
- if (!existsSync(p)) die("TEMPLATE_MISSING", `skeleton not found at ${p}`);
332
- return readFileSync(p, "utf8");
333
- }
334
- function writeProject(rel, content) {
335
- const dest = join(projectDir, rel);
336
- mkdirSync(dirname(dest), { recursive: true });
337
- writeFileSync(dest, content);
338
- }
339
- function escAttr(s) {
340
- return String(s ?? "").replace(/"/g, "&quot;");
341
- }
342
- // Strip the leading "// ── Composer skeleton: … ──" authoring-comment block from
343
- // an .astro skeleton's frontmatter. Those lines document the {{…}} slots (and
344
- // thus contain placeholder text that must NOT be substituted) and are not part
345
- // of the shipped site — the real Composer output drops them too. Removes the
346
- // contiguous run of `//` comment lines immediately after the opening `---`.
347
- function stripAstroHeader(src) {
348
- return src.replace(/^(---\n)((?:[ \t]*\/\/.*\n)+)/, "$1");
349
- }
350
-
351
- // ── Google Fonts href ─────────────────────────────────────────────────────────
352
- // Prefer the Designer-supplied href; otherwise build one deterministically with
353
- // a standard weight set. Returns ""
354
- // when both families are system fonts (caller drops the <link>).
355
- function buildGoogleHref() {
356
- if (typeof designTokens.googleFontsHref === "string" && designTokens.googleFontsHref.trim()) {
357
- return designTokens.googleFontsHref.trim();
358
- }
359
- const families = [];
360
- for (const fam of [fonts.display, fonts.body]) {
361
- if (typeof fam !== "string") continue;
362
- const first = fam.split(",")[0].trim();
363
- if (!first || SYSTEM_FONTS.has(first.toLowerCase())) continue;
364
- if (!families.includes(first)) families.push(first);
365
- }
366
- if (families.length === 0) return "";
367
- const q = families
368
- .map((f) => `family=${f.replace(/\s+/g, "+")}:wght@400;500;600;700`)
369
- .join("&");
370
- return `https://fonts.googleapis.com/css2?${q}&display=swap`;
371
- }
372
-
373
- // ── 1. global.css ──────────────────────────────────────────────────────────────
374
- {
375
- const skeleton = readTemplate("global.css");
376
- // Replace the first `@theme { … }` block (its comment has no braces, so the
377
- // first `}` is its close). Everything else is literal fixed bulk.
378
- const out = skeleton.replace(/@theme\s*\{[\s\S]*?\n\}/, `@theme {\n${themeBlock}\n}`);
379
- if (out === skeleton) die("ANCHOR_THEME", "could not locate the @theme block in global.css skeleton");
380
- writeProject("src/styles/global.css", out);
381
- }
382
-
383
- // ── 2. astro.config.mjs (anchored MERGE, fail loud on missing anchor) ─────────
384
- {
385
- const dest = join(projectDir, "astro.config.mjs");
386
- // The scaffold may briefly be in flight; the new wiring invokes compose only
387
- // after Setup Step 1 awaited the scaffold, so a short retry is belt-and-braces.
388
- let src = null;
389
- for (let attempt = 0; attempt < 10; attempt++) {
390
- if (existsSync(dest)) { src = readFileSync(dest, "utf8"); break; }
391
- try { execSync("sleep 1"); } catch { /* ignore */ }
392
- }
393
- if (src === null) die("SCAFFOLD_NOT_COMPLETE", `astro.config.mjs not found at ${dest} after retries`);
394
-
395
- const hasImport = /import\s+tailwindcss\s+from\s+["']@tailwindcss\/vite["']/.test(src);
396
- const hasCall = /tailwindcss\s*\(\s*\)/.test(src);
397
-
398
- // (1a) import — insert after the last top-level import statement.
399
- if (!hasImport) {
400
- const importRe = /^import\b.*$/gm;
401
- let last = null, m;
402
- while ((m = importRe.exec(src)) !== null) last = m;
403
- if (!last) die("ANCHOR_IMPORT", "no import statement found in astro.config.mjs to anchor the @tailwindcss/vite import");
404
- const insertAt = last.index + last[0].length;
405
- src = src.slice(0, insertAt) + `\nimport tailwindcss from "@tailwindcss/vite";` + src.slice(insertAt);
406
- }
407
-
408
- // (1b) merge tailwindcss() into vite.plugins (idempotent on hasCall).
409
- if (!hasCall) {
410
- if (/plugins\s*:\s*\[/.test(src)) {
411
- src = src.replace(/plugins\s*:\s*\[/, (mm) => `${mm}tailwindcss(), `);
412
- } else if (/\bvite\s*:\s*\{/.test(src)) {
413
- src = src.replace(/(\bvite\s*:\s*\{)/, `$1\n plugins: [tailwindcss()],`);
414
- } else if (/defineConfig\s*\(\s*\{/.test(src)) {
415
- src = src.replace(/(defineConfig\s*\(\s*\{)/, `$1\n vite: { plugins: [tailwindcss()] },`);
416
- } else {
417
- die("ANCHOR_VITE", "could not find vite.plugins, a vite block, or defineConfig({ to register @tailwindcss/vite");
418
- }
419
- }
420
-
421
- // (2) process.env → globalThis guard (TS-safe under strict tsc --noEmit).
422
- const GUARD = `const isBuild =\n (/** @type {any} */ (globalThis)).process?.env?.NODE_ENV === "production";`;
423
- const alreadyGuarded = /\(globalThis\)\)\.process\?\.env\?\.NODE_ENV/.test(src);
424
- const bareRe = /const\s+isBuild\s*=\s*process\.env\.NODE_ENV\s*===?\s*["']production["']\s*;/;
425
- if (!alreadyGuarded) {
426
- if (bareRe.test(src)) {
427
- src = src.replace(bareRe, GUARD);
428
- } else if (/process\.env/.test(src)) {
429
- die("ANCHOR_PROCESS_ENV", "found a bare process.env reference but not the expected `const isBuild = process.env.NODE_ENV …` line to guard");
430
- }
431
- // else: no process.env at all — nothing to guard, leave as-is.
432
- }
433
-
434
- writeProject("astro.config.mjs", src);
435
- }
436
-
437
- // ── 3. Layout.astro ────────────────────────────────────────────────────────────
438
- const componentCssImports = packsWithComponents.map(
439
- (pack) => `import '../styles/components-${pack}.css';`,
440
- );
441
- {
442
- let out = stripAstroHeader(readTemplate("Layout.astro"));
443
- // {{components-css-imports}} — one import per pack, or drop the whole line.
444
- if (componentCssImports.length) {
445
- out = out.replace(/^\{\{components-css-imports\}\}\s*$/m, componentCssImports.join("\n"));
446
- } else {
447
- out = out.replace(/^\{\{components-css-imports\}\}\s*\n/m, "");
448
- }
449
- // {{fonts.googleHref}} — drop the <link> when no web fonts.
450
- const href = buildGoogleHref();
451
- if (href) {
452
- out = out.replace(/\{\{fonts\.googleHref\}\}/g, escAttr(href));
453
- } else {
454
- out = out.replace(/^.*\{\{fonts\.googleHref\}\}.*\n/m, "");
455
- }
456
- out = out.replaceAll("{{brand.name}}", brandName);
457
- writeProject("src/layouts/Layout.astro", out);
458
- }
459
-
460
- // ── nav-link rendering ──────────────────────────────────────────────────────────
461
- const navItems = navLinks
462
- .filter((l) => l && l.href != null && l.label != null)
463
- .map((l) => ({ href: String(l.href), label: String(l.label) }));
464
-
465
- // ── 4. Navigation.astro (LLM-generated, verbatim) ─────────────────────────────
466
- {
467
- if (!navPath || !existsSync(navPath)) die("NO_NAV", `LLM-generated header required via navPath (none at ${navPath ?? "<unset>"})`);
468
- writeProject("src/components/Navigation.astro", readFileSync(navPath, "utf8"));
469
- }
470
-
471
- // ── 5. Footer.astro (LLM-generated, verbatim) ─────────────────────────────────
472
- {
473
- if (!footerPath || !existsSync(footerPath)) die("NO_FOOTER", `LLM-generated footer required via footerPath (none at ${footerPath ?? "<unset>"})`);
474
- writeProject("src/components/Footer.astro", readFileSync(footerPath, "utf8"));
475
- }
476
-
477
- // ── 6. index.astro ────────────────────────────────────────────────────────────────
478
- // Home markers: one `<!-- home:<pack> -->` per contributing pack. Today
479
- // stores + bookings + gift-cards contribute a home section. Disabled packs
480
- // (gift-cards) still get their marker (markers are their only acceptable touchpoint).
481
- const HOME_CONTRIBUTING = ["stores", "bookings", "gift-cards"]; // canonical order
482
- const homePool = new Set([...loadedPacks, ...disabledPacks]);
483
- const homeMarkerPacks = HOME_CONTRIBUTING.filter((p) => homePool.has(p));
484
- {
485
- if (!homePath || !existsSync(homePath)) die("NO_HOME", `LLM-generated home page required via homePath (none at ${homePath ?? "<unset>"})`);
486
- writeProject("src/pages/index.astro", readFileSync(homePath, "utf8"));
487
- }
488
-
489
- // ── manifest (the orchestrator parses this off stdout) ────────────────────────
490
- const filesWritten = [
491
- "src/styles/global.css",
492
- "astro.config.mjs",
493
- "src/layouts/Layout.astro",
494
- "src/components/Navigation.astro",
495
- "src/components/Footer.astro",
496
- "src/pages/index.astro",
497
- ];
498
- const manifest = {
499
- status: errors.length ? "partial" : "complete",
500
- phase: "compose",
501
- data: {
502
- filesWritten,
503
- nav: "llm-generated",
504
- footer: "llm-generated",
505
- home: "llm-generated",
506
- componentCssImports: packsWithComponents,
507
- homeMarkers: homeMarkerPacks.map((p) => `home:${p}`),
508
- tokensApplied: {
509
- colors: Object.keys(colors).length,
510
- containers: Object.keys(containers).length,
511
- radii: Object.keys(radii).length,
512
- fonts: Object.keys(fonts).length,
513
- },
514
- ...(derived.length ? { derivedTokens: derived } : {}),
515
- },
516
- files: filesWritten,
517
- ...(errors.length ? { errors } : {}),
518
- };
519
- console.log(JSON.stringify(manifest, null, 2));
520
- process.exit(0);