@wix/agent-skills 1.7.0 → 1.9.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 (126) hide show
  1. package/README.md +3 -7
  2. package/package.json +1 -1
  3. package/skills/wix-app/SKILL.md +2 -0
  4. package/skills/wix-app/references/EDITOR_REACT_COMPONENT.md +2 -1
  5. package/skills/wix-app/references/STORES_VERSIONING.md +1 -0
  6. package/skills/wix-app/references/editor-react-component/ACCESSIBILITY.md +14 -0
  7. package/skills/wix-app/references/editor-react-component/REACT-GUIDELINES.md +11 -6
  8. package/skills/wix-app/references/editor-react-component/REACT-PATTERNS.md +3 -17
  9. package/skills/wix-app/references/editor-react-component/SSR.md +119 -0
  10. package/skills/wix-design-system/SKILL.md +5 -1
  11. package/skills/wix-headless/SKILL.md +55 -32
  12. package/skills/wix-headless/references/BUILD-astro.md +244 -0
  13. package/skills/wix-headless/references/BUILD-own-build.md +167 -0
  14. package/skills/wix-headless/references/BUILD.md +50 -252
  15. package/skills/wix-headless/references/DESIGN_SYSTEM.md +94 -34
  16. package/skills/wix-headless/references/DISCOVERY-connect.md +55 -0
  17. package/skills/wix-headless/references/DISCOVERY-create.md +238 -0
  18. package/skills/wix-headless/references/DISCOVERY.md +41 -422
  19. package/skills/wix-headless/references/PLAN-connect.md +19 -0
  20. package/skills/wix-headless/references/PLAN-create.md +17 -0
  21. package/skills/wix-headless/references/PLAN.md +37 -27
  22. package/skills/wix-headless/references/SEED.md +27 -18
  23. package/skills/wix-headless/references/SETUP.md +32 -213
  24. package/skills/wix-headless/references/astro/blog/BLOG_PAGES.md +5 -4
  25. package/skills/wix-headless/references/astro/bookings/COMPONENTS.md +45 -0
  26. package/skills/wix-headless/references/astro/bookings/SERVICES_PAGES.md +58 -0
  27. package/skills/wix-headless/references/astro/cms/CMS_FOUNDATIONS.md +5 -5
  28. package/skills/wix-headless/references/astro/cms/FAQ_KNOWLEDGE_BASE.md +10 -10
  29. package/skills/wix-headless/references/astro/cms/PORTFOLIO.md +12 -13
  30. package/skills/wix-headless/references/astro/cms/RESOURCE_LIBRARY.md +10 -12
  31. package/skills/wix-headless/references/astro/cms/TEAM_DIRECTORY.md +8 -8
  32. package/skills/wix-headless/references/astro/designer/INSTRUCTIONS.md +47 -27
  33. package/skills/wix-headless/references/astro/ecom/CART_PAGES.md +7 -8
  34. package/skills/wix-headless/references/astro/ecom/CART_WIRING.md +5 -5
  35. package/skills/wix-headless/references/astro/ecom/COMPONENTS_CSS.md +3 -3
  36. package/skills/wix-headless/references/astro/forms/CONTACT_FORM.md +5 -19
  37. package/skills/wix-headless/references/astro/gift-cards/COMPONENTS.md +2 -2
  38. package/skills/wix-headless/references/astro/gift-cards/PAGES.md +1 -1
  39. package/skills/wix-headless/references/astro/stores/BACK_IN_STOCK.md +6 -6
  40. package/skills/wix-headless/references/astro/stores/CATEGORY_PAGES.md +4 -4
  41. package/skills/wix-headless/references/astro/stores/COMPONENTS_CSS.md +3 -3
  42. package/skills/wix-headless/references/astro/stores/HOME_AND_NAV.md +3 -3
  43. package/skills/wix-headless/references/astro/stores/PRODUCT_PAGES.md +9 -9
  44. package/skills/wix-headless/references/astro/stores/SHARED_WIRING.md +5 -4
  45. package/skills/wix-headless/references/astro/templates/Footer.astro +1 -1
  46. package/skills/wix-headless/references/astro/templates/Layout.astro +1 -1
  47. package/skills/wix-headless/references/astro/templates/Navigation.astro +1 -1
  48. package/skills/wix-headless/references/astro/templates/astro.config.mjs +1 -1
  49. package/skills/wix-headless/references/astro/templates/bookings/AvailabilityCalendar.tsx +233 -0
  50. package/skills/wix-headless/references/astro/templates/bookings/BookingForm.tsx +136 -0
  51. package/skills/wix-headless/references/astro/templates/bookings/SeoTags.astro +25 -0
  52. package/skills/wix-headless/references/astro/templates/bookings/ServiceBookingFlow.tsx +54 -0
  53. package/skills/wix-headless/references/astro/templates/bookings/ServiceCard.astro +45 -0
  54. package/skills/wix-headless/references/astro/templates/bookings/booking-confirmation.astro +49 -0
  55. package/skills/wix-headless/references/astro/templates/bookings/bookingDriver.ts +245 -0
  56. package/skills/wix-headless/references/astro/templates/bookings/components-bookings.css +356 -0
  57. package/skills/wix-headless/references/astro/templates/bookings/services/[slug].astro +133 -0
  58. package/skills/wix-headless/references/astro/templates/bookings/services/index.astro +73 -0
  59. package/skills/wix-headless/references/astro/templates/global.css +2 -2
  60. package/skills/wix-headless/references/astro/templates/index.astro +1 -1
  61. package/skills/wix-headless/references/blog/BLOG_CONTENT.md +19 -9
  62. package/skills/wix-headless/references/blog/INSTRUCTIONS.md +3 -3
  63. package/skills/wix-headless/references/bookings/FLOW.md +185 -0
  64. package/skills/wix-headless/references/bookings/INSTRUCTIONS.md +90 -0
  65. package/skills/wix-headless/references/bookings/SERVICES_DATA.md +295 -0
  66. package/skills/wix-headless/references/cms/CMS_FOUNDATIONS.md +4 -2
  67. package/skills/wix-headless/references/cms/INSTRUCTIONS.md +27 -1
  68. package/skills/wix-headless/references/commands/known-apps.json +2 -1
  69. package/skills/wix-headless/references/custom/CONNECTION_PLAN.md +142 -0
  70. package/skills/wix-headless/references/custom/INSTRUCTIONS.md +71 -21
  71. package/skills/wix-headless/references/custom/blog/WIRING.md +52 -0
  72. package/skills/wix-headless/references/custom/bookings/WIRING.md +146 -0
  73. package/skills/wix-headless/references/custom/cms/WIRING.md +97 -0
  74. package/skills/wix-headless/references/custom/ecom/WIRING.md +67 -0
  75. package/skills/wix-headless/references/custom/forms/WIRING.md +101 -0
  76. package/skills/wix-headless/references/custom/stores/WIRING.md +80 -0
  77. package/skills/wix-headless/references/ecom/INSTRUCTIONS.md +5 -5
  78. package/skills/wix-headless/references/forms/INSTRUCTIONS.md +2 -2
  79. package/skills/wix-headless/references/gift-cards/INSTRUCTIONS.md +3 -3
  80. package/skills/wix-headless/references/images/INSTRUCTIONS.md +16 -15
  81. package/skills/wix-headless/references/seed-recipes.md +2 -2
  82. package/skills/wix-headless/references/shared/AGENTS_MD.md +47 -0
  83. package/skills/wix-headless/references/shared/AUTHENTICATION.md +3 -5
  84. package/skills/wix-headless/references/shared/DESIGN_MD.md +85 -0
  85. package/skills/wix-headless/references/shared/IMAGE_GENERATION.md +29 -28
  86. package/skills/wix-headless/references/shared/IMPLEMENTER.md +87 -27
  87. package/skills/wix-headless/references/shared/PRODUCTION_SHARP_EDGES.md +2 -2
  88. package/skills/wix-headless/references/shared/RETURN_CONTRACT.md +24 -313
  89. package/skills/wix-headless/references/shared/STYLING.md +8 -18
  90. package/skills/wix-headless/references/stores/INSTRUCTIONS.md +39 -9
  91. package/skills/wix-headless/references/stores/PRODUCT_CATALOG_DATA.md +17 -14
  92. package/skills/wix-headless/references/verticals/_schema.json +1 -1
  93. package/skills/wix-headless/references/verticals/_schema.md +3 -3
  94. package/skills/wix-headless/references/verticals/blog.md +1 -1
  95. package/skills/wix-headless/references/verticals/bookings.md +39 -0
  96. package/skills/wix-headless/references/verticals/cms.md +1 -1
  97. package/skills/wix-headless/references/verticals/ecom.md +2 -2
  98. package/skills/wix-headless/references/verticals/gift-cards.md +1 -1
  99. package/skills/wix-headless/references/verticals/stores.md +1 -1
  100. package/skills/wix-headless/scripts/check-manifest.mjs +143 -6
  101. package/skills/wix-headless/scripts/compose.mjs +540 -0
  102. package/skills/wix-headless/scripts/emit-design-tokens.mjs +128 -51
  103. package/skills/wix-headless/scripts/flatten.sh +61 -0
  104. package/skills/wix-headless/scripts/generate-images.mjs +242 -0
  105. package/skills/wix-headless/scripts/scaffold.sh +47 -16
  106. package/skills/wix-headless/scripts/write-decorative-json.mjs +62 -0
  107. package/skills/wix-manage/SKILL.md +13 -1
  108. package/skills/wix-manage/references/app-installation/install-wix-apps.md +3 -27
  109. package/skills/wix-manage/references/blog/how-to-create-blog-posts.md +1 -1
  110. package/skills/wix-manage/references/bookings/create-appointment-service.md +266 -0
  111. package/skills/wix-manage/references/bookings/create-booking-service-from-prompt.md +37 -0
  112. package/skills/wix-manage/references/bookings/create-class-service.md +245 -0
  113. package/skills/wix-manage/references/bookings/create-course-service.md +249 -0
  114. package/skills/wix-manage/references/cms/cms-data-items-crud.md +3 -2
  115. package/skills/wix-manage/references/cms/cms-references-and-relationships.md +1 -1
  116. package/skills/wix-manage/references/cms/cms-schema-management.md +2 -2
  117. package/skills/wix-manage/references/domains/domain-search-and-purchase.md +10 -7
  118. package/skills/wix-manage/references/forms/create-form.md +49 -1
  119. package/skills/wix-manage/references/stores/bulk-create-products-with-options.md +1 -1
  120. package/skills/wix-manage/references/stores/create-product-from-image.md +154 -2
  121. package/skills/wix-manage/references/stores/setup-online-store-catalog-v3.md +1 -1
  122. package/skills/wix-headless/references/astro/COMPOSE.md +0 -142
  123. package/skills/wix-headless/scripts/finalize-run-json.mjs +0 -141
  124. package/skills/wix-headless/scripts/init-site-json.mjs +0 -101
  125. package/skills/wix-headless/scripts/preview.sh +0 -45
  126. package/skills/wix-headless/scripts/release.sh +0 -73
