@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
@@ -4,7 +4,7 @@ description: Uses bulk products endpoint to create multiple products with invent
4
4
  ---
5
5
  # RECIPE: Business Recipe - Bulk Creating Wix Store Products with inventory and options
6
6
 
7
- > **Standard call shape (every curl below).** The `<AUTH>` placeholder is shorthand for `Authorization: Bearer <TOKEN>` only. Every actual call ALSO needs `wix-site-id: <SITE_ID>` and (for body-bearing requests) `Content-Type: application/json`. **POST against `stores/v3/bulk/*` returns 403 without `wix-site-id`** — recipe examples below show `<AUTH>` only for brevity, but the header is required on every call you make. Token: `npx @wix/cli@latest token --site "$SITE_ID"`.
7
+ > **Standard call shape (every curl below).** The `<AUTH>` placeholder is shorthand for `Authorization: Bearer <TOKEN>` only. Body-bearing requests also need `Content-Type: application/json`.
8
8
 
9
9
  Learn how to create multiple Wix store products with customizable options like colors, sizes, or other variants in a single bulk operation, allowing efficient creation of product catalogs.
10
10
 
@@ -183,6 +183,30 @@ Examine the images for visible product attributes that should become variant opt
183
183
  - If multiple images show the **same product from different angles**, treat them as additional product media — NOT as separate variants.
184
184
  - If only one image is provided and a distinctive color is visible, suggest that single color as a choice and ask the user if the product comes in other colors.
185
185
 
186
+ ### 4h. Subscription Eligibility Detection (silent — no user interaction)
187
+
188
+ Based on the product name, description, and image analysis, determine whether this product is **subscription-eligible**. A product qualifies if it is a consumable that gets depleted at a predictable rate — something customers buy repeatedly on a regular schedule.
189
+
190
+ **Eligible categories (examples):**
191
+ - Food & beverage: coffee beans/pods, tea, protein powder, meal kits
192
+ - Supplements & health: vitamins, probiotics, protein supplements
193
+ - Pet: pet food, flea/tick treatments, cat litter
194
+ - Personal care: skincare routine products, razor blades/cartridges, deodorant, shampoo/conditioner
195
+ - Household: cleaning supplies, paper towels, toilet paper, laundry detergent
196
+ - Baby: diapers, formula, wipes
197
+ - Media: print/digital newspapers, magazines
198
+ - Candles (daily-use scented candles with high burn frequency)
199
+
200
+ **NOT eligible (do not suggest):**
201
+ - Furniture, art, décor (one-time purchase)
202
+ - Electronics, tools, appliances
203
+ - Standard clothing, apparel, shoes (not subscription-typical)
204
+ - Jewelry, watches
205
+ - Books (single title), games, toys
206
+ - Any unique or collectible item
207
+
208
+ Store the result internally as `subscription_eligible: true/false`. If `true`, also note a brief reason (e.g., `"coffee beans — daily consumable"`). No user interaction at this step.
209
+
186
210
  ---
187
211
 
188
212
  ## V3 STEP 4: Present Review Card to User (INTERACTIVE)
@@ -207,6 +231,7 @@ Present a structured review card using the markdown format below. This provides
207
231
  | Images | [count] uploaded |
208
232
  | SEO | [first 60 chars of meta description]… |
209
233
  | Tone | [Matched from existing site products / Neutral e-commerce] |
234
+ | Subscription | [e.g. Monthly · 10% off] or [Not applicable] |
210
235
 
211
236
  **Info Sections**
212
237
  - **[Title 1]:** [one-line summary]
@@ -221,7 +246,7 @@ After the card, present the action options:
221
246
 
222
247
  > 1. **Refine** — tell me what to change (e.g., "make the description shorter", "the price should be lower")
223
248
  > 2. **Regenerate** — I'll start the analysis over, optionally with additional context from you
224
- > 3. **Approve** — proceed to options and product creation
249
+ > 3. **Approve** — lock in these details and continue to the next steps
225
250
 
226
251
  If the user provided a text note that **contradicts** what's visible in the image (e.g., image shows blue but note says "available in red"), ask the user to clarify before proceeding.
227
252
 
@@ -229,6 +254,68 @@ If the user provided a text note that **contradicts** what's visible in the imag
229
254
 
230
255
  ---
231
256
 
