@wix/agent-skills 1.20.0 → 1.21.0

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 (183) hide show
  1. package/package.json +1 -1
  2. package/skills/wix-app/SKILL.md +14 -112
  3. package/skills/wix-app/references/APP_TOOLS.md +2 -1
  4. package/skills/wix-app/references/BACKEND_EVENT.md +3 -3
  5. package/skills/wix-app/references/CUSTOM_ELEMENT_WIDGET.md +41 -152
  6. package/skills/wix-app/references/DASHBOARD_MODAL.md +4 -4
  7. package/skills/wix-app/references/SDK_MODULE_MAP.md +44 -0
  8. package/skills/wix-app/references/SITE_PLUGIN.md +36 -190
  9. package/skills/wix-app/references/app-tools/TOOLS.md +3 -1
  10. package/skills/wix-app/references/custom-element-widget/SETTINGS_PANEL.md +21 -0
  11. package/skills/wix-app/references/dashboard-page/ECOM_NAVIGATION.md +17 -0
  12. package/skills/wix-app/references/dashboard-plugin/SLOTS.md +4 -18
  13. package/skills/wix-app/references/site-plugin/EXAMPLES.md +1 -1
  14. package/skills/wix-headless-fast/SKILL.md +302 -51
  15. package/skills/wix-headless-fast/entry/skill.md +11 -2
  16. package/skills/wix-headless-fast/install/AGENTS.md +32 -0
  17. package/skills/wix-headless-fast/install/agents-md.mjs +39 -0
  18. package/skills/wix-headless-fast/install/attach.mjs +360 -0
  19. package/skills/wix-headless-fast/install/deploy.mjs +109 -9
  20. package/skills/wix-headless-fast/install/setup.mjs +239 -0
  21. package/skills/wix-headless-fast/references/blog/INSTRUCTIONS.md +226 -60
  22. package/skills/wix-headless-fast/references/blog/app/components/blog/BlogFeedView.tsx +2 -3
  23. package/skills/wix-headless-fast/references/blog/app/components/blog/PostView.tsx +2 -3
  24. package/skills/wix-headless-fast/references/blog/app/hooks/blog/useBlogFeed.ts +24 -116
  25. package/skills/wix-headless-fast/references/blog/app/hooks/blog/usePost.ts +16 -64
  26. package/skills/wix-headless-fast/references/blog/app/wix/blog/blog-feed-store.ts +137 -0
  27. package/skills/wix-headless-fast/references/blog/app/wix/blog/post-store.ts +78 -0
  28. package/skills/wix-headless-fast/references/blog/app/wix/blog/posts-core.ts +117 -0
  29. package/skills/wix-headless-fast/references/blog/app/wix/blog/posts.ts +13 -60
  30. package/skills/wix-headless-fast/references/blog/app/wix/blog/taxonomy-core.ts +47 -0
  31. package/skills/wix-headless-fast/references/blog/app/wix/blog/taxonomy.ts +10 -28
  32. package/skills/wix-headless-fast/references/blog/app-astro/pages/blog/[...slug].astro +2 -4
  33. package/skills/wix-headless-fast/references/blog/rest/posts.ts +42 -0
  34. package/skills/wix-headless-fast/references/blog/rest/taxonomy.ts +62 -0
  35. package/skills/wix-headless-fast/references/blog/seed/SEED.md +9 -0
  36. package/skills/wix-headless-fast/references/blog/seed/read-site.mjs +22 -0
  37. package/skills/wix-headless-fast/references/bookings/INSTRUCTIONS.md +181 -33
  38. package/skills/wix-headless-fast/references/bookings/app/components/bookings/ServiceBookingView.tsx +2 -1
  39. package/skills/wix-headless-fast/references/bookings/app/hooks/bookings/useBookingFlow.ts +26 -132
  40. package/skills/wix-headless-fast/references/bookings/app/hooks/bookings/useServices.ts +18 -49
  41. package/skills/wix-headless-fast/references/bookings/app/wix/bookings/booking-core.ts +218 -0
  42. package/skills/wix-headless-fast/references/bookings/app/wix/bookings/booking-flow-store.ts +169 -0
  43. package/skills/wix-headless-fast/references/bookings/app/wix/bookings/booking.ts +57 -142
  44. package/skills/wix-headless-fast/references/bookings/app/wix/bookings/services-core.ts +92 -0
  45. package/skills/wix-headless-fast/references/bookings/app/wix/bookings/services-store.ts +90 -0
  46. package/skills/wix-headless-fast/references/bookings/app/wix/bookings/services.ts +22 -61
  47. package/skills/wix-headless-fast/references/bookings/app/wix/bookings/types.ts +3 -1
  48. package/skills/wix-headless-fast/references/bookings/rest/booking.ts +113 -0
  49. package/skills/wix-headless-fast/references/bookings/rest/services.ts +55 -0
  50. package/skills/wix-headless-fast/references/bookings/seed/SEED.md +10 -0
  51. package/skills/wix-headless-fast/references/bookings/seed/read-site.mjs +28 -0
  52. package/skills/wix-headless-fast/references/cms/INSTRUCTIONS.md +238 -62
  53. package/skills/wix-headless-fast/references/cms/app/hooks/cms/useCollection.ts +19 -52
  54. package/skills/wix-headless-fast/references/cms/app/hooks/cms/useItem.ts +16 -36
  55. package/skills/wix-headless-fast/references/cms/app/wix/cms/collection-store.ts +158 -0
  56. package/skills/wix-headless-fast/references/cms/app/wix/cms/item-store.ts +93 -0
  57. package/skills/wix-headless-fast/references/cms/app/wix/cms/items-core.ts +177 -0
  58. package/skills/wix-headless-fast/references/cms/app/wix/cms/items.ts +13 -41
  59. package/skills/wix-headless-fast/references/cms/rest/items.ts +125 -0
  60. package/skills/wix-headless-fast/references/cms/seed/SEED.md +9 -0
  61. package/skills/wix-headless-fast/references/cms/seed/read-site.mjs +20 -0
  62. package/skills/wix-headless-fast/references/events/INSTRUCTIONS.md +241 -83
  63. package/skills/wix-headless-fast/references/events/app/components/events/EventConfirmationView.tsx +1 -1
  64. package/skills/wix-headless-fast/references/events/app/components/events/EventRegistrationView.tsx +7 -5
  65. package/skills/wix-headless-fast/references/events/app/components/events/EventsView.tsx +2 -2
  66. package/skills/wix-headless-fast/references/events/app/hooks/events/useEventRegistration.ts +28 -110
  67. package/skills/wix-headless-fast/references/events/app/hooks/events/useEvents.ts +19 -54
  68. package/skills/wix-headless-fast/references/events/app/wix/events/events-core.ts +130 -0
  69. package/skills/wix-headless-fast/references/events/app/wix/events/events-store.ts +97 -0
  70. package/skills/wix-headless-fast/references/events/app/wix/events/events.ts +13 -94
  71. package/skills/wix-headless-fast/references/events/app/wix/events/registration-core.ts +113 -0
  72. package/skills/wix-headless-fast/references/events/app/wix/events/registration-store.ts +156 -0
  73. package/skills/wix-headless-fast/references/events/app/wix/events/registration.ts +38 -69
  74. package/skills/wix-headless-fast/references/events/rest/events.ts +57 -0
  75. package/skills/wix-headless-fast/references/events/rest/registration.ts +83 -0
  76. package/skills/wix-headless-fast/references/events/seed/SEED.md +9 -0
  77. package/skills/wix-headless-fast/references/events/seed/read-site.mjs +26 -0
  78. package/skills/wix-headless-fast/references/forms/INSTRUCTIONS.md +216 -26
  79. package/skills/wix-headless-fast/references/forms/app/hooks/forms/useWixForm.ts +35 -267
  80. package/skills/wix-headless-fast/references/forms/app/wix/forms/form-store.ts +332 -0
  81. package/skills/wix-headless-fast/references/forms/app/wix/forms/forms-core.ts +238 -0
  82. package/skills/wix-headless-fast/references/forms/app/wix/forms/forms.ts +28 -243
  83. package/skills/wix-headless-fast/references/forms/app/wix/forms/submissions-core.ts +216 -0
  84. package/skills/wix-headless-fast/references/forms/app/wix/forms/submissions.ts +32 -204
  85. package/skills/wix-headless-fast/references/forms/rest/forms.ts +34 -0
  86. package/skills/wix-headless-fast/references/forms/rest/submissions.ts +56 -0
  87. package/skills/wix-headless-fast/references/forms/seed/SEED.md +8 -0
  88. package/skills/wix-headless-fast/references/forms/seed/read-site.mjs +20 -0
  89. package/skills/wix-headless-fast/references/forms/seed/seed-forms.mjs +15 -8
  90. package/skills/wix-headless-fast/references/members/INSTRUCTIONS.md +316 -63
  91. package/skills/wix-headless-fast/references/members/app/components/members/LoginForm.tsx +1 -1
  92. package/skills/wix-headless-fast/references/members/app/wix/members/auth-core.ts +105 -0
  93. package/skills/wix-headless-fast/references/members/app/wix/members/auth.ts +36 -65
  94. package/skills/wix-headless-fast/references/members/app/wix/members/client.ts +1 -1
  95. package/skills/wix-headless-fast/references/members/app/wix/members/members-core.ts +43 -0
  96. package/skills/wix-headless-fast/references/members/app/wix/members/members.ts +11 -32
  97. package/skills/wix-headless-fast/references/members/rest/auth.ts +215 -0
  98. package/skills/wix-headless-fast/references/members/rest/members.ts +26 -0
  99. package/skills/wix-headless-fast/references/members/seed/read-site.mjs +15 -0
  100. package/skills/wix-headless-fast/references/portfolio/INSTRUCTIONS.md +240 -59
  101. package/skills/wix-headless-fast/references/portfolio/app/components/portfolio/CollectionProjectsView.tsx +2 -2
  102. package/skills/wix-headless-fast/references/portfolio/app/components/portfolio/CollectionsView.tsx +2 -2
  103. package/skills/wix-headless-fast/references/portfolio/app/components/portfolio/GalleryMedia.tsx +35 -0
  104. package/skills/wix-headless-fast/references/portfolio/app/components/portfolio/ProjectDetailView.tsx +8 -38
  105. package/skills/wix-headless-fast/references/portfolio/app/hooks/portfolio/useCollectionProjects.ts +23 -50
  106. package/skills/wix-headless-fast/references/portfolio/app/hooks/portfolio/useCollections.ts +16 -34
  107. package/skills/wix-headless-fast/references/portfolio/app/hooks/portfolio/useProjectDetail.ts +22 -49
  108. package/skills/wix-headless-fast/references/portfolio/app/wix/portfolio/collection-projects-store.ts +82 -0
  109. package/skills/wix-headless-fast/references/portfolio/app/wix/portfolio/collections-store.ts +58 -0
  110. package/skills/wix-headless-fast/references/portfolio/app/wix/portfolio/portfolio-core.ts +177 -0
  111. package/skills/wix-headless-fast/references/portfolio/app/wix/portfolio/portfolio.ts +31 -118
  112. package/skills/wix-headless-fast/references/portfolio/app/wix/portfolio/project-detail-store.ts +81 -0
  113. package/skills/wix-headless-fast/references/portfolio/rest/portfolio.ts +75 -0
  114. package/skills/wix-headless-fast/references/portfolio/seed/SEED.md +8 -0
  115. package/skills/wix-headless-fast/references/portfolio/seed/read-site.mjs +20 -0
  116. package/skills/wix-headless-fast/references/portfolio/seed/seed-portfolio.mjs +19 -21
  117. package/skills/wix-headless-fast/references/pricing-plans/INSTRUCTIONS.md +214 -51
  118. package/skills/wix-headless-fast/references/pricing-plans/app/components/pricing-plans/PlanDetailView.tsx +9 -20
  119. package/skills/wix-headless-fast/references/pricing-plans/app/components/pricing-plans/PlansView.tsx +7 -32
  120. package/skills/wix-headless-fast/references/pricing-plans/app/components/pricing-plans/SubscribeButton.tsx +41 -0
  121. package/skills/wix-headless-fast/references/pricing-plans/app/hooks/pricing-plans/usePlanPurchase.ts +12 -33
  122. package/skills/wix-headless-fast/references/pricing-plans/app/hooks/pricing-plans/usePlans.ts +17 -34
  123. package/skills/wix-headless-fast/references/pricing-plans/app/wix/pricing-plans/plan-purchase-store.ts +54 -0
  124. package/skills/wix-headless-fast/references/pricing-plans/app/wix/pricing-plans/plans-core.ts +106 -0
  125. package/skills/wix-headless-fast/references/pricing-plans/app/wix/pricing-plans/plans-store.ts +64 -0
  126. package/skills/wix-headless-fast/references/pricing-plans/app/wix/pricing-plans/plans.ts +7 -55
  127. package/skills/wix-headless-fast/references/pricing-plans/app/wix/pricing-plans/purchase-core.ts +43 -0
  128. package/skills/wix-headless-fast/references/pricing-plans/app/wix/pricing-plans/purchase.ts +11 -34
  129. package/skills/wix-headless-fast/references/pricing-plans/rest/plans.ts +31 -0
  130. package/skills/wix-headless-fast/references/pricing-plans/rest/purchase.ts +20 -0
  131. package/skills/wix-headless-fast/references/pricing-plans/seed/SEED.md +8 -0
  132. package/skills/wix-headless-fast/references/pricing-plans/seed/read-site.mjs +21 -0
  133. package/skills/wix-headless-fast/references/restaurants/INSTRUCTIONS.md +242 -47
  134. package/skills/wix-headless-fast/references/restaurants/app/components/restaurants/MenuView.tsx +2 -2
  135. package/skills/wix-headless-fast/references/restaurants/app/components/restaurants/OrderCartDrawer.tsx +2 -2
  136. package/skills/wix-headless-fast/references/restaurants/app/hooks/restaurants/useMenus.ts +14 -35
  137. package/skills/wix-headless-fast/references/restaurants/app/hooks/restaurants/useReservation.ts +28 -171
  138. package/skills/wix-headless-fast/references/restaurants/app/wix/restaurants/menu-core.ts +155 -0
  139. package/skills/wix-headless-fast/references/restaurants/app/wix/restaurants/menu-store.ts +89 -0
  140. package/skills/wix-headless-fast/references/restaurants/app/wix/restaurants/menu.ts +23 -117
  141. package/skills/wix-headless-fast/references/restaurants/app/wix/restaurants/ordering-core.ts +124 -0
  142. package/skills/wix-headless-fast/references/restaurants/app/wix/restaurants/ordering.ts +45 -114
  143. package/skills/wix-headless-fast/references/restaurants/app/wix/restaurants/reservation-store.ts +193 -0
  144. package/skills/wix-headless-fast/references/restaurants/app/wix/restaurants/reservations-core.ts +94 -0
  145. package/skills/wix-headless-fast/references/restaurants/app/wix/restaurants/reservations.ts +15 -87
  146. package/skills/wix-headless-fast/references/restaurants/rest/menu.ts +60 -0
  147. package/skills/wix-headless-fast/references/restaurants/rest/ordering.ts +169 -0
  148. package/skills/wix-headless-fast/references/restaurants/rest/reservations.ts +68 -0
  149. package/skills/wix-headless-fast/references/restaurants/seed/SEED.md +8 -0
  150. package/skills/wix-headless-fast/references/restaurants/seed/read-site.mjs +25 -0
  151. package/skills/wix-headless-fast/references/restaurants/seed/seed-restaurants.mjs +25 -5
  152. package/skills/wix-headless-fast/references/shared/SUPPLIED-CONTENT.md +23 -0
  153. package/skills/wix-headless-fast/references/shared/app/wix/media.ts +45 -4
  154. package/skills/wix-headless-fast/references/shared/app/wix/sdk.ts +13 -0
  155. package/skills/wix-headless-fast/references/shared/rest/client.ts +155 -0
  156. package/skills/wix-headless-fast/references/shared/rest/config.ts +3 -0
  157. package/skills/wix-headless-fast/references/shared/rest/media.ts +65 -0
  158. package/skills/wix-headless-fast/references/shared/seed/read-site.mjs +99 -0
  159. package/skills/wix-headless-fast/references/storefront/INSTRUCTIONS.md +186 -63
  160. package/skills/wix-headless-fast/references/storefront/app/components/storefront/OptionPicker.tsx +95 -0
  161. package/skills/wix-headless-fast/references/storefront/app/components/storefront/QuickAdd.tsx +29 -58
  162. package/skills/wix-headless-fast/references/storefront/app/hooks/storefront/useProductDetail.ts +29 -163
  163. package/skills/wix-headless-fast/references/storefront/app/hooks/storefront/useShop.ts +26 -300
  164. package/skills/wix-headless-fast/references/storefront/app/wix/storefront/cart-core.ts +121 -0
  165. package/skills/wix-headless-fast/references/storefront/app/wix/storefront/cart.ts +49 -162
  166. package/skills/wix-headless-fast/references/storefront/app/wix/storefront/catalog-core.ts +314 -0
  167. package/skills/wix-headless-fast/references/storefront/app/wix/storefront/catalog.ts +47 -370
  168. package/skills/wix-headless-fast/references/storefront/app/wix/storefront/product-detail-store.ts +147 -0
  169. package/skills/wix-headless-fast/references/storefront/app/wix/storefront/shop-store.ts +289 -0
  170. package/skills/wix-headless-fast/references/storefront/app/wix/storefront/types.ts +2 -0
  171. package/skills/wix-headless-fast/references/storefront/rest/cart.ts +132 -0
  172. package/skills/wix-headless-fast/references/storefront/rest/catalog.ts +123 -0
  173. package/skills/wix-headless-fast/references/storefront/seed/SEED.md +31 -9
  174. package/skills/wix-headless-fast/references/storefront/seed/read-site.mjs +38 -0
  175. package/skills/wix-headless-fast/references/storefront/seed/seed-store.mjs +57 -50
  176. package/skills/wix-manage/references/ecommerce/ecom-shipping.md +1 -1
  177. package/skills/wix-manage/references/ecommerce/pricing-promotions/ecom-pricing-create-coupon.md +10 -19
  178. package/skills/wix-manage/references/events/create-wix-event.md +5 -1
  179. package/skills/wix-vibe-headless/references/storefront/INSTRUCTIONS.md +0 -40
  180. package/skills/wix-vibe-headless/references/storefront/seed/SEED.md +3 -0
  181. package/skills/wix-vibe-headless/references/storefront/seed/seed-store.cjs +6 -0
  182. package/skills/wix-headless-fast/install/fast-path.mjs +0 -186
  183. package/skills/wix-headless-fast/install/pin-agents-md.mjs +0 -57