@@ -1,15 +1,17 @@
1
1
  # Phase 3 Components — Back in Stock (Stores)
2
2
 
3
- Split across the stores `components` scope (TSX/util files) and the `components-css` sibling (CSS rules). The matching Phase 4 wiring lives in `PRODUCT_PAGES.md` (SSR probe import + new props on `<ProductPurchase>`).
3
+ The stores `components` scope writes the TSX/util files; the CSS rules ship in the **pre-copied** `components-stores.css` template (no agent authors them). The matching page wiring lives in `PRODUCT_PAGES.md` (SSR probe import + new props on `<ProductPurchase>`). Both the components and that page wiring run inside the **same stores merged build agent** (the build wave), components first.
4
4
 
5
5
  ## Scope
6
6
 
7
7
  Files written for back-in-stock, by scope:
8
8
 
9
9
  **`components` scope** (see `./SHARED_WIRING.md`):
10
- - `src/utils/back-in-stock.ts` — SSR-elevated probe of the Wix back-in-stock service, plus the canonical Stores app id constant
11
10
  - `src/components/BackInStockForm.tsx` — React island that posts via `@wix/ecom`'s `backInStockNotifications.createBackInStockNotificationRequest`
12
11
 
12
+ **Pre-copied by the orchestrator** (do NOT author — same treatment as `categories.ts`):
13
+ - `src/utils/back-in-stock.ts` — SSR-elevated probe of the Wix back-in-stock service, plus the canonical Stores app id constant. Pre-copied into the project in the build-wave pre-batch (BUILD-astro.md § "Step 4.5"). **Import** `getBackInStockEnabled`/the app-id constants from `../utils/back-in-stock`; never `Write` it yourself (racing the pre-copy trips the harness staleness guard).
14
+
13
15
  **`components-css` scope** (see `./COMPONENTS_CSS.md`):