257
+ ## V3 STEP 4.5: Suggest Subscription (INTERACTIVE, conditional)
258
+
259
+ > **Run this step ONLY if `subscription_eligible: true` was set in V3 STEP 3 section 4h.** Otherwise skip directly to V3 STEP 5.
260
+
261
+ Present a short, non-pushy suggestion card:
262
+
263
+ ---
264
+
265
+ **This product looks like a great candidate for a subscription plan.**
266
+ Customers who subscribe to *[product name]* get auto-refills on a schedule they choose — boosting repeat revenue for you.
267
+
268
+ Would you like to add a subscription option?
269
+ - **Yes** — set it up now (takes ~30 seconds)
270
+ - **No** — create as a one-time purchase only
271
+
272
+ ---
273
+
274
+ If the user says **No**, proceed directly to V3 STEP 5.
275
+
276
+ If the user says **Yes**, ask the following 4 questions (can be presented together as a single form):
277
+
278
+ **Q1 — Billing frequency**
279
+ > "How often should subscribers be charged and receive this product?"
280
+
281
+ | Choice | `frequency` | `interval` |
282
+ |--------|------------|-----------|
283
+ | Every week | `WEEK` | `1` |
284
+ | Every 2 weeks | `WEEK` | `2` |
285
+ | Every month *(Recommended)* | `MONTH` | `1` |
286
+ | Every 2 months | `MONTH` | `2` |
287
+ | Every 3 months | `MONTH` | `3` |
288
+ | Every 6 months | `MONTH` | `6` |
289
+ | Every year | `YEAR` | `1` |
290
+
291
+ **Q2 — Duration**
292
+ > "How long should the subscription run?"
293
+
294
+ - **Ongoing** — renews automatically until the customer cancels (omit `billingCycles`)
295
+ - **Fixed** — ends after N cycles (ask: "How many cycles?") → set `billingCycles: N`
296
+
297
+ **Q3 — Subscriber discount (optional incentive)**
298
+ > "Would you like to offer a discount to customers who subscribe?"
299
+
300
+ - No discount (omit `discount` block)
301
+ - **10% off** *(Recommended)* → `type: "PERCENTAGE", amount: 10`
302
+ - Custom percentage → ask for value → `type: "PERCENTAGE", amount: [value]`
303
+ - Fixed amount off → ask for value → `type: "AMOUNT", amount: [value]`
304
+
305
+ **Q4 — Allow one-time purchase alongside subscription**
306
+ > "Can customers also buy this product as a one-time purchase (without subscribing)?"
307
+
308
+ - **Yes — sell both ways** *(Recommended)* → `allowOneTimePurchases: true`
309
+ - No — subscription only → `allowOneTimePurchases: false`
310
+
311
+ After collecting the user's answers, show a brief confirmation line before moving on:
312
+
313
+ > Subscription plan configured: [e.g. Monthly · Ongoing · 10% off · One-time purchases also allowed]
314
+
315
+ Store the collected subscription data for use in V3 STEP 6.
316
+
317
+ ---
318
+
232
319
  ## V3 STEP 5: Suggest Options and Ask User (INTERACTIVE)
233
320
 
234
321
  **Present the detected options from V3 STEP 4g and ask the user if they want to add product options.**
@@ -255,10 +342,74 @@ If no options were detected:
255
342
 
256
343
  ## V3 STEP 6: Create the Product
257
344
 
345
+ Before making the API call, ask the user one final time:
346
+
347
+ > Everything is ready. Shall I create the product now?
348
+ > - **Yes, create it** — I'll submit the product to your store now.
349
+ > - **No, go back** — return to a previous step to make changes.
350
+
351
+ **Wait for confirmation.** Only proceed with the API call if the user says Yes.
352
+
353
+ ---
354
+
258
355
  **API Endpoint:** `POST https://www.wixapis.com/stores/v3/products`
259
356
 
260
357
  Build the request body with all confirmed fields. The write must be **atomic** — either all fields save or none do.
261
358
 
359
+ **If a subscription was configured in V3 STEP 4.5**, include a `subscriptionDetails` block in the product body (see rules below). Otherwise omit it entirely.
360
+
361
+ **`subscriptionDetails` rules:**
362
+ - `title`: auto-generate from frequency (e.g. `"Monthly Subscription"`, `"Weekly Subscription"`, `"Quarterly Subscription"`)
363
+ - `description`: if a discount was set, write a short sentence referencing it (e.g. `"Subscribe and save 10% on every order."`). Omit if no discount.
364
+ - `visible`: always `true`
365
+ - `frequency` + `interval`: from user's Q1 answer
366
+ - `billingCycles`: include only for fixed-duration subscriptions (from Q2). Omit for ongoing.
367
+ - `discount`: include only if a discount was chosen (from Q3). Omit the entire block if no discount.
368
+ - `allowOneTimePurchases`: from user's Q4 answer
369
+
370
+ **Example `subscriptionDetails` block (monthly, ongoing, 10% off, one-time also allowed):**
371
+
372
+ ```json
373
+ "subscriptionDetails": {
374
+ "subscriptions": [
375
+ {
376
+ "title": "Monthly Subscription",
377
+ "description": "Subscribe and save 10% on every order.",
378
+ "visible": true,
379
+ "frequency": "MONTH",
380
+ "interval": 1,
381
+ "discount": {
382
+ "type": "PERCENTAGE",
383
+ "amount": 10
384
+ }
385
+ }
386
+ ],
387
+ "allowOneTimePurchases": true
388
+ }
389
+ ```
390
+
391
+ **Example with fixed duration and flat amount discount (every 2 months, 6 cycles, $5 off, subscription only):**
392
+
393
+ ```json
394
+ "subscriptionDetails": {
395
+ "subscriptions": [
396
+ {
397
+ "title": "Bi-Monthly Subscription",
398
+ "description": "Subscribe and save $5 on every order.",
399
+ "visible": true,
400
+ "frequency": "MONTH",
401
+ "interval": 2,
402
+ "billingCycles": 6,
403
+ "discount": {
404
+ "type": "AMOUNT",
405
+ "amount": 5
406
+ }
407
+ }
408
+ ],
409
+ "allowOneTimePurchases": false
410
+ }
411
+ ```
412
+
262
413
  ---