@@ -1,7 +1,7 @@
1
1
  // Storefront seed — a BUILD-TIME script, never shipped in the app. Run it from the project
2
2
  // root (where wix.config.json lives) with a plan file:
3
3
  //
4
- // node <SKILL_ROOT>/references/storefront/seed/seed-store.mjs plan.json [--fresh-site]
4
+ // node <SKILL_ROOT>/references/storefront/seed/seed-store.mjs plan.json
5
5
  //
6
6
  // It mints its own site token via the Wix CLI (the token never leaves this process), installs
7
7
  // the Wix Stores app if needed, waits for the V3 catalog, bulk-creates products (variants
@@ -367,23 +367,6 @@ export async function createCategories(ctx, names) {
367
367
  return out;
368
368
  }
369
369
 
370
- // The Stores install drops sample products ("I'm a product") into every new catalog. On a site the
371
- // fast path JUST created nothing else can exist, so they are deleted before seeding — otherwise the
372
- // storefront ships with the samples between the real products. Only called with --fresh-site; a
373
- // seed against an existing site never deletes anything (SEED.md: seeding is additive).
374
- // docs: https://dev.wix.com/docs/api-reference/business-solutions/stores/catalog-v3/products-v3/bulk-delete-products.md
375
- export async function deleteAllProducts(ctx) {
376
- let deleted = 0;
377
- for (let pass = 0; pass < 10; pass++) {
378
- const r = await req(ctx, "/stores/v3/products/query", { body: { query: { cursorPaging: { limit: 100 } } } });
379
- const ids = (r.products ?? []).map((p) => p.id).filter(Boolean);
380
- if (!ids.length) break;
381
- await req(ctx, "/stores/v3/bulk/products/delete", { body: { productIds: ids } });
382
- deleted += ids.length;
383
- if (ids.length < 100) break;
384
- }
385
- return deleted;
386
- }
387
370
 