14
16
  - `src/styles/components-stores.css` — appends the back-in-stock form CSS rules at the end of the file (see § 3 below)
15
17
 
@@ -45,9 +47,9 @@ This scope uses **template files** instead of inline code. For each file below:
45
47
 
46
48
  Do NOT modify logic, imports, the bare-fields request shape, or the app-id constants.
47
49
 
48
- ### 1. `src/utils/back-in-stock.ts`
50
+ ### 1. `src/utils/back-in-stock.ts` — pre-copied, not owned by this scope
49
51
 
50
- Use template `templates/back-in-stock.ts`.
52
+ > Pre-copied by the orchestrator in the build-wave pre-batch (BUILD-astro.md § "Step 4.5") — same treatment as `categories.ts`. **Import** from `../utils/back-in-stock`; do NOT write it yourself. The exports below are documented here so callers (the form island, the `[slug].astro` probe) know the surface.
51
53
 
52
54
  Exports:
53
55
  - `WIX_STORES_BACK_IN_STOCK_APP_ID` — string constant. Use this for the `catalogReference.appId` in the form.
@@ -150,7 +152,6 @@ The full components scope return must mention back-in-stock:
150
152
  "summary": "Wrote stores islands, scoped CSS, back-in-stock probe + form",
151
153
  "data": {
152
154
  "islands": ["ProductPurchase.tsx", "AddToCartButton.tsx", "BackInStockForm.tsx"],
153
- "utils": ["back-in-stock.ts"],
154
155
  "scopedCssFile": "src/styles/components-stores.css",
155
156
  "backInStockWired": true
156
157
  },
@@ -159,7 +160,6 @@ The full components scope return must mention back-in-stock:
159
160
  "src/components/AddToCartButton.tsx",
160
161
  "src/components/ProductPurchase.tsx",
161
162
  "src/components/BackInStockForm.tsx",
162
- "src/utils/back-in-stock.ts",
163
163
  "src/styles/components-stores.css"
164
164
  ],
165
165
  "errors": []
@@ -1,8 +1,8 @@
1
1
  # Phase 4 Category Pages — Stores
2
2
 
3
- Scope: `pages-categories`. Launched in **Step 7** alongside `pages-products` and `pages-home-and-nav`. This scope writes the dedicated category landing route and the shared `<CategoryRail/>`. The `categories.ts` helper that all three scopes import is **pre-copied by the orchestrator before this phase** (BUILD.md Step 7 pre-batch) — do NOT write it here.
3
+ Scope: `pages-categories` — written by the stores **merged build agent** (the build wave) *before* its `pages-products` scope, so `<CategoryRail/>` is on disk before that scope mounts it. This scope writes the dedicated category landing route and the shared `<CategoryRail/>`. The `categories.ts` helper is **pre-copied by the orchestrator in the build-wave pre-batch** (BUILD-astro.md § "Step 4.5") — do NOT write it here.
4
4
 
5
- **Dispatch:** all three stores Phase-4 scopes are dispatched in parallel — Astro resolves the cross-file imports at build time (Step 8). The orchestrator does not need to serialize them. Each scope only needs its own declared files to exist by the time `astro build` runs; `categories.ts` is already on disk from the pre-batch.
5
+ **Within-agent order:** the merged stores agent writes `components` → `pages-categories` (this scope) → `pages-products`. `pages-home-and-nav` is a *separate* serialized agent (it patches the shared shells) and resolves `<CategoryRail/>` at build time (Step 8). Each scope only needs its own declared files to exist by the time `astro build` runs.
6
6
 
7
7
  ## Scope
8
8
 
@@ -23,7 +23,7 @@ Files this agent MUST NOT touch:
23
23
  ## Inputs (from parent prompt)
24
24
 