263
414
 
264
415
  ### Path A: Simple Product (No Options)
@@ -650,8 +801,9 @@ Before reporting success to the user, verify ALL of the following:
650
801
  - [ ] V3 STEP 2 completed: User provided 1-3 images, all uploaded to Media Manager with wixstatic.com URLs.
651
802
  - [ ] V3 STEP 3 completed: Images analyzed from user's message, all product fields generated based on what's visible in the image(s).
652
803
  - [ ] V3 STEP 4 completed: User reviewed and approved the generated details.
804
+ - [ ] V3 STEP 4.5 completed (if applicable): Subscription eligibility was evaluated. If eligible, user was asked and their choice (Yes/No) was applied before proceeding to STEP 5.
653
805
  - [ ] V3 STEP 5 completed: User confirmed, modified, or skipped product options.
654
- - [ ] V3 STEP 6 completed: Product was created via API and you received a product ID.
806
+ - [ ] V3 STEP 6 completed: User confirmed "create now", product was created via API and you received a product ID.
655
807
 
656
808
  ---
657
809
 
@@ -4,7 +4,7 @@ description: Initializes a Stores catalog with Catalog V3 Products API, bulk pro
4
4
  ---
5
5
  **RECIPE**: Business Recipe – Initial Setup for a Wix Online Store (Catalog V3)
6
6
 
7
- > **Standard call shape (every curl below).** The `<AUTH>` placeholder is shorthand for `Authorization: Bearer <TOKEN>` only. Every actual call ALSO needs `wix-site-id: <SITE_ID>` and (for body-bearing requests) `Content-Type: application/json`. **POST/PATCH against `stores/v3/*` and `categories/v1/*` returns 403 without `wix-site-id`** — recipe examples below show `<AUTH>` only for brevity, but the header is required on every call you make. Token: `npx @wix/cli@latest token --site "$SITE_ID"`.
7
+ > **Standard call shape (every curl below).** The `<AUTH>` placeholder is shorthand for `Authorization: Bearer <TOKEN>` only. Body-bearing requests also need `Content-Type: application/json`.
8
8
 
9
9
  A concise checklist for preparing any new Wix site that uses the Online Stores app with Catalog V3.
10
10
  **Notice** that this recipe is **NOT** meant for coding purposes and is **ONLY** meant for initial catalog setup.