388
371
  // docs: https://dev.wix.com/docs/api-reference/business-solutions/stores/catalog-v3/categories/bulk-add-items-to-category.md
389
372
  export async function addProductsToCategories(ctx, mapping) {
@@ -401,19 +384,47 @@ export async function addProductsToCategories(ctx, mapping) {
401
384
  // current revision is read right before the update, so attach any number of times, any pass.
402
385
  // Wix re-hosts each url server-side; the media can take a little while to appear on read-back
403
386
  // (propagation) — normal, not a failure.
387
+ // The bulk update returns 200 on PARTIAL failure, like the bulk create: each item's outcome is
388
+ // in results[].itemMetadata (success, error, originalIndex). Seen live (runs 85 and 86,
389
+ // 2026-09-26): one product of three came back with no media while the call succeeded — most
390
+ // likely its revision moved between the read and the update (variant stocking runs just
391
+ // before). So: pair results to inputs, retry the misses once with fresh revisions, and report
392
+ // what actually persisted. Returns { attached: [id], failures: [{ id, error }] }.
404
393
  // docs: https://dev.wix.com/docs/api-reference/business-solutions/stores/catalog-v3/products-v3/bulk-update-products.md
405
394
  export async function attachProductImages(ctx, items) {
406
- if (!items?.length) return;
407
- const ids = items.map((it) => it.id);
408
- const q = await req(ctx, "/stores/v3/products/query", { body: { query: { filter: { id: { $in: ids } }, paging: { limit: ids.length } } } });
409
- const revById = new Map((q.products ?? []).map((p) => [p.id, p.revision]));
410
- return req(ctx, "/stores/v3/bulk/products/update", {
411
- body: {
412
- products: items.map((it) => ({
413
- product: { id: it.id, revision: revById.get(it.id), media: { itemsInfo: { items: [{ url: it.url, altText: it.altText }] } } },
414
- })),
415
- },
416
- });
395
+ if (!items?.length) return { attached: [], failures: [] };
396
+ const send = async (batch) => {
397
+ const ids = batch.map((it) => it.id);
398
+ const q = await req(ctx, "/stores/v3/products/query", { body: { query: { filter: { id: { $in: ids } }, paging: { limit: ids.length } } } });
399
+ const revById = new Map((q.products ?? []).map((p) => [p.id, p.revision]));
400
+ const r = await req(ctx, "/stores/v3/bulk/products/update", {
401
+ body: {
402
+ products: batch.map((it) => ({
403
+ product: { id: it.id, revision: revById.get(it.id), media: { itemsInfo: { items: [{ url: it.url, altText: it.altText }] } } },
404
+ })),
405
+ },
406
+ });
407
+ const ok = new Set();
408
+ const failed = [];
409
+ for (const x of r.results ?? []) {
410
+ const src = batch[x.itemMetadata?.originalIndex];
411
+ if (!src) continue;
412
+ if (x.itemMetadata?.success) ok.add(src.id);
413
+ else failed.push({ id: src.id, error: x.itemMetadata?.error?.description ?? x.itemMetadata?.error?.code ?? "unknown" });
414
+ }
415
+ // an input with no result at all did not persist either
416
+ for (const it of batch) if (!ok.has(it.id) && !failed.some((f) => f.id === it.id)) failed.push({ id: it.id, error: "no result for item" });
417
+ return { ok, failed };
418
+ };
419
+ const first = await send(items);
420
+ const attached = new Set(first.ok);
421
+ let failures = first.failed;
422
+ if (failures.length) {
423
+ const retry = await send(items.filter((it) => failures.some((f) => f.id === it.id)));
424
+ for (const id of retry.ok) attached.add(id);
425
+ failures = retry.failed;
426
+ }
427
+ return { attached: [...attached], failures };
417
428
  }
418
429
 
419
430
  // Reject plans the API would reject halfway through, while nothing has been created yet —
@@ -462,22 +473,12 @@ async function setSiteCurrency(ctx, currency) {
462
473
  * threaded in memory. This is the default path — call it once instead of the individual
463
474
  * functions.
464
475
  */
465
- export async function setupStore(ctx, { products = [], categories = {}, currency } = {}, { freshSite = false } = {}) {
476
+ export async function setupStore(ctx, { products = [], categories = {}, currency } = {}) {
466
477
  validateProducts(products);
467
478
  await installStoresApp(ctx);
468
479
  // Before any product exists: a product's price is stored in the site currency at create time,
469
480
  // so switching afterwards leaves the catalog priced in the old one.
470
481
  if (currency) await setSiteCurrency(ctx, currency);
471
- // A just-created site holds only the install's sample products — clear them (never on an
472
- // existing site: the flag is the fast path's, set only when it created the site itself).
473
- let samplesDeleted = 0;
474
- if (freshSite) {
475
- try {
476
- samplesDeleted = await deleteAllProducts(ctx);
477
- } catch (e) {
478
- console.error(`sample cleanup failed (seeding on top): ${String(e.message).slice(0, 120)}`);
479
- }
480
- }
481
482
 
482
483
  // Idempotent by name: an errored bulk create (429/5xx) may still have applied server-side,
483
484
  // and SKILL.md tells the agent to re-run a failed seed — creating only the names that don't
@@ -518,34 +519,40 @@ export async function setupStore(ctx, { products = [], categories = {}, currency
518
519
  const imageItems = withNames
519
520
  .map((p, i) => (files[i] && p.id ? { id: p.id, url: files[i].url, altText: products[i]?.altText ?? p.slug } : null))
520
521
  .filter(Boolean);
522
+ // imagesAttached counts the attaches the API CONFIRMED (per-item results), not the ones sent;
523
+ // imageFailures names the products left text-only and why. Neither blocks the seed: a re-run of
524
+ // the same plan reuses the products and attaches again.
521
525
  let imagesAttached = 0;
526
+ const imageFailures = [];
527
+ const nameOf = (id) => withNames.find((p) => p.id === id)?.name;
522
528
  try {
523
- if (imageItems.length) await attachProductImages(ctx, imageItems);
524
- imagesAttached = imageItems.length;
525
- } catch {
526
- /* never block on image failure — the products stay text-only */
529
+ if (imageItems.length) {
530
+ const r = await attachProductImages(ctx, imageItems);
531
+ imagesAttached = r.attached.length;
532
+ for (const f of r.failures) imageFailures.push({ name: nameOf(f.id), error: f.error });
533
+ }
534
+ } catch (e) {
535
+ for (const it of imageItems) imageFailures.push({ name: nameOf(it.id), error: e?.message ?? String(e) });
527
536
  }
528
537
 
529
538
  // failures is part of the result, not an exception: a partial seed still leaves a usable
530
539
  // store, and the agent needs the names to report rather than silently shipping a short
531
540
  // catalog. Re-run the seed to retry them — existing names are skipped, not duplicated.
532
- return { products: withNames, categories: cats, imagesAttached, samplesDeleted, failures };
541
+ return { products: withNames, categories: cats, imagesAttached, imageFailures, failures };
533
542
  }
534
543
 
535
544
  // ---- CLI entry ----------------------------------------------------------------------------------
536
545
 
537
546
  const invokedDirectly = process.argv[1] && import.meta.url.endsWith(process.argv[1].split("/").pop());
538
547
  if (invokedDirectly) {
539
- const args = process.argv.slice(2);
540
- const freshSite = args.includes("--fresh-site");
541
- const planPath = args.find((a) => !a.startsWith("--"));
548
+ const planPath = process.argv[2];
542
549
  if (!planPath) {
543
- console.error("usage: node seed-store.mjs <plan.json> [--fresh-site] (run from the project root)");
550
+ console.error("usage: node seed-store.mjs <plan.json> (run from the project root)");
544
551
  process.exit(1);
545
552
  }
546
553
  const plan = JSON.parse(readFileSync(planPath, "utf8"));
547
554
  const ctx = makeCtx();
548
- setupStore(ctx, plan, { freshSite })
555
+ setupStore(ctx, plan)
549
556
  .then((result) => console.log(JSON.stringify(result, null, 2)))
550
557
  .catch((e) => {
551
558
  console.error(e.message);
@@ -29,7 +29,7 @@ Set up and tune how a store ships — what rates to charge, which regions are co
29
29
 
30
30
  > - [Set up shipping rates / rules](https://dev.wix.com/docs/api-reference/business-solutions/e-commerce/skills/shipping-set-up-rates) — tags: `[intent:setup-rates]` · priority 0
31
31
  > - [Set up delivery regions / coverage](https://dev.wix.com/docs/api-reference/business-solutions/e-commerce/skills/shipping-set-up-regions) — tags: `[intent:setup-regions]` · priority 0
32
- > - [Set up store pickup / local delivery](https://dev.wix.com/docs/api-reference/business-solutions/e-commerce/skills/local-delivery) — tags: `[intent:setup-pickup]` · priority 0
32
+ > - [Set up store pickup / local delivery](https://dev.wix.com/docs/api-reference/business-solutions/e-commerce/skills/shipping-set-up-pickup-local-delivery) — tags: `[intent:setup-pickup]` · priority 0
33
33
  > - [Add free shipping over $X](https://dev.wix.com/docs/api-reference/business-solutions/e-commerce/skills/shipping-add-free-shipping) — tags: `[intent:free-shipping]` · priority 0
34
34
 
35
35
  ### Optimize & fix
@@ -47,10 +47,7 @@ Before creating a coupon, check for code conflicts and existing promotions on th
47
47
  "code": "SUMMER20",
48
48
  "percentOffRate": 20,
49
49
  "scope": {
50
- "namespace": "stores",
51
- "group": {
52
- "name": "product"
53
- }
50
+ "namespace": "stores"
54
51
  },
55
52
  "startTime": 1717200000000,
56
53
  "expirationTime": 1719792000000,
@@ -91,10 +88,7 @@ Check for: duplicate codes, overlapping scopes with active coupons, and cross-me
91
88
  "code": "SPRING15",
92
89
  "percentOffRate": 15,
93
90
  "scope": {
94
- "namespace": "stores",
95
- "group": {
96
- "name": "product"
97
- }
91
+ "namespace": "stores"
98
92
  },
99
93
  "startTime": 1714521600000,
100
94
  "usageLimit": 200,
@@ -167,10 +161,7 @@ Check for: duplicate codes, overlapping scopes with active coupons, and cross-me
167
161
  "code": "SAVE10",
168
162
  "moneyOffAmount": 10,
169
163
  "scope": {
170
- "namespace": "stores",
171
- "group": {
172
- "name": "product"
173
- }
164
+ "namespace": "stores"
174
165
  },
175
166
  "startTime": 1714521600000,
176
167
  "active": true
@@ -230,11 +221,11 @@ Instead of targeting a scope, you can require a minimum cart subtotal. This is a
230
221
 
231
222
  ## Scope values for Wix Stores
232
223
 
233
- | Scope target | `namespace` | `group.name` | `group.entityId` |
234
- |---|---|---|---|
235
- | All store products | `"stores"` | `"product"` | Omit (applies to all) |
236
- | Specific product | `"stores"` | `"product"` | Product UUID |
237
- | Specific collection | `"stores"` | `"collection"` | Collection UUID |
224
+ | Scope target | `namespace` | `group` |
225
+ |---|---|---|
226
+ | All store products | `"stores"` | Omit the `group` field entirely — a present-but-empty `group: {}` is rejected the same as a populated one missing `entityId` |
227
+ | Specific product | `"stores"` | `{ "name": "product", "entityId": "<product UUID>" }` |
228
+ | Specific collection | `"stores"` | `{ "name": "collection", "entityId": "<collection UUID>" }` |
238
229
 
239
230
  ---
240
231
 
@@ -246,7 +237,7 @@ When the recommendation output has `mechanism: "COUPON"`, use this mapping to co
246
237
 
247
238
  | Recommendation `scope` | Coupon `scope` |
248
239
  |---|---|
249
- | `SITE` | `{ "namespace": "stores", "group": { "name": "product" } }` (all products, no entityId) |
240
+ | `SITE` | `{ "namespace": "stores" }` (all products — omit `group` entirely) |
250
241
  | `CATEGORY` | `{ "namespace": "stores", "group": { "name": "collection", "entityId": "<first categoryId>" } }` |
251
242
  | `ITEMS` | `{ "namespace": "stores", "group": { "name": "product", "entityId": "<first productId>" } }` |
252
243
 
@@ -340,7 +331,7 @@ When the recommendation output has `mechanism: "COUPON"`, use this mapping to co
340
331
 
341
332
  | Error | Cause | Fix |
342
333
  |---|---|---|
343
- | `"When scope or minimumSubtotal is not used - only FreeShipping coupon is allowed"` | Coupon sent without `scope` or `minimumSubtotal` | Add `scope: { "namespace": "stores", "group": { "name": "product" } }` for site-wide, or set `minimumSubtotal` |
334
+ | `"When scope or minimumSubtotal is not used - only FreeShipping coupon is allowed"` | Coupon sent without `scope` or `minimumSubtotal` | Add `scope: { "namespace": "stores" }` for site-wide (omit `group` — do not send `group: {}`, which is rejected identically), or set `minimumSubtotal` |
344
335
  | Duplicate code | Another coupon uses the same code | Generate a different code |
345
336
  | Invalid startTime | Value too low (must be epoch ms, not seconds) | Multiply by 1000 if in seconds |
346
337
  | Both scope and minimumSubtotal set | These are oneOf — cannot use both | Choose scope OR minimumSubtotal |
@@ -200,7 +200,11 @@ The response is the definition under `ticketDefinition`:
200
200
  Keep `revision` — `PATCH /events/v3/ticket-definitions/{id}` requires the current value, and it
201
201
  increments on every update.
202
202
 
203
- - **`feeType` is required** — `FEE_ADDED_AT_CHECKOUT` or `FEE_INCLUDED`.
203
+ - **`feeType` is required.** A free ticket (`fixedPrice` of `"0"`) takes `NO_FEE`. A paid ticket
204
+ takes `FEE_ADDED_AT_CHECKOUT` (the guest pays the service fee) unless the user asked to absorb it,
205
+ then `FEE_INCLUDED`. `NO_FEE` on a paid ticket is accepted only on sites that do not collect ticket
206
+ fees. If a paid ticket fails with `400 INVALID_FEE_TYPE`, the site is one that does not collect
207
+ ticket fees: retry that ticket once with `NO_FEE`.
204
208
  - **`value` is a string.** `"value": 10` fails `400 Unexpected value for field value`.
205
209
  - **No writable `free` flag** — `pricingMethod.free` is read-only; a free ticket is a `fixedPrice`
206
210
  of `"0"`.
@@ -235,24 +235,6 @@ export default function ProductDetail() {
235
235
  - Render the PDP gallery from `images` — every image reachable (thumbnails, arrows, or a swipeable rail), not just the first; a single-image product gets no empty strip.
236
236
  - `submit()` resets `adding` after completion and preserves the cart result: `undefined` on success, `null` on failure. Add failures live in `useCart().error`, not the PDP load `error`; the shipped drawer opens to display them.
237
237
 
238
- For an optional **add and check out** shortcut, check the add result before checkout:
239
- ```jsx
240
- // Inside ProductDetail, with the other hooks above any conditional returns:
241
- const { checkout, loading: cartLoading } = useCart(); // named import from @/context/CartContext
242
- async function addAndCheckout() {
243
- if (!d.product || !d.canAdd || d.adding || cartLoading) return;
244
- const result = await d.submit();
245
- if (result === null) return; // add failed; preserve its error and do not check out the old cart
246
- await checkout();
247
- }
248
- // <button disabled={!d.canAdd || d.adding || cartLoading} onClick={addAndCheckout}>Add and check out</button>
249
- ```
250
- This adds to the shopper's **current cart** and checks that cart out — so label it that way. A true
251
- **Buy Now** (skip the cart, buy just this item) needs a standalone cart handed to the redirect session;
252
- it is not shipped, and routing "Buy now" through the current cart is wrong (it would carry whatever the
253
- cart already holds). For direct `addToCart(...)` calls, use the same `result === null` check before checkout.
254
- A resolved promise alone does not mean success; a truthiness check also rejects successful `undefined`.
255
-
256
238
  ### Variant and modifier controls
257
239
  The product-detail example above provides both groups:
258
240
  ```js
@@ -475,28 +457,6 @@ Path params are `$name` in both the filename and the route path; `useParams()` f
475
457
  reads them unchanged. Full pattern, including `ssr: false` for per-user routes:
476
458
  [`../_shared/routing.md`](../_shared/routing.md).
477
459
 
478
- ## What a complete storefront shows
479
-
480
- The wiring above is necessary, not sufficient. These are defaults for when the brief doesn't say
481
- otherwise — whatever the user asked for in their prompt wins over any line here. Look at the
482
- catalog before designing — categories, assortment size, media, options, sales — and design for this
483
- store, not for a stereotype of its category. Then:
484
-
485
- - **Home:** what the store sells and one shopping action in the first screen; real products from
486
- the catalog under truthful headings; not a repeat of the shop page.
487
- - **Shop:** a real product card — image, name, price, link — in the first screen; sort and the
488
- filters the catalog supports; loading, empty, no-results, and error states that look different.
489
- - **Product page:** image, name, price, the first choice, and the buy button with `blockedReason`
490
- in the first screen; every ribbon; every image reachable in the gallery.
491
- - **Cart:** the shipped drawer — it opens after every add, and checkout is a button in it.
492
- - **Overlays you build** (quick-add, mobile nav, filters): mount at the document root, lock
493
- background scroll, close on Escape, return focus on close — as the shipped `CartDrawer` does.
494
- - **Copy:** nothing the merchant didn't supply — no invented reviews, scarcity, or delivery
495
- promises; no Wix IDs or technical words in visible text.
496
-
497
- Pre-order ships (`isPreorder`). Subscriptions, product groups, promotions, and notify-me are built
498
- only when the catalog has them — never fabricated; consult the documentation skill for their endpoints.
499
-
500
460
  ## Missing capabilities
501
461
  For anything these interfaces do not cover, consult the official Wix API documentation using
502
462
  the documentation skill available in your environment.
@@ -41,6 +41,9 @@ const result = await seed.setupStore(ctx, {
41
41
  // currency: { requested, actual, status, warnings } }
42
42
  ```
43
43
 
44
+ A product `name` is at most **80 characters** — Wix rejects the whole batch over that, so keep
45
+ names short and put the detail in `description`.
46
+
44
47
  The optional `currency` sets the site's payment currency before product creation. Pass it only when
45
48
  the user explicitly asked for a currency, or when it's obvious for the store — otherwise omit it. Do
46
49
  not infer a currency from the builder's country/region or the brief's language; when in doubt, leave
@@ -174,6 +174,12 @@ function buildOptions(options = []) {
174
174
  function validateProducts(products) {
175
175
  const seen = new Map();
176
176
  for (const product of products) {
177
+ // Wix caps a product name at 80 characters and the bulk create rejects the WHOLE batch over it
178
+ // ("name has size 175, expected 80 or less"), so the 81st character costs the entire seed.
179
+ if (typeof product.name === "string" && product.name.length > 80) {
180
+ throw new Error(`Product "${product.name.slice(0, 48)}…": the name is ${product.name.length} characters and Wix allows 80. ` +
181
+ `Shorten it and move the detail into description. No products were created by this call.`);
182
+ }
177
183
  if (product.inStock !== undefined && typeof product.inStock !== "boolean") {
178
184
  throw new Error(`Product "${product.name}": inStock must be a boolean. No products were created by this call.`);
179
185
  }
@@ -1,186 +0,0 @@
1
- // Fast path for a managed CREATE run — one deterministic call from "plan exists" to
2
- // "brand layer can start". Composes the pieces that also remain individually runnable
3
- // (deploy.mjs, the vertical's seed module); use those directly to recover a failed step,
4
- // or for connect/iterate runs (which must NOT scaffold and don't use this script).
5
- //
6
- // node <SKILL_ROOT>/install/fast-path.mjs --business-name "<Brand>" --plan plan.json \
7
- // --vertical <storefront|bookings|…> [--stack astro] [--folder-name <npm-safe-name>] [--flatten]
8
- //
9
- // --flatten (opt-in): leave the project directly in the current directory instead of a subfolder,
10
- // moving it before the background install starts. Default off — the normal output is a subfolder.
11
- //
12
- // It emits ONE JSON event per line and exits in ~35s with BOTH long steps — the dependency
13
- // install AND the seed — running detached in the background (logs + completion markers
14
- // reported in the final event), so the caller can build the brand layer while they finish.
15
- // Steps: scaffold (Wix CLI; requires a logged-in session) → deploy shipped code + deps +
16
- // lockfile → pin AGENTS.md → start `npm ci || npm install` detached → start the seed detached.
17
- import { spawn, spawnSync } from "node:child_process";
18
- import { existsSync, openSync, readFileSync, readdirSync, renameSync, rmSync } from "node:fs";
19
- import { dirname, join, resolve } from "node:path";
20
- import { fileURLToPath } from "node:url";
21
-
22
- const SKILL_ROOT = resolve(dirname(fileURLToPath(import.meta.url)), "..");
23
-
24
- const emit = (event, extra = {}) => console.log(JSON.stringify({ event, ...extra }));
25
- const fail = (step, detail) => {
26
- emit("error", { step, detail: String(detail).slice(0, 600) });
27
- process.exit(1);
28
- };
29
-
30
- // ---- args ---------------------------------------------------------------------------------------
31
- const argv = process.argv.slice(2);
32
- const flag = (name) => {
33
- const i = argv.indexOf(`--${name}`);
34
- return i !== -1 && argv[i + 1] && !argv[i + 1].startsWith("--") ? argv[i + 1] : null;
35
- };
36
- const businessName = flag("business-name");
37
- const planPath = flag("plan");
38
- const vertical = flag("vertical");
39
- const stack = flag("stack") ?? "astro";
40
- // Opt-in: leave the project in the current directory (flat) instead of a subfolder.
41
- const flatten = argv.includes("--flatten");
42
- // --vertical is REQUIRED: a defaulted vertical deploys the wrong code and runs the wrong
43
- // seed against the plan — fail loudly with the discovered choices instead.
44
- const knownVerticals = readdirSync(join(SKILL_ROOT, "references"), { withFileTypes: true })
45
- .filter((d) => d.isDirectory() && d.name !== "shared" && existsSync(join(SKILL_ROOT, "references", d.name, "app")))
46
- .map((d) => d.name);
47
- if (!businessName || !planPath || !vertical) {
48
- fail("args", `usage: fast-path.mjs --business-name "<Brand>" --plan plan.json --vertical <${knownVerticals.join("|")}> [--stack astro]`);
49
- }
50
- if (!knownVerticals.includes(vertical)) {
51
- fail("args", `unknown vertical "${vertical}" — shipped verticals: ${knownVerticals.join(", ")}`);
52
- }
53
- if (!existsSync(planPath)) fail("args", `plan file not found: ${planPath}`);
54
- const plan = JSON.parse(readFileSync(planPath, "utf8"));
55
-
56
- const folderName =
57
- flag("folder-name") ??
58
- businessName.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 40);
59
- // `let`: after deploy we flatten the scaffold up into the repo root and repoint
60
- // projectDir there, so the detached install/seed and every reported path use the
61
- // final location.
62
- let projectDir = resolve(process.cwd(), folderName);
63
-
64
- // ---- 1 · scaffold -------------------------------------------------------------------------------
65
- if (existsSync(join(process.cwd(), "wix.config.json"))) {
66
- fail("scaffold", "the current directory is already a Wix project — this script is for CREATE runs only; use deploy.mjs + the seed module directly");
67
- }
68
- if (existsSync(join(projectDir, "wix.config.json"))) {
69
- emit("scaffold_skipped", { reason: "project already exists", folder: folderName });
70
- } else {
71
- emit("scaffolding", { folder: folderName });
72
- const scaffold = spawnSync(
73
- "npm",
74
- // --skip-git: this wrapper composes its own steps and leaves version control to
75
- // the caller / the enclosing repo; the scaffold's own `git init` + "Initial
76
- // commit" is noise here, and becomes a nested-repo (submodule gitlink) hazard
77
- // if the project is later placed inside an existing repo. --skip-install for the
78
- // same reason: deps install in a detached step below.
79
- ["create", "@wix/new@latest", "--", "headless",
80
- "--folder-name", folderName, "--business-name", businessName,
81
- "--site-template", "--skip-install", "--skip-git", "--no-publish"],
82
- { env: { ...process.env, CI: "1" }, encoding: "utf8", timeout: 300_000 },
83
- );
84
- if (scaffold.status !== 0 || !existsSync(join(projectDir, "wix.config.json"))) {
85
- fail("scaffold", (scaffold.stderr || scaffold.stdout || "scaffold produced no wix.config.json — is the Wix CLI logged in? (npx @wix/cli@latest whoami)").slice(-600));
86
- }
87
- }
88
- const wixConfig = JSON.parse(readFileSync(join(projectDir, "wix.config.json"), "utf8"));
89
- const siteId = wixConfig.siteId ?? wixConfig.projectId;
90
- emit("scaffolded", { folder: folderName, siteId });
91
-
92
- // ---- 2 · deploy shipped code + deps + lockfile ---------------------------------------------------
93
- const deploy = spawnSync(
94
- "node",
95
- [
96
- join(SKILL_ROOT, "install", "deploy.mjs"),
97
- vertical,
98
- "--stack",
99
- stack,
100
- "--plan",
101
- resolve(planPath),
102
- ],
103
- { cwd: projectDir, encoding: "utf8", timeout: 60_000 },
104
- );
105
- if (deploy.status !== 0) fail("deploy", deploy.stderr || deploy.stdout);
106
- let deployResult = {};
107
- try { deployResult = JSON.parse(deploy.stdout); } catch { /* keep going with raw output below */ }
108
- if (deployResult.error) fail("deploy", deployResult.error);
109
- emit("deployed", deployResult);
110
-
111
- // ---- 2b · record what this project is, for later sessions ---------------------------------------
112
- const pin = spawnSync(
113
- "node",
114
- [join(SKILL_ROOT, "install", "pin-agents-md.mjs"), "--vertical", vertical, "--stack", stack],
115
- { cwd: projectDir, encoding: "utf8", timeout: 10_000 },
116
- );
117
- try { emit("agents_md", JSON.parse(pin.stdout)); } catch { /* never block the build on the note */ }
118
-
119
- // ---- 2c · optional --flatten: move the scaffold into the current directory ----------------------
120
- // OFF by default — the normal output is a self-contained subfolder, unchanged. Opt in when the
121
- // caller wants the project directly in the current directory (e.g. bootstrapping into an existing
122
- // repo that must stay one flat tree). Done HERE, before the detached install below, on purpose:
123
- // no node_modules exists yet, so the move is instant and cannot collide with a running install —
124
- // the failure mode when a project is flattened by hand after the background install has started.
125
- // A pure move: the scaffold was created with --skip-git (above), so there is no nested repo to
126
- // reconcile — git is whatever the destination already is.
127
- const targetDir = process.cwd();
128
- if (flatten && projectDir !== targetDir) {
129
- try {
130
- for (const entry of readdirSync(projectDir)) {
131
- renameSync(join(projectDir, entry), join(targetDir, entry));
132
- }
133
- rmSync(projectDir, { recursive: true, force: true });
134
- projectDir = targetDir;
135
- emit("flattened", { into: targetDir });
136
- } catch (e) {
137
- fail("flatten", e?.stack || e);
138
- }
139
- }
140
-
141
- // ---- 3 · start the dependency install, detached --------------------------------------------------
142
- const installLog = join(projectDir, "npm-install.log");
143
- const logFd = openSync(installLog, "a");
144
- const install = spawn("sh", ["-c", "npm ci --ignore-scripts || npm install --ignore-scripts"], {
145
- cwd: projectDir,
146
- detached: true,
147
- stdio: ["ignore", logFd, logFd],
148
- });
149
- install.unref();
150
- emit("install_started", { log: installLog, doneMarker: "node_modules/.package-lock.json" });
151
-
152
- // ---- 4 · start the seed, detached ----------------------------------------------------------------
153
- // The seed includes a Wix-side provisioning wait of unpredictable length (10-80s); running it
154
- // in the caller's foreground would idle the agent for exactly that long. Detach it like the
155
- // install: result JSON + exit-code marker land as files the caller syncs on before release.
156
- const seedDir = join(SKILL_ROOT, "references", vertical, "seed");
157
- const seedName = existsSync(seedDir)
158
- ? readdirSync(seedDir).find((f) => f.startsWith("seed-") && f.endsWith(".mjs"))
159
- : undefined;
160
- const seedFile = seedName ? join(seedDir, seedName) : null;
161
- if (!seedFile) fail("seed", `no seed module found under ${seedDir}`);
162
- const seedResultFile = join(projectDir, "seed-result.json");
163
- const seedLog = join(projectDir, "seed.log");
164
- const seedDoneMarker = join(projectDir, ".seed-exit");
165
- const planAbs = resolve(planPath);
166
- const seedChild = spawn(
167
- "sh",
168
- // --fresh-site: this script created the site moments ago, so the only products in it are the
169
- // Stores install's samples — the seed clears them first (a seed run by hand never deletes).
170
- ["-c", `node "${seedFile}" "${planAbs}" --fresh-site > seed-result.json 2> seed.log; echo $? > .seed-exit`],
171
- { cwd: projectDir, detached: true, stdio: "ignore" },
172
- );
173
- seedChild.unref();
174
- emit("seeding_started", { vertical, resultFile: seedResultFile, log: seedLog, doneMarker: seedDoneMarker });
175
-
176
- // ---- done ----------------------------------------------------------------------------------------
177
- emit("ready_for_brand_layer", {
178
- projectDir,
179
- siteId,
180
- dashboardUrl: deployResult.dashboardUrl,
181
- productsUrl: deployResult.productsUrl,
182
- categoriesUrl: deployResult.categoriesUrl,
183
- install: { log: installLog, doneMarker: "node_modules/.package-lock.json" },
184
- seed: { resultFile: "seed-result.json", log: "seed.log", doneMarker: ".seed-exit", success: "file contains 0" },
185
- next: "theme SiteLayout + write the home page; then wait for BOTH done markers, verify .seed-exit is 0 (else read seed.log and re-run the seed module), build, release",
186
- });
@@ -1,57 +0,0 @@
1
- // Record what this project is in its agent instruction files, so a later session — which has
2
- // none of the build conversation and may never open SKILL.md — still knows the Wix site is the
3
- // source of truth and which skill answers which kind of question.
4
- //
5
- // node <SKILL_ROOT>/install/pin-agents-md.mjs --vertical <name> [--stack astro]
6
- //
7
- // Run from the project root. Kept out of deploy.mjs on purpose: "copy a vertical's files" and
8
- // "record the project's ground rules" are separate concerns with separate reasons to change.
9
- // APPENDS to each file — a template's or the user's own content is never overwritten — and is
10
- // idempotent via the heading sentinel, so re-running fast-path.mjs writes at most once.
11
- // Project facts that live in the repo (site id, app id) are NOT copied here; they would go
12
- // stale against wix.config.json, which is the one place that owns them.
13
- import { appendFileSync, existsSync, readFileSync } from "node:fs";
14
- import { join } from "node:path";
15
-
16
- const argv = process.argv.slice(2);
17
- const flag = (n, d) => { const i = argv.indexOf(`--${n}`); return i >= 0 ? argv[i + 1] : d; };
18
-
19
- const vertical = flag("vertical");
20
- const stack = flag("stack", "astro");
21
- // "astro" means the Wix-managed flavour (ambient auth), which is worth naming. Any other stack
22
- // is echoed as given rather than mapped, so adding one can't silently mislabel the project.
23
- const frontend = stack === "astro" ? "Wix-managed Astro" : stack.charAt(0).toUpperCase() + stack.slice(1);
24
-
25
- const SENTINEL = "## This app — a Wix Headless frontend";
26
- const note = `
27
- ${SENTINEL}
28
-
29
- A ${frontend} frontend for a live Wix site; \`wix.config.json\` identifies the site. Built on
30
- the **${vertical}** Wix business solution — more can be added to this same app. **The Wix site
31
- owns the content and commerce** — read and write it through the Wix APIs, never hardcode what
32
- it holds.
33
-
34
- The Wix skills are installed at \`.agents/skills/\` — read them from that exact path:
35
-
36
- - **\`wix-headless-fast\`** — the code already deployed in \`src/\` and how to extend it. Every
37
- business solution it ships sits under \`references/<solution>/\`: \`INSTRUCTIONS.md\` is that
38
- solution's playbook, \`seed/\` creates its content. To add one to this app, run from the
39
- project root:
40
- \`node .agents/skills/wix-headless-fast/install/deploy.mjs <solution> --stack ${stack}\`
41
- - **\`wix-docs\`** — the Wix API reference. Confirm any endpoint, request shape, field, or enum
42
- here before writing code against it, frontend or backend. Never infer a contract from
43
- generated SDK types or \`node_modules\`.
44
- - **\`wix-manage\`** — recipes for managing the live site itself, as opposed to changing this
45
- codebase. No recipe for the task? Fall back to \`wix-docs\`.
46
- `;
47
-
48
- // Both files, independently — a project may have either, both, or neither, and agents differ
49
- // in which one they read.
50
- const pinned = ["AGENTS.md", "CLAUDE.md"].map((name) => {
51
- const file = join(process.cwd(), name);
52
- const existing = existsSync(file) ? readFileSync(file, "utf8") : "";
53
- const wrote = !existing.includes(SENTINEL);
54
- if (wrote) appendFileSync(file, (existing && !existing.endsWith("\n") ? "\n" : "") + note);
55
- return { file: name, wrote, created: wrote && !existing };
56
- });
57
- console.log(JSON.stringify({ event: "agents_md", pinned }));