25
25
  - **Phase 1 return data** — `categories: []`. Phase 1 does not seed categories (they're merchant-driven). This scope still writes the helper + rail + route — they're harmless when no categories exist, and they light up automatically once the merchant creates visible categories with items in the dashboard. `listStoreCategories()` queries the API live at SSR time (5-min TTL cache), so no redeploy is needed when categories are added later.
26
- - **Design tokens** — the full `designTokens` JSON is inlined in your prompt (same shape Designer returned). Page header / breadcrumbs / pill / pagination styling should follow `references/shared/STYLING.md` (utilities derived from tokens, semantic classes only for primitives).
26
+ - **Design tokens** — read the design tokens (the DESIGN.md vocabulary) from `.wix/design-tokens.css` (on disk). Page header / breadcrumbs / pill / pagination styling should follow `references/shared/STYLING.md` (utilities derived from tokens, semantic classes only for primitives).
27
27
  - **Designer output summary** — confirm `Layout.astro` already includes `<ClientRouter />`, `transition:persist` markers on nav/footer, and the `[data-nav-progress]` element + after-swap hook. If any of those is missing, return `status: "partial"` with `errors: [{ code: "DESIGNER_LAYOUT_MISSING_TRANSITIONS", path: "src/layouts/Layout.astro" }]`.
28
28
 
29
29
  ## Critical rules (all must be honored)
@@ -40,7 +40,7 @@ Files this agent MUST NOT touch:
40
40
 
41
41
  ## Writing the templates
42
42
 
43
- Read each template at `templates/stores/` and write it verbatim to the corresponding `src/` path, with three small adjustments. (`categories.ts` is **not** in this list — the orchestrator pre-copies it; you only import its helpers.)
43
+ Read each template at `references/astro/templates/stores/` and write it verbatim to the corresponding `src/` path, with three small adjustments. (`categories.ts` is **not** in this list — the orchestrator pre-copies it; you only import its helpers.)
44
44
 
45
45
  | Template path | Site path |
46
46
  |---|---|
@@ -1,6 +1,6 @@
1
1
  # Phase 3 Components-CSS — Stores
2
2
 
3
- Sibling of the `components` scope. Launched in **Step 4.5** in the same concurrent batch — runs in parallel with the TSX/Astro work, ecom and gift-cards components, and Image Phase 2.
3
+ **This stylesheet is pre-copied from the skill template by the orchestrator** (build-wave pre-batch, BUILD-astro.md § "Step 4.5") — there is no `components-css` subagent to dispatch. This file documents the CSS for reference so the stores `components` scope (in the merged build agent) knows the class-name surface it targets.
4
4
 
5
5
  ## What this scope owns
6
6
 
@@ -23,7 +23,7 @@ You only need:
23
23
  2. **`<SKILL_ROOT>/references/shared/STYLING.md`** — the styling-contract conventions (how to use `@apply`, the `@theme` token utilities, the no-default-Tailwind-colors rule, and the global-vs-scoped CSS ownership boundary).
24
24
  3. **`<SKILL_ROOT>/references/shared/RETURN_CONTRACT.md`** — the return JSON shape.
25
25
  4. **`src/styles/global.css`** in the project — read to audit for stores-class leaks (see § "Global-CSS leak audit" below).
26
- 5. **Design tokens (inline in your prompt)** — the parent skill pastes the full `designTokens` JSON into your dispatch prompt. Use it directly; do NOT read `.wix/design-tokens.css` or `.wix/site.d.ts` from disk.
26
+ 5. **Design tokens (on disk)** — read the design tokens (the DESIGN.md vocabulary — `colors`/`typography`/`spacing`/`rounded`/`containers`) from `.wix/design-tokens.css` (gate-verified present before the wave). They are NOT inlined in your prompt.
27
27
 
28
28
  You do NOT need to read `INSTRUCTIONS.md`, `SHARED_WIRING.md`, `BACK_IN_STOCK.md`, the TSX templates, the back-in-stock util, or any other reference. Skipping those reads is the point of the split — they would consume tokens for context this scope doesn't use.
29
29
 
@@ -86,7 +86,7 @@ Write the adapted CSS to `src/styles/components-stores.css`. The first line must
86
86
 
87
87
  ## Coordination: design tokens
88
88
 
89
- Your parent prompt includes the design tokens JSON inline. Use it directly — do **not** read `.wix/design-tokens.css` or `.wix/site.d.ts` from disk and do not poll for them.
89
+ Read the design tokens from `.wix/design-tokens.css` (on disk, gate-verified present before the wave) — they are NOT inlined in your prompt.
90
90
 
91
91
  ## Return format
92
92
 
@@ -1,8 +1,8 @@
1
1
  # Phase 4 Home Page + Nav — Stores
2
2
 
3
- Scope: `pages-home-and-nav`. Launched in **Step 7**; imports the orchestrator-pre-copied `categories.ts` helper (and the rail `pages-categories` writes — resolved at build time). Patches the home page's stores-related placeholder data with live `productsV3` queries AND inserts the Shop submenu (categories list) into the persisted Navigation.
3
+ Scope: `pages-home-and-nav` — dispatched as its **own serialized shell-patcher agent** in the build wave (NOT merged into the stores private-files agent, because it patches the shared shells). Imports the orchestrator-pre-copied `categories.ts` helper and the `CategoryRail`/`ProductCard` the stores private agent writes — **resolved at build time, so no write-ordering against that agent.** Patches the home page's stores-related placeholder data with live `productsV3` queries AND inserts the Shop submenu (categories list) into the persisted Navigation at the `<!-- nav:links -->` marker. (The `CartBadge` mount at `<!-- nav:actions -->` is ecom's; you own only `<!-- nav:links -->`.) Read your seeded slice from `.wix/seeded.json` (`seeded.stores`).
4
4
 
5
- > **You patch the shared `Navigation.astro` + `index.astro` shells**, which other packs (e.g. gift-cards) also patch at their own markers. **Touch only your markers and preserve every other scope's siblings — never rewrite either file.** (Flow is the conductor's job: it serializes shell-patching scopes so concurrent marker edits don't collide — BUILD.md Step 7.)
5
+ > **You patch the shared `Navigation.astro` + `index.astro` shells**, which other packs (ecom at `nav:actions`, gift-cards, blog) also patch at their own markers. **Touch only your markers and preserve every other scope's siblings — never rewrite either file.** (Flow is the conductor's job: it serializes the shell-patching agents so concurrent marker edits don't collide — BUILD-astro.md § "Step 4.5", the serialized shell chain.)
6
6
 
7
7
  ## Scope
8
8
 
@@ -21,7 +21,7 @@ Files this agent MUST NOT touch:
21
21
  ## Inputs (from parent prompt)
22
22
 
23
23
  - **Phase 1 stores return** — `products: [{id, name, slug, ...}]`. Needed for live query on home page; also useful for deciding how many to feature.
24
- - **Design tokens** — the full `designTokens` JSON is inlined in your prompt for the published color/spacing/typography vocabulary; compose Tailwind utilities derived from those tokens at the call site rather than inventing semantic classes. See `references/shared/STYLING.md` for the three styling categories.
24
+ - **Design tokens** — read the design tokens (the DESIGN.md vocabulary) from `.wix/design-tokens.css` (on disk) for the published color/spacing/typography vocabulary; compose Tailwind utilities derived from those tokens at the call site rather than inventing semantic classes. See `references/shared/STYLING.md` for the three styling categories.
25
25
  - **Designer output summary** — path of `src/pages/index.astro` and `src/components/Navigation.astro`, with notes on what placeholder data exists.
26
26
  - **Categories (lookup)** — if the designer used category links with hardcoded slugs, call `categoriesV3` SDK to discover real category slugs and rewrite `href`s.
27
27
 
@@ -1,10 +1,10 @@
1
1
  # Phase 4 Product Pages — Stores
2
2
 
3
- Scope: `product-pages`. Launched in **Step 7** after designer page scopes have written placeholder `.astro` files. This scope rewrites the product listing, product detail, and ProductCard component with live `productsV3` queries.
3
+ Scope: `product-pages` (the `pages-products` scope) — written by the stores **merged build agent** (the build wave) *after* its `components` and `pages-categories` scopes. This scope writes the product listing, product detail, and ProductCard component **once** — applying the designer's visual spec (`references/astro/designer/INSTRUCTIONS.md` → `store-pages`) together with live `productsV3` queries in a single pass. Read your seeded slice from `.wix/seeded.json` (`seeded.stores`).
4
4
 