@@ -1,142 +0,0 @@
1
- ---
2
- name: design-system-composer
3
- description: "The Composer role of the wix-headless design-system phase. Applies the Designer's framework-agnostic design spec to the astro frontend by SUBSTITUTING into pinned skeletons at references/astro/templates/ — it does not re-author the fixed bulk. Maps semantic token values to the @theme vocabulary, writes the 6 design-system files (global.css, astro.config.mjs, Layout.astro, Navigation.astro, Footer.astro, index.astro), and owns the component-CSS token contract (every var(--token) a components-<pack>.css references must resolve). Returns a manifest."
4
- ---
5
-
6
- # Composer — how the design becomes code
7
-
8
- You are the **Composer**. The Designer already decided *what the brand looks like* and returned it as a framework-agnostic spec. Your job is *how that becomes code* for the **astro** frontend: you map the spec onto the framework's token vocabulary and **substitute it into pinned skeletons**. You do **not** re-author the fixed bulk — the View-Transitions script, the view-transition / `.nav-progress` CSS, the `@utility btn` family, the `process.env` fix, the markers — all of that is literal in the skeletons. Read a skeleton, fill its `{{…}}` slots, write the file. Substitute; do not re-write.
9
-
10
- This is deterministic work against pinned templates, so it is fast and low-variance. The whole reason the rewrite-from-scratch failure mode (which roughly doubled the old design-system wall) is gone is that you never regenerate the bulk.
11
-
12
- > **Framework:** astro only. The skeletons live at `<SKILL_ROOT>/references/astro/templates/`. Custom (non-astro) frontends never reach the Composer — they route to the not-available-yet stub (`references/custom/INSTRUCTIONS.md`) before the build flow runs. If your prompt ever names a non-astro frontend, return `status: "failed"` with `errors: [{code: "FRONTEND_NOT_SUPPORTED"}]` — do not improvise a second framework.
13
-
14
- ## Self-Loading
15
-
16
- 1. Read `<SKILL_ROOT>/references/shared/RETURN_CONTRACT.md` — structured-return format.
17
- 2. Read `<SKILL_ROOT>/references/shared/STYLING.md` — the three styling categories and, in particular, § "Required tokens — the component-CSS template contract" (the token set you must guarantee). You own that contract now.
18
-
19
- No REST calls, no MCP — this is frontend-only work.
20
-
21
- **Do NOT `Read .wix/site.json`.** Every input is inlined in your prompt.
22
-
23
- ## Inputs (entirely from your prompt)
24
-
25
- - **`designTokens`** — the Designer's spec (`colors`, `fonts`, `spacing`, `radii`, `containers`), bare-key form.
26
- - **`shell`** — brand-voice strings: `heroHeadline`, `heroSub`, `footerTagline`, `navBrandMark`.
27
- - **Brand** — `{ name, description }`.
28
- - **Navigation links** — JSON array of `{href, label}`. Use labels **verbatim**.
29
- - **Loaded packs**, **Packs with components**, **Disabled packs** — comma-joined lists.
30
- - **Project directory** — the scaffold subdir (CWD).
31
-
32
- ## What you write (the 6 files)
33
-
34
- Read each skeleton from `<SKILL_ROOT>/references/astro/templates/`, substitute, write to the project. The fixed bulk in every skeleton is literal — change only the documented `{{…}}` slots.
35
-
36
- > **Read skeletons by file, never the directory (`EISDIR`).** `Read <SKILL_ROOT>/references/astro/templates/` fails with `EISDIR: illegal operation on a directory` and costs a wasted recovery round-trip. Read each of the six by its exact path: `<SKILL_ROOT>/references/astro/templates/global.css`, `…/astro.config.mjs`, `…/Layout.astro`, `…/Navigation.astro`, `…/Footer.astro`, `…/index.astro` (issue the six `Read`s as one concurrent batch). If you must discover them first, `Glob` the directory (`…/templates/*`) — never `Read` it.
37
-
38
- **Pre-write: scaffold may still be in flight.** A scaffold file you need (`Layout.astro` stub, `astro.config.mjs`) may not yet be present. Before reading one, if a `Read` returns "file does not exist", wait 5 s and retry, cap 6 attempts (~30 s). The 6-attempt cap is hard — do not check a 7th time; return `status: "failed"` with `errors: [{code: "SCAFFOLD_NOT_COMPLETE"}]` immediately on attempt 6's miss. (Reading the *skeletons* under `<SKILL_ROOT>` never needs this — they are always present.)
39
-
40
- **Read each destination before you overwrite it.** The scaffold ships stubs for several of your six targets (today: `src/layouts/Layout.astro`, `src/pages/index.astro`, `astro.config.mjs`). The harness **blocks a `Write` to an existing file you have not `Read` this run** (`File has not been read yet`). So your batched reads must include the *destination* project paths for any file the scaffold created — not only the `<SKILL_ROOT>` skeletons. Practically: in the same concurrent batch, `Read` both the skeleton and the destination for `Layout.astro`, `index.astro`, and `astro.config.mjs` (the latter you read anyway to merge); `global.css`, `Navigation.astro`, and `Footer.astro` are net-new, so a destination read isn't required (but is harmless if the scaffold happens to ship them).
41
-
42
- ### Token contract (do this first — it gates everything)
43
-
44
- Map the Designer's `designTokens` into the `@theme` palette that goes in `global.css`, and **guarantee every required token resolves**. Per `STYLING.md` § "Required tokens", the `components-<pack>.css` templates reference a fixed set via `var(--token)`. Your `@theme` MUST declare all of:
45
-
46
- - `--color-{paper,paper-warm,ink,mute,rule,accent}` (required), `--color-{ink-soft,cream,error}` (recommended).
47
- - `--font-{display,body}`.
48
- - the full `--spacing-{2xs,xs,sm,md,lg,xl,2xl,3xl,4xl}` scale.
49
- - `--radius-{sm,md}` (required), `--radius-{lg,xl}` (recommended).
50
- - a **container scale** separate from spacing: `--container-{prose,md,3xl,6xl}` minimum.
51
-
52
- If the Designer's spec is missing a required role, **derive** a sensible value (e.g. `ink-soft` ≈ `ink` lightened, `paper-warm` ≈ `paper` warmed) rather than dropping the token — a missing required token renders components unstyled. Map each group with the fixed prefix: `colors.<k>` → `--color-<k>`, `fonts.<k>` → `--font-<k>`, `spacing.<k>` → `--spacing-<k>`, `radii.<k>` → `--radius-<k>`, `containers.<k>` → `--container-<k>`.
53
-
54
- > **Container ≠ spacing.** Tailwind v4 maps `max-w-3xl` → `var(--container-3xl)`, not `var(--spacing-3xl)`. Never set a `--container-*` to a spacing value — a reading column is ~`42rem`, not `5rem`, or pages collapse to one word per line.
55
-
56
- ### 1. `global.css`
57
-
58
- Substitute the `{{theme}}` block in the skeleton with the `@theme` palette you built above — every `--color-*`, `--font-*`, `--spacing-*`, `--container-*`, `--radius-*` line. **Everything else in the skeleton is literal** (the `@utility container-reading`/`btn`, base layer, button family, decorative + site-shell + view-transition + nav-submenu + category-rail CSS). Do not add component-specific classes (`.product-card`, `.cart-summary`, …) — those live in `components-<pack>.css`, owned by Phase 3.
59
-
60
- ### 2. `astro.config.mjs`
61
-
62
- This is a **merge, not a clobber** — the scaffold's config varies. Read the scaffold's `astro.config.mjs` and apply exactly two mutations (the skeleton shows the target shape):
63
- 1. Register the Tailwind v4 Vite plugin: `import tailwindcss from "@tailwindcss/vite";` and merge `tailwindcss()` into `vite.plugins` (preserve any existing `vite` settings — `server.allowedHosts`, etc.).
64
- 2. Fix the bare `process.env` line (`const isBuild = process.env.NODE_ENV == "production";`) to the `globalThis` guard so strict `tsc --noEmit` passes without `@types/node`.
65
-
66
- ### 3. `Layout.astro`
67
-
68
- Fully replace the scaffold stub. Substitute:
69
- - `{{components-css-imports}}` — one `import '../styles/components-<pack>.css';` per pack in **"Packs with components"**, in that order. Packs without components (e.g. `cms`) get **no** import — importing a file no agent writes breaks the build. If "Packs with components" is empty, remove the placeholder line entirely.
70
- - `{{fonts.googleHref}}` — the Google Fonts stylesheet href for the chosen `display` + `body` families (e.g. `https://fonts.googleapis.com/css2?family=Fraunces:ital,opsz,wght@...&family=Inter:wght@400;500;600&display=swap`). If both fonts are system fonts, remove the `<link rel="stylesheet">` line.
71
- - `{{brand.name}}` — the default `<title>`.
72
-
73
- The View-Transitions `<script>`, the `nav-progress` div, the `ClientRouter`, the `Props` interface, and the `hasSeoTags` pattern are **literal** — keep them.
74
-
75
- ### 4. `Navigation.astro`
76
-
77
- Substitute `{{shell.navBrandMark}}` and `{{nav.links}}` (one `<li class="site-nav-item"><a href={href}>{label}</a></li>` per inlined nav link, labels **verbatim** — no editorial rebrands like "Journal" for `/about`). Keep the `<!-- nav:links -->` marker, the empty `<div class="nav-actions">`, the `transition:persist`, and the hamburger literal. Do **not** add `/products`, cart, login, or account links — packs splice those at the marker in Phase 4.
78
-
79
- ### 5. `Footer.astro`
80
-
81
- Substitute `{{brand.name}}`, `{{shell.footerTagline}}`, and `{{nav.links}}` (mirror/subset of the same array, labels verbatim). Keep `transition:persist` literal.
82
-
83
- ### 6. `index.astro`
84
-
85
- Substitute `{{shell.heroHeadline}}`, `{{shell.heroSub}}`, `{{brand.name}}`, and `{{home-markers}}`. For `{{home-markers}}`, emit one `<!-- home:<pack> -->` marker per **loaded pack that contributes a home section** (today: `stores`, `gift-cards`). Emit a marker **only** for such packs — never one no pack will fill (no `<!-- home:cms -->`; CMS owns brand-story directly, which the skeleton already renders). Keep the hero + brand-story structure and both `data-decorative-slot` placeholders literal and **empty** (the orchestrator injects `<img>` after Image Phase 1).
86
-
87
- ## Disabled-pack discipline
88
-
89
- A pack in **"Disabled packs"** (today: only `gift-cards`) ships dormant. Its `<!-- home:<pack> -->` / `<!-- nav:links -->` markers are the **only** acceptable touchpoints. Do **not** add hero CTAs, footer links, brand-story callouts, or any other entry point pointing at a disabled pack's route — users click through to a feature that does not exist yet. Treat disabled packs as code-only: they appear in your marker emission, never in visible UI you author.
90
-
91
- ## Self-checks before returning
92
-
93
- 1. **Component-CSS imports.** For every pack in "Packs with components", grep your written `Layout.astro` for `components-<pack>.css`. If any is missing, add it. If unrecoverable, return `status: "partial"` with `errors: [{code: "MISSING_COMPONENT_CSS_IMPORT", pack: "<name>"}]`. (The orchestrator also re-verifies this after you return — at the seed gate — but catch it here.)
94
- 2. **Required-token coverage.** Confirm every required token from the contract above is present in the `@theme` block you wrote. A missing one renders components unstyled.
95
- 3. **Container vs spacing.** Confirm no `--container-*` was set to a spacing value.
96
- 4. **Marker hygiene.** No marker emitted for a pack that does not contribute; both decorative slots present and empty.
97
-
98
- If a check fails and you cannot fix it, return `status: "partial"` with the specific `errors` code rather than shipping silently.
99
-
100
- ## Return contract
101
-
102
- A single fenced JSON block per `<SKILL_ROOT>/references/shared/RETURN_CONTRACT.md`, last content in your message — a manifest of what you wrote:
103
-
104
- ```json
105
- {
106
- "status": "complete",
107
- "phase": "compose",
108
- "data": {
109
- "filesWritten": [
110
- "src/styles/global.css",
111
- "astro.config.mjs",
112
- "src/layouts/Layout.astro",
113
- "src/components/Navigation.astro",
114
- "src/components/Footer.astro",
115
- "src/pages/index.astro"
116
- ],
117
- "componentCssImports": ["stores", "ecom"],
118
- "homeMarkers": ["home:stores"],
119
- "tokensApplied": { "colors": 9, "spacing": 9, "containers": 4, "radii": 2, "fonts": 2 }
120
- },
121
- "files": [ "...same as filesWritten..." ]
122
- }
123
- ```
124
-
125
- No trailing prose after the closing fence.
126
-
127
- ## Anti-patterns
128
-
129
- | WRONG | CORRECT |
130
- |---|---|
131
- | Re-author the View-Transitions script, btn family, or view-transition CSS | Keep the skeleton bulk literal; substitute only `{{…}}` slots |
132
- | Rewrite `global.css` from scratch to "clean it up" | Substitute `{{theme}}`; the rest is pinned (this is the variance win) |
133
- | Overwrite `astro.config.mjs` with the skeleton verbatim | Merge the two mutations into the scaffold's own config |
134
- | `import '../styles/components-cms.css'` (cms has no components) | One import only per pack in "Packs with components" |
135
- | Drop a required token because the Designer omitted it | Derive a sensible value — required tokens must resolve |
136
- | Set `--container-3xl` to `--spacing-3xl`'s value | Containers are widths (~`42rem`+), a separate axis from spacing |
137
- | Coin label rebrands ("Journal" → /about) or add `/products`/cart links | Nav labels verbatim; packs splice their links at the marker |
138
- | Add a hero CTA / footer link to a disabled-pack route | Disabled packs are code-only — markers are the sole touchpoint |
139
- | Emit `<!-- home:cms -->` or a marker for a non-contributing pack | One marker per contributing loaded pack only |
140
- | `Read <SKILL_ROOT>/references/astro/templates/` (the directory) | `EISDIR` — Read each of the six skeletons by its exact file path (batch the six Reads); `Glob` if you must discover them |
141
- | `Read .wix/site.json` for brand/tokens | Every input is inlined in your prompt |
142
- | Branch to a non-astro / custom frontend | astro only; return `FRONTEND_NOT_SUPPORTED` otherwise |
@@ -1,141 +0,0 @@
1
- #!/usr/bin/env node
2
- // Finalize and write .wix/run.json at the end of the build.
3
- //
4
- // The orchestrator collects agent returns, timings, and outcome data over the
5
- // run. This script takes the orchestrator's draft as a JSON blob via stdin,
6
- // runs the timing-completeness gate (every required phase MUST have non-null
7
- // seconds, otherwise emit MISSING_TIMING errors), computes totalSeconds from
8
- // started/ended, writes the canonical .wix/run.json, and prints the perf
9
- // one-liner the orchestrator shows in the final message.
10
- //
11
- // Usage:
12
- // echo "$DRAFT_JSON" | node finalize-run-json.mjs <project-dir>
13
- //
14
- // Input shape (via stdin):
15
- // {
16
- // "run": { started, ended, brand, prompt, verticals, packs },
17
- // "outcome": { build, previewUrl, dashboardUrl, ... },
18
- // "phases": [ { phase, status, seconds, data?, errors? }, ... ],
19
- // "recoveries": [ ... ], // optional; from manifest-check script outputs
20
- // "errors": [ ... ], // optional; from agent returns / orchestrator
21
- // "notes": [ ... ], // optional
22
- // "requiredPhases": ["scaffold","app-install-Wix Stores","env-pull",...]
23
- // }
24
- //
25
- // `requiredPhases` is the orchestrator's set of skill-invoked phases that MUST
26
- // have a captured duration (scaffold, every app-install-*, env-pull,
27
- // seed-utilities, npm-install, build, release|preview, etc.). The set is
28
- // run-specific (number of app-install-* depends on loaded packs), so the
29
- // orchestrator passes it in rather than the script guessing.
30
- //
31
- // Output:
32
- // - Writes .wix/run.json (full shape, with timing-completeness gate applied).
33
- // - Prints to stdout: a JSON object with { perfLine, missingTiming, totalSeconds }.
34
-
35
- import { writeFileSync, mkdirSync, readFileSync } from "node:fs";
36
- import { join } from "node:path";
37
-
38
- const projectDir = process.argv[2];
39
-
40
- if (!projectDir) {
41
- console.error("usage: cat draft.json | finalize-run-json.mjs <project-dir>");
42
- process.exit(2);
43
- }
44
-
45
- let draft;
46
- try {
47
- draft = JSON.parse(readFileSync(0, "utf8"));
48
- } catch (e) {
49
- console.error(`finalize-run-json: stdin is not valid JSON (${e.message})`);
50
- process.exit(2);
51
- }
52
-
53
- const run = draft.run ?? {};
54
- const phases = Array.isArray(draft.phases) ? [...draft.phases] : [];
55
- const errors = Array.isArray(draft.errors) ? [...draft.errors] : [];
56
- const recoveries = Array.isArray(draft.recoveries) ? draft.recoveries : [];
57
- const notes = Array.isArray(draft.notes) ? draft.notes : [];
58
- const outcome = draft.outcome ?? {};
59
- const requiredPhases = Array.isArray(draft.requiredPhases) ? draft.requiredPhases : [];
60
-
61
- // ---- 1. Timing completeness gate ------------------------------------------
62
- const phasesByName = new Map();
63
- for (const p of phases) {
64
- phasesByName.set(p.phase, p);
65
- }
66
-
67
- const missingTiming = [];
68
-
69
- for (const required of requiredPhases) {
70
- const existing = phasesByName.get(required);
71
- if (!existing) {
72
- // Missing entry entirely.
73
- const entry = { phase: required, status: "unknown", seconds: null };
74
- phases.push(entry);
75
- phasesByName.set(required, entry);
76
- errors.push({ code: "MISSING_TIMING", phase: required });
77
- missingTiming.push(required);
78
- } else if (existing.seconds === null || existing.seconds === undefined) {
79
- existing.seconds = null;
80
- if (!errors.some((e) => e.code === "MISSING_TIMING" && e.phase === required)) {
81
- errors.push({ code: "MISSING_TIMING", phase: required });
82
- }
83
- missingTiming.push(required);
84
- }
85
- }
86
-
87
- // ---- 2. totalSeconds derivation -------------------------------------------
88
- if (!run.totalSeconds && run.started && run.ended) {
89
- const started = Date.parse(run.started);
90
- const ended = Date.parse(run.ended);
91
- if (!Number.isNaN(started) && !Number.isNaN(ended) && ended >= started) {
92
- run.totalSeconds = Math.round((ended - started) / 1000);
93
- }
94
- }
95
-
96
- // ---- 3. Compose final shape -----------------------------------------------
97
- const final = {
98
- version: "1.0",
99
- run,
100
- outcome,
101
- phases,
102
- ...(recoveries.length > 0 ? { recoveries } : {}),
103
- ...(errors.length > 0 ? { errors } : {}),
104
- ...(notes.length > 0 ? { notes } : { notes: [] }),
105
- };
106
-
107
- const wixDir = join(projectDir, ".wix");
108
- mkdirSync(wixDir, { recursive: true });
109
- const runJsonPath = join(wixDir, "run.json");
110
- writeFileSync(runJsonPath, JSON.stringify(final, null, 2) + "\n");
111
-
112
- // ---- 4. Perf one-liner ----------------------------------------------------
113
- // Format: "Built in <Nm Ss> — design-system <n>s · images (phase 1 + phase 2) <n>s · build+release <n>s"
114
- const fmtSeconds = (sec) => (sec === null || sec === undefined ? "–" : `${sec}s`);
115
- const fmtTotal = (sec) => {
116
- if (sec === null || sec === undefined) return "–";
117
- const m = Math.floor(sec / 60);
118
- const s = sec % 60;
119
- return `${m}m ${s}s`;
120
- };
121
- const phaseSeconds = (name) => {
122
- const p = phasesByName.get(name);
123
- return p && p.seconds !== null && p.seconds !== undefined ? p.seconds : null;
124
- };
125
- const designSystem = phaseSeconds("design-system");
126
- const img1 = phaseSeconds("image-phase-1-decorative");
127
- const img2 = phaseSeconds("image-phase-2-entity");
128
- const imgTotal = img1 !== null && img2 !== null ? img1 + img2 : null;
129
- const build = phaseSeconds("build");
130
- const release = phaseSeconds("release") ?? phaseSeconds("preview");
131
- const buildPlusRelease = build !== null && release !== null ? build + release : null;
132
-
133
- const perfLine = `Built in ${fmtTotal(run.totalSeconds)} — design-system ${fmtSeconds(designSystem)} · images (phase 1 + phase 2) ${fmtSeconds(imgTotal)} · build+release ${fmtSeconds(buildPlusRelease)}`;
134
-
135
- console.log(JSON.stringify({
136
- status: missingTiming.length > 0 ? "partial" : "ok",
137
- path: runJsonPath,
138
- totalSeconds: run.totalSeconds ?? null,
139
- missingTiming,
140
- perfLine,
141
- }, null, 2));
@@ -1,101 +0,0 @@
1
- #!/usr/bin/env node
2
- // Write the initial .wix/site.json — slim metadata snapshot for resume
3
- // detection + run.json composition. Subagents do NOT read this file during
4
- // the run; the orchestrator is the sole reader/writer and inlines anything
5
- // downstream phases need into their prompts.
6
- //
7
- // Final shape:
8
- // {
9
- // "brand": { "name": "...", "description": "..." },
10
- // "frontend": "astro" | "custom",
11
- // "verticals": ["stores", "cms", ...],
12
- // "siteId": "..." (optional — Setup Step 1 may patch later),
13
- // "appId": "..." (optional — Setup Step 1 may patch later)
14
- // }
15
- //
16
- // Usage:
17
- // node init-site-json.mjs <project-dir> <brand-name> <brand-description> \
18
- // <verticals-csv> --frontend <astro|custom> \
19
- // [--site-id <id>] [--app-id <id>]
20
- // (In practice only "astro" reaches this step — custom frontends route to the
21
- // not-available stub before Discovery's approval/site.json write.)
22
- //
23
- // Behavior:
24
- // - Refuses to overwrite an existing .wix/site.json (exit 2). The orchestrator
25
- // should call this exactly once during Discovery's "After Approval" step.
26
- // To re-init for testing, the caller can rm the file first.
27
- // - Creates .wix/ if it doesn't exist.
28
- // - Outputs a JSON summary to stdout.
29
-
30
- import { writeFileSync, existsSync, mkdirSync } from "node:fs";
31
- import { join } from "node:path";
32
-
33
- const ALLOWED_FRONTENDS = new Set(["astro", "custom"]);
34
-
35
- let frontend = "astro";
36
- let siteId;
37
- let appId;
38
- const positional = [];
39
- const rawArgs = process.argv.slice(2);
40
- for (let i = 0; i < rawArgs.length; i++) {
41
- const arg = rawArgs[i];
42
- if (arg === "--frontend") {
43
- frontend = rawArgs[++i];
44
- } else if (arg.startsWith("--frontend=")) {
45
- frontend = arg.slice("--frontend=".length);
46
- } else if (arg === "--site-id") {
47
- siteId = rawArgs[++i];
48
- } else if (arg.startsWith("--site-id=")) {
49
- siteId = arg.slice("--site-id=".length);
50
- } else if (arg === "--app-id") {
51
- appId = rawArgs[++i];
52
- } else if (arg.startsWith("--app-id=")) {
53
- appId = arg.slice("--app-id=".length);
54
- } else {
55
- positional.push(arg);
56
- }
57
- }
58
-
59
- if (!ALLOWED_FRONTENDS.has(frontend)) {
60
- console.error(`init-site-json: --frontend must be one of ${[...ALLOWED_FRONTENDS].join(", ")}; got ${JSON.stringify(frontend)}`);
61
- process.exit(2);
62
- }
63
-
64
- const [projectDir, brandName, brandDescription, verticalsCsv] = positional;
65
-
66
- if (!projectDir || !brandName || brandDescription === undefined || !verticalsCsv) {
67
- console.error("usage: init-site-json.mjs <project-dir> <brand-name> <brand-description> <verticals-csv> --frontend <astro|custom> [--site-id <id>] [--app-id <id>]");
68
- process.exit(2);
69
- }
70
-
71
- const verticals = verticalsCsv
72
- .split(",")
73
- .map((v) => v.trim())
74
- .filter(Boolean);
75
-
76
- if (verticals.length === 0) {
77
- console.error("init-site-json: <verticals-csv> resolved to zero verticals — cms is always loaded, so this is a bug");
78
- process.exit(2);
79
- }
80
-
81
- const wixDir = join(projectDir, ".wix");
82
- const sitePath = join(wixDir, "site.json");
83
-
84
- if (existsSync(sitePath)) {
85
- console.error(`init-site-json: ${sitePath} already exists — refusing to overwrite. Discovery should call this exactly once.`);
86
- process.exit(2);
87
- }
88
-
89
- mkdirSync(wixDir, { recursive: true });
90
-
91
- const site = {
92
- brand: { name: brandName, description: brandDescription },
93
- frontend,
94
- verticals,
95
- };
96
- if (siteId) site.siteId = siteId;
97
- if (appId) site.appId = appId;
98
-
99
- writeFileSync(sitePath, JSON.stringify(site, null, 2) + "\n");
100
-
101
- console.log(JSON.stringify({ status: "ok", path: sitePath, frontend, verticals, ...(siteId ? { siteId } : {}), ...(appId ? { appId } : {}) }, null, 2));
@@ -1,45 +0,0 @@
1
- #!/usr/bin/env bash
2
- # Build the project and deploy a rotating preview URL.
3
- #
4
- # Usage:
5
- # bash <SKILL_ROOT>/scripts/preview.sh
6
- #
7
- # Run from the project directory (CWD = <project>/). Requires wix.config.json.
8
- #
9
- # Output: stdout is the preview URL that `npx @wix/cli@latest preview` printed; the
10
- # orchestrator captures it and records as outcome.previewUrl in run.json. All
11
- # other CLI output goes to stderr.
12
- #
13
- # `preview` does NOT populate the Frontend link in headless settings — that's
14
- # what `release.sh` is for. Use preview for fast iteration on a rotating URL;
15
- # use release for production deploy + transactional-email URL stability.
16
- #
17
- # Exit codes:
18
- # 0 — ok; preview URL on stdout
19
- # <other> — build or preview failed; stderr surfaces the underlying error
20
- # (TypeScript / Astro errors are code bugs, not endpoint drift —
21
- # the orchestrator's recovery ladder doesn't retry build).
22
-
23
- set -euo pipefail
24
-
25
- # Build first; surface compile errors verbatim if it fails.
26
- npx @wix/cli@latest build 1>&2
27
-
28
- # Preview captures the deployed URL on stdout. We tee its output to stderr for
29
- # the user-visible log AND parse the URL out for the orchestrator's stdout.
30
- PREVIEW_OUTPUT="$(mktemp)"
31
- trap 'rm -f "$PREVIEW_OUTPUT"' EXIT
32
-
33
- npx @wix/cli@latest preview 2>&1 | tee "$PREVIEW_OUTPUT" 1>&2
34
-
35
- # Wix CLI prints `Site preview URL: <url>` (or similar) — extract the first
36
- # https URL from the output. If multiple are printed, the first is the canonical
37
- # preview URL.
38
- PREVIEW_URL="$(grep -oE 'https://[A-Za-z0-9.-]+\.wix-host\.com[^[:space:]]*' "$PREVIEW_OUTPUT" | head -n 1 || true)"
39
-
40
- if [[ -z "$PREVIEW_URL" ]]; then
41
- echo "preview.sh: could not extract a *.wix-host.com URL from preview output" >&2
42
- exit 1
43
- fi
44
-
45
- echo "$PREVIEW_URL"