5
5
  ## Scope
6
6
 
7
- Files this agent OWNS (rewrites from designer output):
7
+ Files this agent OWNS (each written once, visual structure + live queries together):
8
8
 
9
9
  - `src/pages/products/index.astro` — product listing
10
10
  - `src/pages/products/[slug].astro` — product detail with `wixMetadata` + SEO tags
@@ -12,17 +12,17 @@ Files this agent OWNS (rewrites from designer output):
12
12
 
13
13
  Files this agent MUST NOT touch:
14
14
  - `src/components/ProductPurchase.tsx`, `src/components/AddToCartButton.tsx` — owned by `components`
15
- - `src/pages/cart.astro`, `src/pages/thank-you.astro` — owned by `pages-cart-checkout`
15
+ - `src/pages/cart.astro`, `src/pages/thank-you.astro` — owned by `cart-checkout`
16
16
  - `src/pages/index.astro`, `src/components/Navigation.astro` — owned by `pages-home-and-nav`
17
- - `src/components/CategoryRail.astro` — owned by `pages-categories`. **Import** from `../../components/CategoryRail.astro`; never `Write` it. If it's not on disk yet when you go to mount it, that means the orchestrator dispatched scopes out of order — return `status: "partial"` with `errors: [{ code: "MISSING_PAGES_CATEGORIES_OUTPUT", path: "src/components/CategoryRail.astro" }]` (never defensively `Write` it yourself — `pages-categories` is the only writer, and racing it trips the harness staleness guard).
18
- - `src/utils/categories.ts` — pre-copied by the orchestrator before Phase 4 (BUILD.md Step 7 pre-batch). **Import** `listStoreCategories`/etc. from `../../utils/categories`; never `Write` it.
17
+ - `src/components/CategoryRail.astro` — owned by the `pages-categories` scope, which your merged agent writes **before** this one. **Import** from `../../components/CategoryRail.astro`; never `Write` it here. By the time you mount it, the `pages-categories` step has already put it on disk. If it's somehow absent, you wrote your scopes out of order — return `status: "partial"` with `errors: [{ code: "MISSING_PAGES_CATEGORIES_OUTPUT", path: "src/components/CategoryRail.astro" }]` (write `pages-categories` before `pages-products`; never defensively `Write` it from this scope).
18
+ - `src/utils/categories.ts` — pre-copied by the orchestrator in the build-wave pre-batch (BUILD-astro.md § "Step 4.5"). **Import** `listStoreCategories`/etc. from `../../utils/categories`; never `Write` it.
19
19
  - `global.css`, any other `.astro` page, any other component — owned by designers
20
20
 
21
21
  ## Inputs (from parent prompt)
22
22
 
23
23
  - **Phase 1 return data** — `products: [{id, name, slug, variantId, price, inventory, sku}]` — use slugs when needed (rarely; `queryProducts` returns them already).
24
- - **Design tokens** — the full `designTokens` JSON is inlined in your prompt for the published color/spacing/typography vocabulary; compose Tailwind utilities derived from those tokens (`class="py-4xl flex flex-col gap-md font-display"`) at the call site rather than inventing semantic classes for layout/spacing/typography. Retained global semantic classes are limited to compound patterns (`offer-callout`, `cart-summary`), interactive primitives (`btn-primary`, `product-card`), and JS targets — see `references/shared/STYLING.md`.
25
- - **Designer output summary** — paths of existing `products/index.astro`, `products/[slug].astro`, `ProductCard.astro` with placeholder data.
24
+ - **Design tokens** — read the design tokens (the DESIGN.md vocabulary) from `.wix/design-tokens.css` (on disk) for the published color/spacing/typography vocabulary; compose Tailwind utilities derived from those tokens (`class="py-4xl flex flex-col gap-md font-display"`) at the call site rather than inventing semantic classes for layout/spacing/typography. Retained global semantic classes are limited to compound patterns (`offer-callout`, `cart-summary`), interactive primitives (`btn-primary`, `product-card`), and JS targets — see `references/shared/STYLING.md`.
25
+ - **Designer visual spec** — the layout, contract classes, and decorative-slot conventions for `products/index.astro`, `products/[slug].astro`, `ProductCard.astro` (from `references/astro/designer/INSTRUCTIONS.md` → `store-pages`), applied in the same pass as the live queries.
26
26
 
27
27
  ## Critical rules (all must be honored)
28
28
 
@@ -68,9 +68,9 @@ Do NOT modify logic, imports, SDK calls, `wixMetadata` export, or prop-passing.
68
68
 
69
69
  Use template `templates/products/index.astro`.
70
70
 
71
- Preserves the designer's page structure (class names, layout) and replaces the placeholder products array with a guarded, **cursor-paginated** `productsV3.queryProducts({ fields: ["CURRENCY"] }).limit(24).skipTo(cursor).find()` (cursor read from `?cursor=` on the URL; Prev/Next anchors built from `result.cursors.next` / `.prev`). Mounts the shared `<CategoryRail/>` (written by `pages-categories`) above the grid, passing `activeSlug={null}` and the prev/next hrefs. Emits the `AddProductImpression` analytics event from a client-side script that reads a JSON payload serialized at SSR.
71
+ Applies the designer's page structure (class names, layout) and binds a guarded, **cursor-paginated** `productsV3.queryProducts({ fields: ["CURRENCY"] }).limit(24).skipTo(cursor).find()` (cursor read from `?cursor=` on the URL; Prev/Next anchors built from `result.cursors.next` / `.prev`). Mounts the shared `<CategoryRail/>` (written by `pages-categories`) above the grid, passing `activeSlug={null}` and the prev/next hrefs. Emits the `AddProductImpression` analytics event from a client-side script that reads a JSON payload serialized at SSR.
72
72
 
73
- > **Imports written by `pages-categories`.** Both `<CategoryRail/>` and `listStoreCategories` come from files this scope must NOT write — they're owned by the `pages-categories` scope. Import paths: `../../components/CategoryRail.astro` and `../../utils/categories`. If either import fails to resolve, return `status: "partial"` with `errors: [{ code: "MISSING_PAGES_CATEGORIES_OUTPUT", path: "<missing path>" }]` — that means the orchestrator dispatched scopes out of order.
73
+ > **Imports you must NOT write.** `<CategoryRail/>` (`../../components/CategoryRail.astro`) is written by the `pages-categories` scope your merged agent runs *before* this one; `listStoreCategories` (`../../utils/categories`) is pre-copied by the orchestrator. Both are on disk by the time you mount them. If either fails to resolve, return `status: "partial"` with `errors: [{ code: "MISSING_PAGES_CATEGORIES_OUTPUT", path: "<missing path>" }]` — that means your agent wrote `pages-products` before `pages-categories`, or the pre-copy was skipped.
74
74
 
75
75
  > **Page size 24** — multiple of the 2/3/4-column grid, well under Wix's per-request cap of 100. Do not change without updating `CATEGORY_PAGES.md` to match.
76
76
 
@@ -1,8 +1,8 @@
1
1
  # Phase 3 Components — Stores (TSX/Astro)
2
2
 
3
- Launched in **Step 4.5** (after Phase 2 Design System completes, parallel to any running designer page scopes). Writes code that depends on the **design tokens** but NOT on Phase 4 page markup. Finishes before the Phase 4 Pages scopes run in Step 7.
3
+ This is the **components** portion of the stores **merged build agent** (the build wave — `BUILD-astro.md` § "Step 4.5"). Your agent writes these islands **first**, then the stores pages (`pages-categories`, `pages-products`) that mount them — so the islands are on disk before the page code references them. The code here depends on the **design tokens** (read from `.wix/design-tokens.css` on disk) but NOT on page markup.
4
4
 
5
- > **CSS lives in a sibling scope.** `src/styles/components-stores.css` is owned by the `components-css` scope (see `./COMPONENTS_CSS.md`), which runs concurrently with this one in the same Step 4.5 batch. This scope does NOT write the CSS file. Reference contract class names from the design tokens here; the CSS sibling defines the rules.
5
+ > **CSS is pre-copied, not authored.** `src/styles/components-stores.css` ships from the skill template, copied by the orchestrator in the build-wave pre-batch (see `./COMPONENTS_CSS.md`). This scope does NOT write the CSS file. Reference its contract class names from the design tokens here; the pre-copied stylesheet defines the rules.
6
6
 
7
7
  ## Scope
8
8
 
@@ -17,14 +17,15 @@ Files this agent MUST NOT touch:
17
17
  - `src/styles/components-stores.css` — owned by the **`components-css`** sibling scope (see `./COMPONENTS_CSS.md`). Reference its class names; do not write the file.
18
18
  - `src/utils/wix-image.ts` — **shared utility shipped by the build skill.** Import `resolveWixImageUrl` from `../utils/wix-image`; do NOT write your own copy (would shadow the shared util and drop other verticals' callers). The canonical source lives at `<SKILL_ROOT>/shared-utilities/wix-image.ts`; it's copied into projects by `seed-utilities.sh` during Setup.
19
19
  - `src/components/CartView.tsx`, `src/components/CartBadge.tsx`, `src/utils/analytics.ts`, `src/styles/components-ecom.css` — owned by ecom
20
- - Any `.astro` page — those are designed and later rewritten by other scopes
20
+ - `src/utils/back-in-stock.ts` — **pre-copied by the orchestrator** in the build-wave pre-batch (BUILD-astro.md § "Step 4.5"), same as `categories.ts`. Import `getBackInStockEnabled`/the app-id constants from `../utils/back-in-stock`; never `Write` it (see `./BACK_IN_STOCK.md`).
21
+ - Any `.astro` page — written by your agent's `pages-*` scopes (after the islands) or by another vertical
21
22
  - `src/styles/global.css` — owned by designer foundation
22
23
  - `src/layouts/Layout.astro` — owned by designer foundation (including the `components-stores.css` import line)
23
24
  - Any designed component (`ProductCard.astro`, `Navigation.astro`, etc.) — owned by designers
24
25
 
25
26
  ## Coordination: design tokens
26
27
 
27
- Your parent prompt includes the design tokens inline. Use it directly — do **not** read `.wix/design-tokens.css` + `.wix/site.d.ts` from disk and do not poll for it. The parent skill serializes your launch behind designer foundation specifically so the contract is already available in your prompt when you start.
28
+ Read the design tokens from `.wix/design-tokens.css` (on disk, gate-verified present before the wave). The parent skill serializes your launch behind the designer foundation specifically so this file is already written when you start.
28
29
 
29
30
  Reference the ACTUAL class names from the contract in React components (e.g. `className="add-to-cart-btn"`, not `className="addToCartButton"` or an invented name). See `references/shared/IMPLEMENTER.md` § "Contract class-name adaptation" for the full rule.
30
31
 
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  // ── Composer skeleton: src/components/Footer.astro ────────────────────────────
3
- // Substitutions (see COMPOSE.md § "5. Footer.astro"):
3
+ // Substitutions (see compose.mjs):
4
4
  // {{brand.name}} — brand name for the wordmark + copyright.
5
5
  // {{shell.footerTagline}} — short brand-voice tagline from data.shell.
6
6
  // {{nav.links}} — same inlined Navigation links array (mirror/subset);
@@ -2,7 +2,7 @@
2
2
  // ── Composer skeleton: src/layouts/Layout.astro ──────────────────────────────
3
3
  // Fully replaces the scaffold's bare stub. The <script> below and the View
4
4
  // Transitions wiring are LITERAL fixed bulk — do not re-author. Composer's only
5
- // substitutions (see COMPOSE.md § "3. Layout.astro"):
5
+ // substitutions (see compose.mjs):
6
6
  // {{components-css-imports}} — one `import '../styles/components-<pack>.css';`
7
7
  // per pack in "Packs with components" (omit entirely when none).
8
8
  // {{fonts.googleHref}} — the Google Fonts <link> href built from designTokens
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  // ── Composer skeleton: src/components/Navigation.astro ────────────────────────
3
- // Substitutions (see COMPOSE.md § "4. Navigation.astro"):
3
+ // Substitutions (see compose.mjs):
4
4
  // {{shell.navBrandMark}} — brand mark / wordmark text from data.shell.
5
5
  // {{nav.links}} — one <a href={href}>{label}</a> per entry in the inlined
6
6
  // Navigation links array, labels VERBATIM (no editorial rebrands). Render
@@ -3,7 +3,7 @@
3
3
  // scaffold's generated astro.config.mjs varies (integrations args, image.domains,
4
4
  // vite.server settings differ run to run). Composer must NOT overwrite it with
5
5
  // this file — it applies exactly two mutations to the scaffold's own config and
6
- // preserves everything else (see COMPOSE.md § "2. astro.config.mjs"):
6
+ // preserves everything else (see compose.mjs):
7
7
  //
8
8
  // (1) register the Tailwind v4 Vite plugin → vite.plugins: [tailwindcss()]
9
9
  // (2) fix the bare `process.env` reference → globalThis guard (TS-safe)
@@ -0,0 +1,233 @@
1
+ import { useCallback, useEffect, useMemo, useState } from "react";
2
+ import { availabilityTimeSlots, eventTimeSlots } from "@wix/bookings";
3
+ import type { SelectedSlot } from "./bookingDriver";
4
+
5
+ // AvailabilityCalendar.tsx — client:only="react" island. A week calendar: a
6
+ // 7-day strip with week navigation, then the picked day's time slots. This is
7
+ // the usable shape — a flat list of every slot with time-only labels leaves the
8
+ // visitor unable to tell which day a slot is on.
9
+ //
10
+ // SDK calls run ambiently (the @wix/astro visitor client), like the ecom
11
+ // CartView island — no createClient/OAuthStrategy here. On an own/own-build SPA
12
+ // acquire a visitor client (OAuthStrategy) and call the same functions on it.
13
+ //
14
+ // Branches on serviceType:
15
+ // APPOINTMENT → availabilityTimeSlots.listAvailabilityTimeSlots() (serviceId is
16
+ // a single GUID string; slots carry scheduleId).
17
+ // CLASS → eventTimeSlots.listEventTimeSlots() (serviceIds is an array;
18
+ // slots carry eventInfo.eventId and NO scheduleId).
19
+ // Re-export SelectedSlot from bookingDriver so the form/driver share one shape.
20
+ export type { SelectedSlot } from "./bookingDriver";
21
+
22
+ interface Props {
23
+ serviceId: string;
24
+ serviceName: string;
25
+ serviceType: "APPOINTMENT" | "CLASS";
26
+ onSlotSelected: (slot: SelectedSlot) => void;
27
+ }
28
+
29
+ const DAY_MS = 86_400_000;
30
+ const HORIZON_WEEKS = 13; // how far "check next availability" probes forward
31
+
32
+ const pad = (n: number) => String(n).padStart(2, "0");
33
+ // Local date string YYYY-MM-DDThh:mm:ss (no Z) — availability expects local time.
34
+ const localDateString = (d: Date) =>
35
+ `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())}T${pad(d.getHours())}:${pad(d.getMinutes())}:${pad(d.getSeconds())}`;
36
+ const tz = () => Intl.DateTimeFormat().resolvedOptions().timeZone || "UTC";
37
+ const dateKey = (iso: string) => iso.slice(0, 10); // group slots by calendar day
38
+ const timeLabel = (iso: string) =>
39
+ new Date(iso).toLocaleTimeString([], { hour: "2-digit", minute: "2-digit" });
40
+
41
+ const startOfDay = (d: Date) => { const n = new Date(d); n.setHours(0, 0, 0, 0); return n; };
42
+ // Monday-start week containing `d`.
43
+ const mondayOf = (d: Date) => {
44
+ const n = startOfDay(d);
45
+ const day = (n.getDay() + 6) % 7; // 0 = Monday
46
+ n.setDate(n.getDate() - day);
47
+ return n;
48
+ };
49
+
50
+ // Fetch one week of availability and group the slots by calendar day.
51
+ const fetchWeek = async (
52
+ serviceId: string,
53
+ serviceType: "APPOINTMENT" | "CLASS",
54
+ weekStart: Date,
55
+ ): Promise<Record<string, SelectedSlot[]>> => {
56
+ const from = startOfDay(weekStart);
57
+ const to = new Date(from.getTime() + 7 * DAY_MS);
58
+ const timeZone = tz();
59
+ let raw: any[] = [];
60
+
61
+ if (serviceType === "CLASS") {
62
+ const result = await eventTimeSlots.listEventTimeSlots({
63
+ serviceIds: [serviceId], // CLASS API takes an array
64
+ fromLocalDate: localDateString(from),
65
+ toLocalDate: localDateString(to),
66
+ timeZone,
67
+ includeNonBookable: false,
68
+ cursorPaging: { limit: 100 },
69
+ });
70
+ raw = (result.timeSlots ?? []).map((s: any) => ({
71
+ serviceType: "CLASS" as const,
72
+ serviceId,
73
+ localStartDate: s.localStartDate,
74
+ localEndDate: s.localEndDate,
75
+ timezone: result.timeZone ?? timeZone,
76
+ eventId: s.eventInfo?.eventId, // session id — no scheduleId on event slots
77
+ }));
78
+ } else {
79
+ const result = await availabilityTimeSlots.listAvailabilityTimeSlots({
80
+ serviceId, // single GUID string — NOT an array
81
+ fromLocalDate: localDateString(from),
82
+ toLocalDate: localDateString(to),
83
+ timeZone,
84
+ bookable: true,
85
+ cursorPaging: { limit: 100 },
86
+ });
87
+ raw = (result.timeSlots ?? []).map((s: any) => ({
88
+ serviceType: "APPOINTMENT" as const,
89
+ serviceId,
90
+ localStartDate: s.localStartDate,
91
+ localEndDate: s.localEndDate,
92
+ timezone: result.timeZone ?? timeZone,
93
+ scheduleId: s.scheduleId,
94
+ locationId: s.location?._id, // the id field is _id, not .id
95
+ locationType: s.location?.locationType,
96
+ }));
97
+ }
98
+
99
+ const byDay: Record<string, SelectedSlot[]> = {};
100
+ for (const slot of raw) {
101
+ if (!slot.localStartDate) continue;
102
+ (byDay[dateKey(slot.localStartDate)] ||= []).push(slot);
103
+ }
104
+ return byDay;
105
+ };
106
+
107
+ export default function AvailabilityCalendar({ serviceId, serviceName, serviceType, onSlotSelected }: Props) {
108
+ const thisMonday = useMemo(() => mondayOf(new Date()), []);
109
+ const [weekStart, setWeekStart] = useState<Date>(thisMonday);
110
+ const [byDay, setByDay] = useState<Record<string, SelectedSlot[]>>({});
111
+ const [selectedDay, setSelectedDay] = useState<string | null>(null);
112
+ const [selectedKey, setSelectedKey] = useState<string | null>(null);
113
+ const [status, setStatus] = useState<"loading" | "ready" | "error" | "searching">("loading");
114
+
115
+ const days = useMemo(
116
+ () => Array.from({ length: 7 }, (_, i) => new Date(weekStart.getTime() + i * DAY_MS)),
117
+ [weekStart],
118
+ );
119
+ const atFirstWeek = weekStart.getTime() <= thisMonday.getTime();
120
+
121
+ const load = useCallback(async (start: Date) => {
122
+ setStatus("loading"); setSelectedKey(null);
123
+ try {
124
+ const grouped = await fetchWeek(serviceId, serviceType, start);
125
+ setByDay(grouped);
126
+ const firstDayWithSlots = Object.keys(grouped).sort()[0] ?? null;
127
+ setSelectedDay(firstDayWithSlots);
128
+ setStatus("ready");
129
+ } catch (err) {
130
+ console.error("[availability] list failed:", err);
131
+ setStatus("error");
132
+ }
133
+ }, [serviceId, serviceType]);
134
+
135
+ useEffect(() => { void load(weekStart); }, [weekStart, load]);
136
+
137
+ const shiftWeek = (deltaWeeks: number) =>
138
+ setWeekStart((prev) => startOfDay(new Date(prev.getTime() + deltaWeeks * 7 * DAY_MS)));
139
+
140
+ // Probe forward week-by-week for the next week that has any slots.
141
+ const checkNextAvailability = useCallback(async () => {
142
+ setStatus("searching");
143
+ let cursor = new Date(weekStart.getTime() + 7 * DAY_MS);
144
+ for (let i = 0; i < HORIZON_WEEKS; i++) {
145
+ try {
146
+ const grouped = await fetchWeek(serviceId, serviceType, cursor);
147
+ if (Object.keys(grouped).length > 0) {
148
+ setWeekStart(cursor); // triggers load() via the effect
149
+ return;
150
+ }
151
+ } catch { /* keep probing */ }
152
+ cursor = new Date(cursor.getTime() + 7 * DAY_MS);
153
+ }
154
+ setStatus("ready"); // nothing found within the horizon
155
+ }, [serviceId, serviceType, weekStart]);
156
+
157
+ const handleSelect = (s: SelectedSlot) => {
158
+ const id = s.serviceType === "CLASS" ? s.eventId : s.scheduleId;
159
+ if (!s.localStartDate || !id) return;
160
+ setSelectedKey(`${s.localStartDate}|${id}`);
161
+ onSlotSelected(s);
162
+ };
163
+
164
+ const weekLabel = `${days[0].toLocaleDateString([], { month: "short", day: "numeric" })} – ${days[6].toLocaleDateString([], { month: "short", day: "numeric" })}`;
165
+ const daySlots = selectedDay ? byDay[selectedDay] ?? [] : [];
166
+ const weekIsEmpty = status === "ready" && Object.keys(byDay).length === 0;
167
+
168
+ return (
169
+ <div className="availability-calendar">
170
+ <div className="availability-week-nav">
171
+ <button type="button" className="availability-nav-btn" onClick={() => shiftWeek(-1)} disabled={atFirstWeek} aria-label="Previous week">← Prev week</button>
172
+ <span className="availability-week-label">{weekLabel}</span>
173
+ <button type="button" className="availability-nav-btn" onClick={() => shiftWeek(1)} aria-label="Next week">Next week →</button>
174
+ </div>
175
+
176
+ <div className="availability-day-strip" role="group" aria-label="Pick a day">
177
+ {days.map((d) => {
178
+ const key = `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())}`;
179
+ const has = (byDay[key]?.length ?? 0) > 0;
180
+ const isSelected = key === selectedDay;
181
+ return (
182
+ <button
183
+ key={key}
184
+ type="button"
185
+ className={["availability-day", isSelected ? "availability-day--selected" : "", has ? "availability-day--has-slots" : "availability-day--empty"].filter(Boolean).join(" ")}
186
+ disabled={!has}
187
+ aria-pressed={isSelected}
188
+ onClick={() => { setSelectedDay(key); setSelectedKey(null); }}
189
+ >
190
+ <span className="availability-day-name">{d.toLocaleDateString([], { weekday: "short" })}</span>
191
+ <span className="availability-day-num">{d.getDate()}</span>
192
+ </button>
193
+ );
194
+ })}
195
+ </div>
196
+
197
+ {status === "loading" && <p className="availability-loading">Checking availability…</p>}
198
+ {status === "searching" && <p className="availability-loading">Searching for the next available time…</p>}
199
+ {status === "error" && (
200
+ <>
201
+ <p className="availability-error">Could not load availability — please try again.</p>
202
+ <button type="button" className="availability-nav-btn" onClick={() => void load(weekStart)}>Retry</button>
203
+ </>
204
+ )}
205
+ {weekIsEmpty && (
206
+ <div className="availability-empty">
207
+ <p>No availability this week.</p>
208
+ <button type="button" className="availability-nav-btn" onClick={() => void checkNextAvailability()}>Check next availability</button>
209
+ </div>
210
+ )}
211
+ {status === "ready" && daySlots.length > 0 && (
212
+ <div className="availability-slots" role="group" aria-label={`Available times for ${serviceName}`}>
213
+ {daySlots.map((s) => {
214
+ const id = s.serviceType === "CLASS" ? s.eventId : s.scheduleId;
215
+ const key = `${s.localStartDate}|${id}`;
216
+ const isSelected = key === selectedKey;
217
+ return (
218
+ <button
219
+ key={key}
220
+ type="button"
221
+ className={["time-slot", isSelected ? "time-slot--selected" : "time-slot--available"].join(" ")}
222
+ aria-pressed={isSelected}
223
+ onClick={() => handleSelect(s)}
224
+ >
225
+ <span className="time-slot-time">{timeLabel(s.localStartDate)}</span>
226
+ </button>
227
+ );
228
+ })}
229
+ </div>
230
+ )}
231
+ </div>
232
+ );
233
+ }